| |

LFCE 126 ๐Ÿง node_exporter โ€” Setup

โฑ๏ธ Estimated read: 12 min | |

node_exporter is the standard Prometheus exporter for Linux host metrics. It is a single static binary that reads from /proc and /sys, translates the kernel’s counters and gauges into Prometheus’s exposition format, and serves them over HTTP on port 9100. It does not store data, query data, or alert. It collects and exposes, and Prometheus scrapes it.

This chapter covers the setup of node_exporter on a Linux host: downloading the binary, creating a dedicated system user, writing a systemd unit that keeps the exporter running, opening the firewall only to the Prometheus server, and wiring the target into Prometheus’s scrape configuration. It also covers the textfile collector, which lets external scripts expose custom metrics through node_exporter’s endpoint, and the collector-selection flags that control which host subsystems are scraped.

Key point: node_exporter’s /metrics endpoint is unauthenticated by default and exposes kernel version, mounted filesystems, network interfaces, and systemd unit names. The firewall rule that allows only the Prometheus server is not optional.


Why node_exporter setup has these requirements

The host-view problem. node_exporter reads the host’s /proc and /sys filesystems directly. In a container, those filesystems reflect the container’s namespace, not the host’s. The project recommends against containerizing node_exporter for exactly this reason: the metrics would describe the container, not the machine . The static binary under systemd is the supported deployment model.

The privilege problem. node_exporter does not need root. It reads files that are world-readable on most systems, and it runs as an unprivileged user. The system user created for it has no shell and no home directory. The textfile collector directory, if used, is owned by that user so the exporter can read the files written by cron jobs or other scripts .

The exposure problem. The metrics endpoint reveals more than the hostname. It lists every mounted filesystem with its size and free space, every network interface with its addresses, and every systemd unit with its state. A default node_exporter installation listens on all interfaces and accepts requests from anyone who can reach port 9100. The firewall rule that restricts access to the Prometheus server is the only thing standing between the metrics and the network .


a. Downloading and installing the binary

node_exporter is distributed as a compressed tarball containing a single executable. The download URL follows the pattern https://github.com/prometheus/node_exporter/releases/download/v<version>/node_exporter-<version>.linux-amd64.tar.gz .

# Download the current release
cd /tmp
curl -LO https://github.com/prometheus/node_exporter/releases/download/v1.12.1/node_exporter-1.12.1.linux-amd64.tar.gz

# Extract and install the binary
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/

# Create a dedicated system user
sudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter

The binary is static, meaning it does not depend on shared libraries. It can be placed in /usr/local/bin and run from any directory.

b. The systemd unit

A systemd unit keeps the exporter running and restarts it if it crashes. The unit runs as the node_exporter user, which has no shell and no home directory. The --collector.systemd flag enables the systemd collector, which exposes the state of every systemd unit on the host .

# /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

After creating the unit, reload systemd, enable the service, and start it.

sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
systemctl status node_exporter --no-pager

The exporter’s own health can be verified by requesting the metrics endpoint. A successful response begins with metric names like node_cpu_seconds_total and node_memory_MemTotal_bytes .

curl -s localhost:9100/metrics | head -5

c. Firewall configuration

The metrics endpoint is unauthenticated. The firewall must restrict access to the Prometheus server’s IP address and deny everything else .

# Allow only the Prometheus server (adjust the IP)
sudo ufw allow from 10.0.1.5 to any port 9100 proto tcp
sudo ufw deny 9100/tcp

# For firewalld
# sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.5/32" port protocol="tcp" port="9100" accept'
# sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" port protocol="tcp" port="9100" reject'
# sudo firewall-cmd --reload

If exporter traffic crosses an untrusted networkโ€”between data centers, for exampleโ€”node_exporter supports TLS and basic authentication through the --web.config.file flag. Inside a single private subnet, the firewall rule is sufficient .

d. Wiring into Prometheus

Prometheus discovers node_exporter through a scrape job in prometheus.yml. The job name identifies the group of targets, and the targets list contains the host:port pairs of every node_exporter instance.

# /etc/prometheus/prometheus.yml
scrape_configs:
  - job_name: "node"
    static_configs:
      - targets: ["10.0.1.10:9100", "10.0.1.11:9100"]

After editing the configuration, validate it with promtool and reload Prometheus.

promtool check config /etc/prometheus/prometheus.yml
sudo systemctl reload prometheus

The Prometheus UI’s Status โ†’ Targets page shows whether the scrape is succeeding. A target showing UP means the connection and the metrics parse both succeeded. A target showing context deadline exceeded usually means the firewall is blocking the scrape .

e. The textfile collector

The textfile collector exposes custom metrics that node_exporter cannot collect natively. A script writes a file in the Prometheus exposition format to a designated directory, and node_exporter reads it and includes its contents in the /metrics response .

The directory must exist, be owned by the node_exporter user, and be passed to the exporter with the --collector.textfile.directory flag.

# Create the directory
sudo mkdir -p /var/lib/node_exporter/textfile_collector
sudo chown node_exporter:node_exporter /var/lib/node_exporter/textfile_collector

# Update the systemd unit ExecStart line
# ExecStart=/usr/local/bin/node_exporter \
#   --collector.systemd \
#   --collector.textfile.directory=/var/lib/node_exporter/textfile_collector

A backup script can write a metric indicating the timestamp of the last successful backup. The write must be atomicโ€”write to a temporary file, then move it into placeโ€”so that Prometheus never reads a partially written file .

#!/bin/bash
# /usr/local/bin/backup-metric.sh
OUT=/var/lib/node_exporter/textfile_collector/backup.prom
TEMP="${OUT}.$$"

cat > "$TEMP" <<EOF
# HELP backup_last_success_timestamp_seconds Unix timestamp of last successful backup
# TYPE backup_last_success_timestamp_seconds gauge
backup_last_success_timestamp_seconds $(date +%s)
EOF

mv "$TEMP" "$OUT"

The script runs from cron after the backup completes. node_exporter reads the file on the next scrape and exposes the metric alongside the host metrics.


Complete Example Session

# ============================================
# PART 1: DOWNLOAD AND INSTALL
# ============================================
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/
# ============================================
# PART 2: CREATE THE SYSTEM USER
# ============================================
sudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter
# ============================================
# PART 3: CREATE THE SYSTEMD UNIT
# ============================================
sudo tee /etc/systemd/system/node_exporter.service <<'EOF'
[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
EOF
# ============================================
# PART 4: START AND VERIFY
# ============================================
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
curl -s localhost:9100/metrics | head -5
# ============================================
# PART 5: FIREWALL RULES
# ============================================
# Allow only the Prometheus server
sudo ufw allow from 10.0.1.5 to any port 9100 proto tcp
sudo ufw deny 9100/tcp

# Verify the rules
sudo ufw status
# ============================================
# PART 6: ADD THE SCRAPE JOB
# ============================================
# On the Prometheus server, add to prometheus.yml:
# scrape_configs:
#   - job_name: "node"
#     static_configs:
#       - targets: ["10.0.1.10:9100"]

promtool check config /etc/prometheus/prometheus.yml
sudo systemctl reload prometheus
# ============================================
# PART 7: VERIFY IN PROMETHEUS
# ============================================
# Open Prometheus UI at http://prometheus:9090/targets
# The "node" job should show UP

# Or query directly
curl 'http://prometheus:9090/api/v1/query?query=up{job="node"}'
# ============================================
# PART 8: ENABLE THE TEXTFILE COLLECTOR
# ============================================
sudo mkdir -p /var/lib/node_exporter/textfile_collector
sudo chown node_exporter:node_exporter /var/lib/node_exporter/textfile_collector

# Edit the systemd unit to add:
# --collector.textfile.directory=/var/lib/node_exporter/textfile_collector
sudo systemctl daemon-reload
sudo systemctl restart node_exporter
# ============================================
# PART 9: WRITE A CUSTOM METRIC
# ============================================
sudo tee /usr/local/bin/backup-metric.sh <<'EOF'
#!/bin/bash
OUT=/var/lib/node_exporter/textfile_collector/backup.prom
TEMP="${OUT}.$$"
cat > "$TEMP" <<METRICS
backup_last_success_timestamp_seconds $(date +%s)
METRICS
mv "$TEMP" "$OUT"
EOF
sudo chmod +x /usr/local/bin/backup-metric.sh
# ============================================
# PART 10: VERIFY THE CUSTOM METRIC
# ============================================
/usr/local/bin/backup-metric.sh
curl -s localhost:9100/metrics | grep backup_last_success

The ten parts covered download and install, user creation, systemd unit creation, service start and verification, firewall rules, Prometheus scrape configuration, target verification, textfile collector enablement, custom metric writing, and custom metric verification.


Quick Reference

Installation commands

StepCommand
Downloadcurl -LO https://github.com/prometheus/node_exporter/releases/download/v<ver>/node_exporter-<ver>.linux-amd64.tar.gz
Extracttar xvf node_exporter-*.tar.gz
Install binarysudo cp node_exporter /usr/local/bin/
Create usersudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter

systemd unit fields

FieldValue
Usernode_exporter
ExecStart/usr/local/bin/node_exporter --collector.systemd
Restarton-failure
WantedBymulti-user.target

Firewall commands

ToolCommand
ufw (allow)ufw allow from <prom-ip> to any port 9100 proto tcp
ufw (deny)ufw deny 9100/tcp
firewalldrich rule with source address and port

Prometheus scrape job

FieldExample
job_namenode
targets["10.0.1.10:9100"]

textfile collector

ItemValue
Directory/var/lib/node_exporter/textfile_collector
Ownershipnode_exporter:node_exporter
Flag--collector.textfile.directory=<path>
File formatPrometheus exposition format
Write methodAtomic (temp file + mv)

Best Practices

โœ… Do This:

# Run as an unprivileged system user
User=node_exporter                                      # โœ…
# Restrict port 9100 to the Prometheus server only
ufw allow from 10.0.1.5 to any port 9100                # โœ…
# Use atomic writes for textfile metrics
mv "$TEMP" "$OUT"                                       # โœ…
# Enable the systemd collector for unit state metrics
--collector.systemd                                     # โœ…

โŒ Don’t Do This:

# Run node_exporter as root
User=root                                               # โŒ
# Expose port 9100 to the entire network
ufw allow 9100/tcp                                      # โŒ
# Containerize node_exporter for host metrics
# The container sees its own /proc, not the host's       # โŒ
# Write textfile metrics non-atomically
cat > "$OUT" <<< "metric 1"                             # โŒ (partial reads)

Common Pitfalls

PitfallWhy It HappensFix
Prometheus target shows context deadline exceededFirewall blocks port 9100Allow the Prometheus IP on port 9100
Metrics are missing for some subsystemsCollector disabled by defaultEnable with --collector.<name>
textfile metrics not appearingWrong directory or permissionsCheck --collector.textfile.directory and chown
Service fails to startBinary path or user missingVerify /usr/local/bin/node_exporter and node_exporter user
High cardinality / slow scrapesToo many collectors enabledDisable unused collectors; monitor scrape_duration_seconds

Real-World Examples

1. Download and install

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-*.tar.gz && sudo cp node_exporter-*/node_exporter /usr/local/bin/

2. Create user

sudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter

3. systemd unit

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter --collector.systemd
Restart=on-failure

4. Enable and start

sudo systemctl enable --now node_exporter

5. Verify metrics

curl -s localhost:9100/metrics | head -5

6. Firewall allow

sudo ufw allow from 10.0.1.5 to any port 9100 proto tcp

7. Firewall deny

sudo ufw deny 9100/tcp

8. Prometheus scrape job

- job_name: "node"
  static_configs:
    - targets: ["10.0.1.10:9100"]

9. Textfile directory

sudo mkdir -p /var/lib/node_exporter/textfile_collector && sudo chown node_exporter: /var/lib/node_exporter/textfile_collector

10. Atomic metric write

echo "metric 1" > /tmp/metric.$$ && mv /tmp/metric.$$ /var/lib/node_exporter/textfile_collector/metric.prom

Visual

The node_exporter flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  NODE_EXPORTER FLOW                                          โ”‚
โ”‚                                                              โ”‚
โ”‚  /proc and /sys                                              โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  node_exporter (port 9100)                                   โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  /metrics endpoint (text format)                             โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  Prometheus scrape (every 15s)                               โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  Time series database                                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Firewall boundary

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FIREWALL                                                    โ”‚
โ”‚                                                              โ”‚
โ”‚  Prometheus (10.0.1.5) โ”€โ”€โ–บ ALLOW โ”€โ”€โ–บ node_exporter:9100     โ”‚
โ”‚                                                              โ”‚
โ”‚  Everyone else โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ DENY                              โ”‚
โ”‚                                                              โ”‚
โ”‚  /metrics is unauthenticated.                                โ”‚
โ”‚  It reveals kernel version, mounts, interfaces, units.      โ”‚
โ”‚  The deny rule is mandatory.                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

textfile collector

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  TEXTFILE COLLECTOR                                          โ”‚
โ”‚                                                              โ”‚
โ”‚  Cron job / script                                           โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  Write metric to temp file                                   โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  mv temp โ†’ /var/lib/node_exporter/textfile_collector/       โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  node_exporter reads on next scrape                          โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  Metric included in /metrics                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Collector selection

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  COLLECTORS                                                  โ”‚
โ”‚                                                              โ”‚
โ”‚  Default: cpu, meminfo, filesystem, diskstats, netdev,      โ”‚
โ”‚           loadavg, and others                                โ”‚
โ”‚                                                              โ”‚
โ”‚  Optional (enable explicitly):                               โ”‚
โ”‚    --collector.systemd       (unit states)                   โ”‚
โ”‚    --collector.textfile      (custom metrics)                โ”‚
โ”‚    --collector.processes     (process stats)                 โ”‚
โ”‚                                                              โ”‚
โ”‚  High-cardinality collectors may exceed scrape timeout.      โ”‚
โ”‚  Enable one at a time, monitor scrape_duration_seconds.     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Binarynode_exporter
Default port9100
Default path/metrics
System usernode_exporter (no shell, no home)
systemd unit/etc/systemd/system/node_exporter.service
Key flag--collector.systemd
Firewall ruleAllow only Prometheus IP on 9100
textfile flag--collector.textfile.directory=<path>
Prometheus jobjob_name: node, targets on port 9100

Key takeaways:

  • node_exporter is a collector, not a monitoring system. It reads /proc and /sys, exposes the metrics on port 9100, and does nothing else. Prometheus scrapes the endpoint and stores the data .
  • Run it as an unprivileged system user under systemd. The binary does not need root. The system user has no shell and no home directory, and the systemd unit restarts the exporter if it crashes .
  • The firewall rule is mandatory. The /metrics endpoint is unauthenticated and exposes kernel version, mounted filesystems, network interfaces, and systemd unit names. Allow only the Prometheus server’s IP and deny everything else .
  • The systemd collector exposes unit state. With --collector.systemd, the exporter reports whether each systemd unit is active, failed, or inactive, which allows alerting on any service entering a failed state without writing a check per service .
  • The textfile collector is how custom metrics reach Prometheus. A script writes a file in the exposition format to a designated directory, and node_exporter includes its contents in the next scrape. The write must be atomic to avoid partial reads .
  • Enable additional collectors cautiously. Collectors disabled by default are disabled for reasons: high cardinality, long runtime, or significant resource demands. Enable one at a time and monitor scrape_duration_seconds to ensure the scrape completes before the timeout .

Remember: node_exporter setup is four steps: install the binary, create the system user and systemd unit, restrict port 9100 to the Prometheus server, and add the target to prometheus.yml. The textfile collector is the extension point for metrics that node_exporter cannot collect natively. The collector flags control which host subsystems are scraped. Get the firewall rule right first: an unauthenticated metrics endpoint on an open port is a disclosure risk, not a convenience. Then verify the target shows UP in Prometheus before moving on to dashboards and alerts.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!