Run node_exporter and Prometheus on One VPS Node
Install node_exporter and Prometheus as systemd services on a single VPS, scrape localhost only, and keep the time series store small and restart-safe.
Netbay Developer Relations
Netbay Engineering
On this page
A single VPS does not need a metrics mesh. It needs one process that exposes kernel facts and one process that scrapes them on a timer. node_exporter reads /proc and /sys and speaks Prometheus text format on port 9100. Prometheus pulls that endpoint, stores samples, and answers PromQL. Together they are the smallest metrics stack that still has history, not just a live top snapshot.
This is not a fleet design. There is no service discovery, no remote write, and no sidecar per container. Bind both listeners to 127.0.0.1, put a reverse proxy in front of Prometheus if you need a browser, and let systemd restart them. On Intel Xeon Platinum cores with High-Speed SSD, this pair is cheap: a few hundred MB of RAM and a few GB of TSDB if you cap retention.
Install node_exporter as a dedicated user
Do not run the exporter as root. Create a system user, drop the binary under /usr/local/bin, and give it a unit that restarts on failure. Official release tarballs are enough; skip package-manager versions that lag by years unless you like surprise metric name changes.
sudo useradd --no-create-home --shell /usr/sbin/nologin nodeexp
sudo tar -C /tmp -xzf node_exporter-*.linux-amd64.tar.gz
sudo install -o root -g root -m 0755 /tmp/node_exporter-*/node_exporter /usr/local/bin/node_exporterThe unit should listen on localhost only. Collectors you do not need stay disabled so the card stays small. Filesystem and diskstats matter. Hardware sensors and InfiniBand do not. Enable the systemd unit, then curl the metrics endpoint from the box itself and confirm node_cpu_seconds_total and node_memory_MemAvailable_bytes exist.
[Unit]
Description=Prometheus node_exporter
After=network-online.target
[Service]
User=nodeexp
Group=nodeexp
ExecStart=/usr/local/bin/node_exporter --web.listen-address=127.0.0.1:9100 --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|run)($|/)
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
[Install]
WantedBy=multi-user.targetIf you leave 9100 on a public interface, the whole internet will scrape your CPU. L3/L4 DDoS filtering will not hide an open metrics port. Localhost plus SSH tunnels or a private reverse proxy is the correct default on a Lucknow VPS that has a public IPv4.
Prometheus: one scrape job, one data directory
Prometheus needs a config file, a data directory owned by its user, and a unit with a memory cap so a compaction spike cannot eat the app. Retention of 15 days is plenty for a node you live on. Two-hour blocks on High-Speed SSD compact quickly. Do not point --storage.tsdb.path at a tmpfs.
A minimal prometheus.yml for a single node is almost rude in how small it is: global scrape_interval 15s, one job named node, target 127.0.0.1:9100. Evaluation interval can match scrape interval. External labels are optional until you have a second box.
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: node
static_configs:
- targets: ['127.0.0.1:9100']
- job_name: prometheus
static_configs:
- targets: ['127.0.0.1:9090']The self-scrape job is not vanity. It tells you when Prometheus is falling behind, when the TSDB is compacting, and when scrape duration climbs. Those are the metrics that explain a hole in every other graph.
Start Prometheus bound to localhost:9090. Confirm Status, Targets shows both jobs UP. Query node_uname_info to prove labels arrived. If the target is DOWN, it is almost always the listen address, a firewall on loopback you did not know you had, or the exporter unit failed to start.
Size the TSDB before it surprises you
Prometheus stores every sample. node_exporter with default collectors is roughly 500 to 1000 series. At 15 second scrape, 15 days is on the order of a few hundred MB to a couple of GB, not tens of GB. Still set --storage.tsdb.retention.time=15d and --storage.tsdb.retention.size=4GB so a collector explosion cannot fill the root filesystem. High-Speed SSD handles the write amplification; your inode budget and backup jobs do not.
Watch process_resident_memory_bytes for both processes after a day. node_exporter should stay tiny. Prometheus grows with series count, not with how pretty Grafana is. If RSS climbs past a gigabyte on a 2 GB VPS, you enabled too many collectors or scraped something chatty. Drop collectors before you drop the app.
Operate it like any other unit
Enable both units. Add a systemd drop-in that sets MemoryMax on Prometheus. Back up prometheus.yml with the rest of /etc, not the TSDB. The TSDB is rebuildable; the config is not. When you upgrade binaries, restart one at a time and watch the UP flags. A scrape gap of 30 seconds is a blip. A scrape gap of 30 minutes is an outage you will only notice when you need the graph.
Do not expose Prometheus to the world to "just look at the graph." Use SSH local forwarding: ssh -L 9090:127.0.0.1:9090 user@VPS and open localhost:9090 on your laptop. That keeps the query API off the public NIC where credential stuffing is a hobby.
Takeaway
One exporter, one Prometheus, localhost listeners, 15 day retention, and a memory cap are enough to give a VPS a real metrics history. You can follow this on a fresh Ubuntu 24.04 VPS from Netbay in under 60 seconds — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance