Skip to content

Set up Prometheus, Node Exporter, and Grafana on Debian or Ubuntu

Step by step guide to build a monitoring stack on a Debian/Ubuntu server. Versions used below are the latest stable as of this writing (August 2026): Prometheus 3.13.1, Node Exporter 1.12.1, Grafana 13.1.1. Check the release pages before you run this in case newer versions are out.

Architecture

+----------------+   scrapes :9100   +----------------+
|  Node Exporter | <---------------- |   Prometheus   |
|   :9100        |                   |   :9090        |
+----------------+                   +--------+-------+
                                              |
                                              | PromQL queries :9090
                                              v
                                     +----------------+
                                     |    Grafana     |
                                     |   :3000        |
                                     +----------------+
                                              |
                                              v
                                        Browser / user

Prerequisites

  • A Debian or Ubuntu server with sudo access
  • curl and tar installed
  • Ports 9090 (Prometheus), 9100 (Node Exporter), 3000 (Grafana) open on your firewall if you access them remotely

Part 1: Install Prometheus

Step 1: Create the prometheus system user

bash
sudo useradd --no-create-home --shell /bin/false prometheus

Step 2: Create directories

bash
sudo mkdir -p /etc/prometheus /var/lib/prometheus

Step 3: Download Prometheus

bash
cd /tmp
curl -LO https://github.com/prometheus/prometheus/releases/download/v3.13.1/prometheus-3.13.1.linux-amd64.tar.gz
tar -xvf prometheus-3.13.1.linux-amd64.tar.gz

Step 4: Install the binaries

bash
sudo cp prometheus-3.13.1.linux-amd64/prometheus /usr/local/bin/
sudo cp prometheus-3.13.1.linux-amd64/promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool

Step 5: Install console templates and set ownership

bash
sudo cp -r prometheus-3.13.1.linux-amd64/consoles /etc/prometheus
sudo cp -r prometheus-3.13.1.linux-amd64/console_libraries /etc/prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus

Step 6: Create the config file

bash
sudo tee /etc/prometheus/prometheus.yml > /dev/null <<EOF
global:
  scrape_interval: 10s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
EOF

Node Exporter's scrape job gets added in Part 3, once it's installed.

Step 7: Create the systemd service

bash
sudo tee /etc/systemd/system/prometheus.service > /dev/null <<EOF
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target

[Service]
User=prometheus
Group=prometheus
Type=simple
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 \\
  --storage.tsdb.retention.time=365d
ExecReload=/bin/kill -HUP \$MAINPID

[Install]
WantedBy=multi-user.target
EOF

ExecReload is what makes systemctl reload prometheus work in Part 3. Without it systemd refuses the reload with "Job type reload is not applicable", and your only option is a full restart. Note the backslash in \$MAINPID: this heredoc is unquoted so the shell would otherwise expand the variable to nothing while writing the file.

Step 8: Start and enable Prometheus

bash
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus

Step 9: Verify

bash
sudo systemctl status prometheus
curl -s http://localhost:9090/-/healthy

Open http://<server-ip>:9090 in a browser to confirm the UI loads.

Clean up the Prometheus download

bash
rm -rf /tmp/prometheus-3.13.1.linux-amd64*

Part 2: Install Node Exporter

Step 1: Create the node_exporter system user

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

Step 2: Download Node Exporter

bash
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

Step 3: Install the binary

bash
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

Step 4: Create the systemd service

bash
sudo tee /etc/systemd/system/node_exporter.service > /dev/null <<EOF
[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

[Install]
WantedBy=multi-user.target
EOF

Step 5: Start and enable Node Exporter

bash
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter

Step 6: Verify

bash
curl -s http://localhost:9100/metrics | head

Clean up the Node Exporter download

bash
rm -rf /tmp/node_exporter-1.12.1.linux-amd64*

Part 3: Point Prometheus at Node Exporter

Step 1: Add the scrape job

bash
sudo vim /etc/prometheus/prometheus.yml

Add under scrape_configs:

yaml
  - job_name: "node_exporter"
    static_configs:
      - targets: ['localhost:9100']

Step 2: Validate the config

bash
promtool check config /etc/prometheus/prometheus.yml

Step 3: Reload Prometheus

bash
sudo systemctl reload prometheus

Step 4: Verify the target is up

Open http://<server-ip>:9090/targets, both prometheus and node_exporter jobs should show State = UP.

Part 4: Install Grafana

Official method: APT repository, so apt-get update keeps Grafana current. Source: https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/

Step 1: Install prerequisites

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

Step 2: Import the GPG key

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

Step 3: Add the stable repository

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

Step 4: Update package list

bash
sudo apt-get update

Step 5: Install Grafana OSS

bash
sudo apt-get install -y grafana

Step 6: Start and enable Grafana

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

Step 7: Verify

bash
sudo systemctl status grafana-server

Open http://<server-ip>:3000. Default login is admin / admin, you'll be asked to change it on first sign-in.

Part 5: Optional Grafana config (custom domain / HTTPS)

Only needed if you're putting Grafana behind a domain name with TLS.

Step 1: Edit grafana.ini

bash
sudo vim /etc/grafana/grafana.ini
ini
[server]
http_addr =
http_port = 3000
domain = mysite.com
root_url = https://subdomain.mysite.com:3000
cert_key = /etc/grafana/grafana.key
cert_file = /etc/grafana/grafana.crt
enforce_domain = False
protocol = https

Step 2: Restart Grafana

bash
sudo systemctl restart grafana-server

Step 3 (optional): Nginx reverse proxy

nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen 80;
    listen [::]:80;

    server_name your_domain www.your_domain;

    location / {
        proxy_set_header Host $http_host;
        proxy_pass http://localhost:3000;
    }

    location /api/live {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $http_host;
        proxy_pass http://localhost:3000;
    }
}

Part 6: Connect Grafana to Prometheus

Step 1: Add the data source

In Grafana: Connections > Data sources > Add data source > Prometheus.

Set URL to:

http://localhost:9090

Click Save & test, you should see "Successfully queried the Prometheus API."

Step 2: Import the Node Exporter dashboard

Dashboards > New > Import, enter dashboard ID:

1860

Select your Prometheus data source when prompted, click Import. This is the community "Node Exporter Full" dashboard and it covers CPU, memory, disk, and network out of the box.

Service management cheat sheet

service          start                 status                enable
---------------  --------------------  --------------------  -------------------------------
prometheus       systemctl start       systemctl status       systemctl enable prometheus
node_exporter    systemctl start       systemctl status       systemctl enable node_exporter
grafana-server   systemctl start       systemctl status       systemctl enable grafana-server

Reload configs without downtime:

bash
sudo systemctl reload prometheus
sudo systemctl restart grafana-server

Where to go next

One server is where this starts, not where it ends. The next two steps are usually alerting (Alertmanager, so a full disk pages you at 3am instead of surprising you at 9) and a second exporter for whatever the box actually runs. If that box is a website, self-hosting WordPress with Docker and Redis is the other half of the same setup.

Monitoring at larger scale is a good chunk of my work: Grafana and Prometheus observability, including a benchmarking rig that dispatched ten million requests in fifteen minutes. Happy to talk it through.

Uninstall

Remove Prometheus

bash
sudo systemctl disable --now prometheus
sudo rm -f /usr/local/bin/prometheus /usr/local/bin/promtool
sudo rm -rf /etc/prometheus /var/lib/prometheus /etc/systemd/system/prometheus.service
sudo userdel prometheus
sudo systemctl daemon-reload

Remove Node Exporter

bash
sudo systemctl disable --now node_exporter
sudo rm -f /usr/local/bin/node_exporter /etc/systemd/system/node_exporter.service
sudo userdel node_exporter
sudo systemctl daemon-reload

Remove Grafana

bash
sudo systemctl stop grafana-server
sudo apt-get remove -y grafana
sudo rm -i /etc/apt/sources.list.d/grafana.list