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.
Three upstream references are worth keeping open alongside this: the Prometheus configuration reference, the list of Node Exporter collectors and what each one costs you, and Grafana's own Debian install docs.
Architecture
+----------------+ scrapes :9100 +----------------+
| Node Exporter | <---------------- | Prometheus |
| :9100 | | :9090 |
+----------------+ +--------+-------+
|
| PromQL queries :9090
v
+----------------+
| Grafana |
| :3000 |
+----------------+
|
v
Browser / userPrerequisites
- A Debian or Ubuntu server with sudo access
curlandtarinstalled- SSH access for a tunnel. Keep ports 9090, 9100 and 3000 closed to the public internet; this guide runs all three services on loopback.
Part 1: Install Prometheus
Step 1: Create the prometheus system user
sudo useradd --no-create-home --shell /bin/false prometheusStep 2: Create directories
sudo mkdir -p /etc/prometheus /var/lib/prometheusStep 3: Download Prometheus
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.gzStep 4: Install the binaries
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/promtoolStep 5: Install console templates and set ownership
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/prometheusStep 6: Create the config file
sudo tee /etc/prometheus/prometheus.yml > /dev/null <<EOF
global:
scrape_interval: 10s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
EOFNode Exporter's scrape job gets added in Part 3, once it's installed.
Step 7: Create the systemd service
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.listen-address=127.0.0.1:9090 \\
--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
EOFExecReload 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
sudo systemctl daemon-reload
sudo systemctl enable --now prometheusStep 9: Verify
sudo systemctl status prometheus
curl -s http://localhost:9090/-/healthyFrom your own computer, open an SSH tunnel and leave it running:
ssh -N -L 9090:127.0.0.1:9090 -L 3000:127.0.0.1:3000 user@serverReplace user@server with your SSH destination. Open http://localhost:9090 on your computer to confirm the UI loads.
Clean up the Prometheus download
rm -rf /tmp/prometheus-3.13.1.linux-amd64*Part 2: Install Node Exporter
Step 1: Create the node_exporter system user
sudo useradd --no-create-home --shell /bin/false node_exporterStep 2: Download Node Exporter
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.gzStep 3: Install the binary
sudo cp node_exporter-1.12.1.linux-amd64/node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporterStep 4: Create the systemd service
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 --web.listen-address=127.0.0.1:9100
[Install]
WantedBy=multi-user.target
EOFStep 5: Start and enable Node Exporter
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporterStep 6: Verify
curl -s http://localhost:9100/metrics | headClean up the Node Exporter download
rm -rf /tmp/node_exporter-1.12.1.linux-amd64*Part 3: Point Prometheus at Node Exporter
Step 1: Add the scrape job
sudo vim /etc/prometheus/prometheus.ymlAdd under scrape_configs:
- job_name: "node_exporter"
static_configs:
- targets: ['localhost:9100']Step 2: Validate the config
promtool check config /etc/prometheus/prometheus.ymlStep 3: Reload Prometheus
sudo systemctl reload prometheusStep 4: Verify the target is up
Through the SSH tunnel, open http://localhost:9090/targets, both prometheus and node_exporter jobs should show State = UP.
Part 4: Install Grafana
Official method: APT repository. apt-get update refreshes package lists; apt-get install --only-upgrade grafana installs an available upgrade. Source: https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/
Step 1: Install prerequisites
sudo apt-get install -y apt-transport-https wget gnupgStep 2: Import the GPG key
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.ascStep 3: Add the stable repository
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.listStep 4: Update package list
sudo apt-get updateStep 5: Install Grafana OSS
sudo apt-get install -y grafanaStep 6: Start and enable Grafana
sudo mkdir -p /etc/systemd/system/grafana-server.service.d
printf '[Service]\nEnvironment=GF_SERVER_HTTP_ADDR=127.0.0.1\n' | sudo tee /etc/systemd/system/grafana-server.service.d/listen.conf
sudo systemctl daemon-reload
sudo systemctl enable grafana-server
sudo systemctl restart grafana-serverStep 7: Verify
sudo systemctl status grafana-serverThrough the SSH tunnel, open http://localhost: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)
The SSH tunnel is enough for private access. For a public dashboard, point grafana.example.com at the server and terminate TLS at nginx. Grafana stays on loopback HTTP; do not enable HTTPS on its upstream port.
Step 1: Edit grafana.ini
sudo vim /etc/grafana/grafana.ini[server]
http_addr = 127.0.0.1
http_port = 3000
domain = grafana.example.com
root_url = https://grafana.example.com/
enforce_domain = true
protocol = httpStep 2: Restart Grafana
sudo systemctl restart grafana-serverStep 3 (optional): Nginx reverse proxy
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name grafana.example.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1: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 $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:3000;
}
}Install nginx and Certbot, then save the configuration above as /etc/nginx/sites-available/grafana.example.com. Replace the example domain throughout:
sudo apt-get install -y nginx certbot python3-certbot-nginx
sudo ln -s /etc/nginx/sites-available/grafana.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d grafana.example.com
sudo certbot renew --dry-runAllow ports 80 and 443 for nginx, not 3000. Certbot installs the TLS configuration and renewal timer. Keep Grafana authentication enabled and change the initial password through the SSH tunnel before exposing the domain.
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:9090Click Save & test, you should see "Successfully queried the Prometheus API."
Step 2: Import the Node Exporter dashboard
Dashboards > New > Import, enter dashboard ID:
1860Select 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-serverReload configs without downtime:
sudo systemctl reload prometheus
sudo systemctl restart grafana-serverWhere 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
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-reloadRemove Node Exporter
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-reloadRemove Grafana
sudo systemctl stop grafana-server
sudo apt-get remove -y grafana
sudo rm -i /etc/apt/sources.list.d/grafana.list