← Start of tutorial

WIUNIX ACADEMY

Build a Prometheus + Grafana monitoring stack

Page 3 of 5. Review the earlier steps and prerequisites before continuing.

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Ubuntu 26.10Reviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment2 editable values
10

LET’S BUILD

Query Prometheus directly before you open Grafana

Initial scrapes take time. Retry the API a bounded 12 times, with five seconds between attempts. Require HTTP 200, API status success and up=1 for the exact local Prometheus and node_exporter instances.

Bash

Monitoring server terminal.

(
set -euo pipefail
response=$(mktemp)
trap 'rm -f "$response"' EXIT
ok=0
for attempt in $(seq 1 12); do
  if code=$(curl -sS --connect-timeout 2 --max-time 5 -G \
    --data-urlencode 'query=up' -o "$response" -w '%{http_code}' \
    http://127.0.0.1:9090/api/v1/query); then
    if [ "$code" = 200 ] && jq -e '.status == "success" and .data.resultType == "vector" and any(.data.result[]; .metric.job == "prometheus" and .metric.instance == "127.0.0.1:9090" and .value[1] == "1") and any(.data.result[]; .metric.job == "node-exporter" and .metric.instance == "127.0.0.1:9100" and .value[1] == "1")' "$response" >/dev/null; then
      ok=1; break
    fi
  fi
  sleep 5
done
[ "$ok" = 1 ] || { cat "$response" >&2; echo 'Both local targets must have up=1' >&2; exit 1; }
jq . "$response"
)
EXAMPLE OUTPUT
Illustrative result excerpt; actual timestamps vary:
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"job":"prometheus","instance":"127.0.0.1:9090"},"value":[1792444800,"1"]},{"metric":{"job":"node-exporter","instance":"127.0.0.1:9100"},"value":[1792444800,"1"]}]}}
How do I know it worked?

The response status is success and the result contains value 1 for both the prometheus and node-exporter jobs.

The query returns an empty result

Review the discovered targets to see whether Prometheus can scrape each job and whether any target is marked down.

Bash
curl -fsS --connect-timeout 2 --max-time 5 http://127.0.0.1:9090/api/v1/targets | jq .

Prepare private Grafana binding before installation

Create this systemd override before installing the package, so even a package-triggered start binds only to loopback.

Bash

Monitoring server terminal.

(
set -euo pipefail
sudo install -d -m 0755 /etc/systemd/system/grafana-server.service.d
sudo nano /etc/systemd/system/grafana-server.service.d/academy-local.conf
)
How do I know it worked?

The command completes successfully; stop and inspect any error before continuing.

Grafana private binding override

Paste this file, save and exit. The environment override takes precedence over grafana.ini. An approved TLS reverse proxy can later use this same local listener.

systemd · /etc/systemd/system/grafana-server.service.d/academy-local.conf

File contents; save in the named file, not in the shell.

[Service]
Environment="GF_SERVER_HTTP_ADDR=127.0.0.1"
How do I know it worked?

Only a loopback bind is configured.

11

LET’S BUILD

Install Grafana from the official APT repository

Grafana documents the Debian and Ubuntu APT repository as the standard installation path. This guide installs the OSS package named grafana. If your environment requires the free Enterprise build instead, switch only the package name and keep the same repository steps.

The repository key is stored under /etc/apt/keyrings and the package source list is written under /etc/apt/sources.list.d.

Bash

Monitoring server terminal.

(
set -euo pipefail
sudo systemctl daemon-reload
sudo install -d -m 0755 /etc/apt/keyrings
key=$(mktemp)
trap 'rm -f "$key"' EXIT
curl -fL --connect-timeout 10 --max-time 60 https://apt.grafana.com/gpg-full.key -o "$key"
gpg --show-keys "$key"
sudo install -m 0644 "$key" /etc/apt/keyrings/grafana.asc
printf '%s\n' 'deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main' | sudo tee /etc/apt/sources.list.d/grafana.list >/dev/null
sudo apt-get update
sudo apt-get install -y grafana
dpkg-query -W -f='${Version}\n' grafana
)
How do I know it worked?

APT can read the Grafana repository and installs the grafana package without signature or dependency errors.

APT cannot validate or find the Grafana package

Check the repository file, key file and APT policy output to confirm that the official repository is visible to the package manager.

Bash
sudo cat /etc/apt/sources.list.d/grafana.list
sudo ls -l /etc/apt/keyrings/grafana.asc
sudo apt-cache policy grafana

Open the next configuration file

Open the file, paste the contents in the following panel, then save and exit (nano: Ctrl+O, Enter, Ctrl+X). Do not run file contents as shell commands.

Bash

Monitoring server terminal.

sudo nano /etc/grafana/provisioning/datasources/prometheus.yaml
How do I know it worked?

The command completes successfully; stop and inspect any error before continuing.

12

LET’S BUILD

Provision the Prometheus data source for Grafana

Grafana supports data source provisioning from declarative files. Using provisioning keeps the first setup reproducible and avoids a manual click path for a basic local Prometheus source.

Create the file below so Grafana loads Prometheus as the default data source at startup.

YAML · /etc/grafana/provisioning/datasources/prometheus.yaml

File contents; save in the named file, not in the shell.

apiVersion: 1

datasources:
  - name: Prometheus
    uid: prometheus-local
    type: prometheus
    access: proxy
    url: http://127.0.0.1:9090
    isDefault: true
    editable: true
How do I know it worked?

The provisioning file exists and points Grafana to the local Prometheus API.

Explore all tutorials ↗