Node exporter setup: Linux server metrics in Prometheus (2026 guide)
Install node_exporter the production way: dedicated user, systemd unit, firewalling the metrics port, wiring it into Prometheus, and the five metrics actually worth watching - plus the textfile collector trick for exposing your own numbers.
The AlertKick team
node_exporter is a single static binary that reads /proc and /sys and serves every Linux host metric that matters on port 9100. Setup is ten minutes: binary, system user, systemd unit, firewall rule, one stanza in Prometheus. This guide does all five properly - including the firewall step that most tutorials skip and the shortlist of metrics that deserve alerts, because the default /metrics page emits over a thousand series and maybe ten of them will ever wake you up. It assumes a running Prometheus server (install guide here).
1. Install the binary
From prometheus.io/download - substitute the current version for 1.12.1:
cd /tmp
curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.12.1/node_exporter-1.12.1.linux-amd64.tar.gz
tar xvf node_exporter-1.12.1.linux-amd64.tar.gz
sudo cp node_exporter-1.12.1.linux-amd64/node_exporter /usr/local/bin/
sudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter
One deliberate non-step: no Docker. The project itself recommends against containerising node_exporter, because its whole job is reading the host’s /proc and /sys, and a container’s view of those is not the host’s. The static binary under systemd is the supported path.
2. The systemd unit
# /etc/systemd/system/node_exporter.service
[Unit]
Description=Prometheus Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
Restart=on-failure
ExecStart=/usr/local/bin/node_exporter \
--collector.systemd
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
curl -s localhost:9100/metrics | head -5
The defaults enable the collectors you want (cpu, meminfo, filesystem, diskstats, netdev, loadavg, and more). --collector.systemd is the one non-default worth adding on servers - it exposes unit states, so you can alert on any service entering failed instead of writing a check per service.
3. Firewall the port - this step is not optional
/metrics is unauthenticated and reveals more than people expect: kernel version, mounted filesystems and their sizes, network interfaces, systemd unit names. Nobody outside your monitoring path should be able to read it.
# Allow only the Prometheus server (adjust the IP), nothing else
sudo ufw allow from 10.0.1.5 to any port 9100 proto tcp
sudo ufw deny 9100/tcp
If exporter traffic crosses untrusted networks, node_exporter also supports TLS and basic auth natively via --web.config.file - worth it between data centres, overkill inside one private subnet.
4. Wire it into Prometheus
On the Prometheus server, add a job to /etc/prometheus/prometheus.yml:
scrape_configs:
- job_name: "node"
static_configs:
- targets: ["10.0.1.10:9100", "10.0.1.11:9100"]
labels:
env: "prod"
promtool check config /etc/prometheus/prometheus.yml && sudo systemctl reload prometheus
Status -> Targets in the Prometheus UI should show the node job UP within one scrape interval. If it shows context deadline exceeded, that is the firewall from step 3 doing its job too well - re-check the allow rule.
5. The five metrics that matter (out of a thousand)
The /metrics page is a firehose. These are the series worth queries and alerts on day one:
node_filesystem_avail_bytes- free disk. The good alert is not “90% full” but “full within 4 hours at the current rate”:predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 4*3600) < 0.node_memory_MemAvailable_bytes- the honest memory metric. IgnoreMemFree, which Linux keeps low on purpose;MemAvailableaccounts for reclaimable cache.node_cpu_seconds_total- CPU usage by mode. Sustained saturation:1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])). On VMs, also watchmode="steal"- steal above a few percent means a noisy neighbour or an oversold host, and no amount of local tuning fixes it.node_load15vs CPU count -node_load15 / count by (instance) (node_cpu_seconds_total{mode="idle"})above ~1.5 means work is queueing.up- the scrape itself.up{job="node"} == 0is the alert that catches a dead exporter, a dead host, or a broken network path. Without it, every other alert fails silent instead of loud.
A ready-made set of fifteen rules built on exactly these - thresholds, for: durations, annotations - is in Prometheus alert rules for Linux servers, and Alertmanager turns them into notifications.
Bonus: the textfile collector
The most underused node_exporter feature. Any script can drop a .prom file into a directory and its numbers become Prometheus metrics - backup age, cert days remaining, queue depth, anything:
# in the systemd unit: --collector.textfile.directory=/var/lib/node_exporter
echo "backup_last_success_timestamp $(date +%s)" \
| sudo tee /var/lib/node_exporter/backup.prom
Alert on time() - backup_last_success_timestamp > 86400 * 2 and the silent-backup-failure class of incident disappears.
The half node_exporter cannot see
node_exporter reports what the host believes about itself, scraped from inside the network. It has no opinion on whether users can actually reach the site, whether the TLS certificate is about to expire, whether the domain renews - or whether the Prometheus server scraping it is still alive, since a monitoring stack cannot alert on its own death. The standard fix is cheap: pair the internal stack with external checks. AlertKick’s free monitors probe HTTP, TCP, DNS, SSL, and domain expiry from the outside and page through real escalation chains (Slack, Telegram, phone, on-call rotations), and a one-line heartbeat from the Prometheus host closes the who-watches-the-watcher loop. Set both up free - the two halves make one whole picture.
Frequently asked questions
- What is node_exporter?
- The official Prometheus exporter for Linux host metrics. It reads /proc and /sys and serves CPU, memory, disk, filesystem, and network metrics on port 9100 for a Prometheus server to scrape. One static binary, no dependencies.
- What port does node_exporter use?
- 9100 by default, on /metrics. Do not expose it to the internet: it reveals kernel version, mounted filesystems, hardware layout, and running-service hints. Firewall it so only your Prometheus server can reach it, or bind it to a private interface.
- Should I run node_exporter in Docker?
- The project explicitly recommends against it. node_exporter reads host /proc and /sys, and containerisation gets in the way - metrics end up describing the container's view instead of the host's unless you punch through with mounts and host networking. Run the static binary under systemd.
- Which node_exporter metrics should I alert on?
- Start with five: node_filesystem_avail_bytes (disk fill - use predict_linear), node_memory_MemAvailable_bytes (memory pressure), node_cpu_seconds_total (sustained saturation and steal), node_load15 relative to CPU count, and the up metric for the scrape itself - a dead exporter looks like silence otherwise.