Monitoring CPU, RAM and Network Traffic on Self-Hosted Servers with Prometheus and Grafana on Ubuntu Server

A step-by-step guide to installing Prometheus, Node Exporter and Grafana on Ubuntu Server, building a lightweight monitoring system for CPU, RAM and network traffic across your self-hosted nodes.

Monitoring CPU, RAM and Network Traffic on Self-Hosted Servers with Prometheus and Grafana on Ubuntu Server

Anyone running even a couple of self-hosted servers — a NAS, a VPS for personal projects, a small homelab with two or three machines — eventually asks the same question: how can I tell if a node is about to run out of RAM, if the CPU is under heavy load, or if network traffic is spiking, without having to log in and check manually every time? The most popular open-source answer is a pair of tools that has become a de facto standard: Prometheus for collecting metrics and Grafana for displaying them in clear, customizable dashboards.

In this guide we'll set up a lightweight monitoring cluster on Ubuntu Server, designed to keep an eye on CPU, RAM and network traffic across several self-hosted nodes, with minimal impact on the resources of the machines being monitored. You don't need to be an experienced system administrator: every step is explained along with the basic concepts behind it.

Why monitor your self-hosted servers

Anyone hosting their own services — a website, a mail server, a NAS, a Nextcloud instance, or a small cluster for personal projects — often only discovers problems once the service is already unreachable: a full disk, memory exhausted by a leaking process, a network interface saturated with traffic. A monitoring system lets you:

  • Spot warning signs early: RAM usage steadily climbing for days before a crash, for instance, is visible on a graph long before it becomes an actual problem.
  • Understand the cause of slowdowns: if a site responds slowly, a historical graph of CPU and network I/O helps determine whether the cause is a load spike or something else.
  • Plan upgrades: watching resource usage over time is the simplest way to know when you really need more RAM or bandwidth, instead of upgrading "by gut feeling".
  • Receive alerts: once metrics are being collected, you can set up automatic alerts (for example via Alertmanager, Prometheus's companion tool) whenever a threshold is crossed.

The tools: Prometheus, Node Exporter and Grafana

Before installing anything, it's worth understanding what each component does, since the stack is made up of three distinct pieces working together:

  • Prometheus is a time-series database specialized in collecting metrics. Unlike many older monitoring systems, Prometheus works on a "pull" model: at regular intervals, it reaches out to the machines being monitored to ask for the latest data, instead of waiting for those machines to send it.
  • Node Exporter is a small program that needs to be installed on every machine you want to monitor. Its job is to expose system metrics (CPU usage, RAM, disk, network interfaces, and so on) in a format Prometheus can read, through a simple internal web page on port 9100.
  • Grafana is the visual layer: it connects to Prometheus as a "data source" and lets you build dashboards with charts, colored thresholds, visual alerts and much more, with no coding required.

In practice: Node Exporter collects raw data on each node, Prometheus periodically fetches and stores it, and Grafana reads it from Prometheus and draws it.

Requirements and architecture of the lightweight cluster

For this guide we'll assume a simple but realistic setup for a homelab or a small set of VPS instances:

  • A "central" node running Ubuntu Server (either the 24.04 LTS release, still the most widely used in many homelabs, or the newer 26.04 LTS), where we'll install Prometheus and Grafana. 1 vCPU and 1-2 GB of RAM are enough to monitor around ten nodes with basic metrics.
  • One or more nodes "to be monitored" (possibly including the central node itself), on each of which we'll install only Node Exporter, an extremely lightweight process (a few MB of RAM).
  • SSH access with sudo privileges on all machines involved.

The big advantage of this pairing is precisely its lightness: unlike heavier solutions based on complex agents or relational databases, Prometheus and Node Exporter are written in Go, compiled as single binaries with no dependencies to install, and designed to use very few resources even on modest hardware (a Raspberry Pi or a cheap VPS works perfectly well).

Step 1: install Prometheus on the central node

Let's SSH into the central node and first create a dedicated system user, so Prometheus won't run with root privileges:

sudo useradd --no-create-home --shell /bin/false prometheus
sudo mkdir /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheus

Next, we download the latest stable release of Prometheus (the 3.x series at the time of writing) from the official downloads page. It's good practice to always check the most recent version available at prometheus.io/download before proceeding:

cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v3.15.1/prometheus-3.15.1.linux-amd64.tar.gz
tar xvf prometheus-3.15.1.linux-amd64.tar.gz
cd prometheus-3.15.1.linux-amd64

sudo cp prometheus promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool

sudo cp -r consoles/ console_libraries/ /etc/prometheus/
sudo chown -R prometheus:prometheus /etc/prometheus/consoles /etc/prometheus/console_libraries

Step 2: create the Prometheus systemd service

To make Prometheus start automatically when the server boots and be managed by systemd (the component on Ubuntu responsible for starting and supervising background services), let's create a unit file:

sudo nano /etc/systemd/system/prometheus.service

with this content:

[Unit]
Description=Prometheus Monitoring System
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=prometheus
Group=prometheus
ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus/ \
  --web.console.templates=/etc/prometheus/consoles \
  --web.console.libraries=/etc/prometheus/console_libraries \
  --web.listen-address=0.0.0.0:9090
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Let's also create a minimal starting prometheus.yml file (we'll complete it in Step 4):

sudo nano /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

Then we start and enable the service:

sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus

Let's check it's running with sudo systemctl status prometheus: it should show active (running) in green. At this point, Prometheus's web interface is already reachable at http://CENTRAL-NODE-IP:9090.

Step 3: install Node Exporter on every node to be monitored

This step needs to be repeated on each node you want to monitor (including the central node, if you also want to monitor its resources). Let's create a dedicated user and install the binary:

sudo useradd --no-create-home --shell /bin/false node_exporter

cd /tmp
wget 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 chown node_exporter:node_exporter /usr/local/bin/node_exporter

Let's also create the systemd service for Node Exporter:

sudo nano /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter

Node Exporter now exposes raw metrics on port 9100: we can check this with curl http://localhost:9100/metrics, which should return hundreds of lines of data about CPU, memory, filesystems and network interfaces.

Step 4: configure Prometheus to collect metrics from all nodes

Back on the central node, let's update /etc/prometheus/prometheus.yml by adding a "job" for every node to monitor, with its IP address and Node Exporter's port 9100:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: "node_exporter"
    static_configs:
      - targets:
          - "localhost:9100"
          - "192.168.1.11:9100"
          - "192.168.1.12:9100"

After every change to this file, it's a good idea to check its syntax with promtool check config /etc/prometheus/prometheus.yml, then reload the configuration without restarting the service:

sudo systemctl reload prometheus

From the Prometheus interface (http://CENTRAL-NODE-IP:9090/targets) we can check that all nodes appear with UP status: that's the sign Prometheus is successfully querying them.

Step 5: open the required firewall ports

If ufw (Ubuntu's default firewall) is active on the nodes, the necessary ports need to be opened. On the central node, to allow access to the Prometheus interface and, later, Grafana's:

sudo ufw allow 9090/tcp
sudo ufw allow 3000/tcp

On each monitored node, on the other hand, Node Exporter's port 9100 should be opened only toward the central node's IP address, not toward the whole internet, so as not to expose system metrics to anyone:

sudo ufw allow from 192.168.1.10 to any port 9100 proto tcp

(replacing 192.168.1.10 with the central node's actual IP).

Step 6: install Grafana

Grafana is best installed via the official APT repository, which makes future updates as simple as apt upgrade. On the central node:

sudo apt-get install -y apt-transport-https wget gnupg

sudo mkdir -p /etc/apt/keyrings
sudo wget -q -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
sudo chmod 644 /etc/apt/keyrings/grafana.asc

echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list

sudo apt-get update
sudo apt-get install -y grafana

Let's start and enable the service:

sudo systemctl daemon-reload
sudo systemctl enable --now grafana-server

Grafana is now reachable at http://CENTRAL-NODE-IP:3000. The default credentials on first login are admin / admin: Grafana will immediately prompt you to change the password, which you should always do, especially if the server is exposed to the internet.

Step 7: connect Grafana to Prometheus

Once inside the Grafana interface:

  • From the side menu, go to Connections > Data sources and choose Add data source.
  • Select Prometheus from the list.
  • In the URL field, enter http://localhost:9090 (since Prometheus runs on the same machine; if it were elsewhere, you'd use its IP address instead).
  • Click Save & test: if everything is configured correctly, a success message will appear.

Step 8: import a ready-made dashboard for CPU, RAM and network traffic

There's no need to build charts from scratch: Grafana's community shares ready-made, free dashboards. The most widely used one for Node Exporter is the "Node Exporter Full" dashboard (ID 1860), which shows CPU, RAM, disk space, I/O and network traffic for every monitored node in a single panel.

To import it:

  • From the side menu, Dashboards > New > Import.
  • In the "Import via grafana.com" field, enter 1860 and click Load.
  • Select the Prometheus data source you just created as the data source, then click Import.

Within a few seconds, the dashboard fills up with real data from every monitored node, letting you pick which node to display from a dropdown menu at the top.

Tips for secure, sustainable monitoring

  • Don't expose Prometheus and Node Exporter directly to the internet. Neither has built-in authentication by default: keep them on a private network (LAN, a VPN like WireGuard or Tailscale) or behind a reverse proxy with authentication.
  • Put Grafana behind HTTPS if it's reachable from the internet, for example with an Nginx reverse proxy and a Let's Encrypt certificate.
  • Set a sensible data retention period. By default, Prometheus keeps data for 15 days; on a homelab with limited disk space it can be useful to lower this with the --storage.tsdb.retention.time flag, or raise it if you have more storage available.
  • Consider Alertmanager for automatic notifications (email, Telegram, etc.) whenever a metric crosses a critical threshold, instead of having to check dashboards manually.
  • Update Prometheus and Node Exporter regularly: since they're single binaries, updating simply means repeating the download-and-replace steps, while Grafana updates with apt upgrade once the repository is configured.

Conclusion

With just a handful of commands and minimal impact on resources, Prometheus, Node Exporter and Grafana let you build a professional-grade monitoring system even for a simple homelab or a small set of personal servers. Once you're comfortable with the stack, it's easy to expand it with new scrape jobs (for instance to monitor application services, not just hardware), new community dashboards, and automatic alerts through Alertmanager.

Official sources

Share

What's Your Reaction?

Like Like 0
Dislike Dislike 0
Love Love 0
Funny Funny 0
Angry Angry 0
Sad Sad 0
Wow Wow 0