Spine is the high-speed, multi-threaded poller replacement for cmd.php.
Written in C, it provides dramatic performance improvements for data collection.
Where cmd.php can take several minutes to poll large installations, Spine
routinely polls tens of thousands of data sources in well under 60 seconds on
modern multi-core hardware.
Spine does not replace your cron or systemd scheduling entries. The scheduler
entry point remains poller.php. When Spine is selected as the poller engine,
poller.php launches Spine processes to perform the data collection across all
configured devices.
- Multi-Threaded Polling: Spine executes a thread-per-device polling model within multiple concurrent processes, allowing hundreds of metrics to be collected simultaneously.
- Persistent PHP Script Server: For custom scripts, Spine starts and
maintains long-running PHP script server processes (
script_server.php). This eliminates the heavy overhead of repeatedly spawning the PHP binary for every individual script item. - Privilege Separation (SUID Root): To perform raw ICMP pings without
invoking external ping utilities, Spine requires raw socket access. Spine
achieves this by shipping with the SUID root bit enabled (
chmod u+s). At runtime, Spine strictly limits elevated privileges: it elevates effective UID only during raw socket creation (serialized by an internal lock) and immediately drops back to the calling user (such asapacheorwww-data). - Direct Database Communication: Spine queries the Cacti database directly via the MySQL/MariaDB client library to retrieve polling targets and writes collected data directly into the poller cache and RRD files.
Because Spine is written in C, it must be compiled against your local database and Net-SNMP client development libraries.
Spine requires development headers found in the CodeReady Builder (crb)
repository on EL 9, or powertools on EL 8:
-
Enable the repository:
# On EL 9 (RHEL 9, Rocky Linux 9, AlmaLinux 9): dnf config-manager --set-enabled crb # On EL 8 (RHEL 8, Rocky Linux 8, AlmaLinux 8): dnf config-manager --set-enabled powertools
-
Install compiler tools and development libraries:
dnf install -y gcc autoconf automake libtool dos2unix help2man \ openssl-devel mariadb-devel net-snmp-devel
On Ubuntu (22.04 LTS / 24.04 LTS) and Debian (11 / 12):
apt-get update
apt-get install -y build-essential autoconf automake libtool dos2unix help2man \
libssl-dev default-libmysqlclient-dev librrd-dev libsnmp-devOn FreeBSD, Spine can be installed directly from pre-built packages or compiled from Ports:
# Using binary packages:
pkg install spine
# Or via FreeBSD Ports:
cd /usr/ports/net-mgmt/spine
make install cleanImportant: The version of Spine MUST match your Cacti version. Use Spine 1.2.31 with Cacti 1.2.31.
-
Download the release archive matching your Cacti version (replace
X.Y.Zwith your version):cd /tmp wget https://github.com/Cacti/spine/archive/refs/tags/release/X.Y.Z.tar.gz -O cacti-spine-X.Y.Z.tar.gz tar -zxvf cacti-spine-X.Y.Z.tar.gz cd spine-release-X.Y.Z
-
Bootstrap, configure, and compile:
./bootstrap ./configure make make install
By default, Spine is installed to
/usr/local/spine. -
Set binary permissions (SUID Root):
Spine must be owned by
rootwith the setuid bit set so it can open raw ICMP sockets:chown root:root /usr/local/spine/bin/spine chmod u+s /usr/local/spine/bin/spine
Spine reads its database connection parameters from spine.conf.
-
Create the configuration file from the template:
cp /usr/local/spine/etc/spine.conf.dist /usr/local/spine/etc/spine.conf -
Secure the file permissions:
Because
spine.confcontains the database password in plaintext, restrict permissions so onlyrootand the web server / poller group can read it:# On RHEL / Rocky / AlmaLinux (web group: apache): chown root:apache /usr/local/spine/etc/spine.conf chmod 0640 /usr/local/spine/etc/spine.conf # On Ubuntu / Debian (web group: www-data): chown root:www-data /usr/local/spine/etc/spine.conf chmod 0640 /usr/local/spine/etc/spine.conf
-
Edit
/usr/local/spine/etc/spine.confand update the database settings to match your Cacticonfig.php:DB_Host localhost DB_Database cacti DB_User cactiuser DB_Pass cactiuser_password DB_Port 3306 #DB_UseSSL 0 #RDB_SSL_Key #RDB_SSL_Cert #RDB_SSL_CA
Before activating Spine in the Cacti web interface, verify that it can connect to the database, query devices, and send ICMP pings without error.
Run Spine in read-only test mode (-R) with summary statistics (-S) and
verbosity level 3 (-V 3). In this mode, Spine polls devices but does not write
results into the database:
/usr/local/spine/bin/spine -R -V 3 -SVerify that the output shows Spine reading /usr/local/spine/etc/spine.conf and
completes with: SPINE: Execution Time: ... Total Hosts: ...
To test a single device without polling your entire infrastructure, pass the
host ID range using -f <host_id> -l <host_id>:
/usr/local/spine/bin/spine -R -f 1 -l 1 -V 5Check the verbose output for ICMP ping success, SNMP retrieval, and script execution without errors.
Once command-line verification passes, activate Spine in Cacti:
- Log in to Cacti as an administrator.
- Navigate to Console > Configuration > Settings > Paths.
- Under Spine Poller File Path (or Spine Binary File Location), enter:
/usr/local/spine/bin/spine - Optionally, set Spine Config File Path to
/usr/local/spine/etc/spine.conf(if left blank, Spine automatically searches its sibling../etcdirectory). - Verify that Cacti indicates
[OK: FILE FOUND]. - Click Save.
- Navigate to Console > Configuration > Settings > Poller.
- Change the Poller Type dropdown from
cmd.phptospine. - Click Save.
The next scheduled polling cycle by poller.php will immediately invoke Spine.
Spine parameters are configured at three distinct levels:
Configured under Console > Configuration > Settings > Poller:
| Parameter | Recommended Value | Description |
|---|---|---|
| Script and Script Server Timeout | 25 seconds | Maximum duration Spine waits for an external script or Script Server call before timing out and returning NaN. Must be less than your polling interval. |
Configured under Console > Data Collection > Data Collectors (select your collector):
| Parameter | Recommended Value | Description |
|---|---|---|
| Maximum Concurrent Poller Processes | 1–2 per CPU core | Number of Spine processes launched concurrently. For a 4-core system, 4 to 8 processes is typical. |
| Maximum Threads per Process | 10–20 threads | Number of concurrent threads per process. Do not set higher than 50, as excessive context switching degrades performance. |
| Number of PHP Script Servers | 2–5 per process | Number of persistent script_server.php workers maintained per Spine process to handle script data queries. |
Configured on individual devices under Console > Management > Devices:
| Parameter | Default | Description |
|---|---|---|
| Device Threads | 1 | Number of concurrent threads dedicated to polling this specific device. Increase for high-density switches or routers with hundreds of interfaces. |
| Maximum OIDs Per Get Request | 10–60 | Number of SNMP OIDs bundled into a single SNMP GET request. Higher values increase throughput over high-latency links, provided the device agent supports it. |
Each concurrent Spine process, thread, and script server requires database
connections. Ensure your MySQL/MariaDB max_connections limit is sized
adequately:
Total Connections >= (Data Collectors * Processes * (Threads + Script Servers + 2)) + 50
If this setting is too low, Spine will fail with FATAL: Connection to MySQL database failed.
Edit /etc/my.cnf.d/server.cnf (or /etc/mysql/mariadb.conf.d/50-server.cnf)
and set:
[mysqld]
max_connections = 500Restart the database server after changing max_connections.
If SELinux is enforcing, allow the web server and poller to establish outgoing network connections:
setsebool -P httpd_can_network_connect 1
setsebool -P httpd_can_network_connect_db 1Ensure the Spine binary has the appropriate system binary context (bin_t):
semanage fcontext -a -t bin_t "/usr/local/spine/bin/spine"
restorecon -v /usr/local/spine/bin/spineIf using a confined profile for Apache or PHP-FPM, allow execution of the Spine binary:
# Add to /etc/apparmor.d/local/usr.sbin.apache2:
/usr/local/spine/bin/spine rix,
/usr/local/spine/etc/spine.conf r,Reload AppArmor:
apparmor_parser -r /etc/apparmor.d/usr.sbin.apache2-
Cause: Spine cannot locate or read
spine.conf. -
Fix: Ensure
/usr/local/spine/etc/spine.confexists and is readable by the user executing the poller (e.g.apacheorwww-data):ls -la /usr/local/spine/etc/spine.conf chmod 640 /usr/local/spine/etc/spine.conf
-
Cause: Spine is missing the SUID root permission required to open raw ICMP sockets.
-
Fix: Restore SUID permissions on the binary:
chown root:root /usr/local/spine/bin/spine chmod u+s /usr/local/spine/bin/spine
- Cause: Incorrect database credentials in
spine.conf, database host unreachable, or MySQL/MariaDBmax_connectionsreached. - Fix: Test database connectivity manually with
mysql -u cactiuser -p -h localhost cactiand increasemax_connectionsin your MySQL configuration.
To confirm Spine is functioning in production, open Console > Utilities > System Utilities > View Cacti Log. Look for the poller completion summary line:
SYSTEM STATS: Time:12.3456 Method:spine Processes:4 Threads:40 Hosts:250 HostsPerProcess:63 DataSources:12400 RRDsProcessed:6200
If the log displays Method:spine, Spine is running successfully.
Copyright (c) 2004-2026 The Cacti Group
