WIUNIX ACADEMY
Build a Prometheus + Grafana monitoring stack
Page 2 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.
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
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.
Monitoring server terminal.
sudo nano /etc/systemd/system/prometheus.serviceThe command completes successfully; stop and inspect any error before continuing.
LET’S BUILD
Create the Prometheus systemd service
This service keeps Prometheus under systemd control and stores metrics in /var/lib/prometheus. The web interface is bound to 127.0.0.1:9090 so the host does not publish Prometheus directly to the network by default.
If you later need remote access, expose it through a trusted reverse proxy or a controlled tunnel rather than widening access immediately.
File contents; save in the named file, not in the shell.
[Unit]
Description=Prometheus Monitoring Server
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 \
--storage.tsdb.retention.time=15d \
--web.listen-address=127.0.0.1:9090
Restart=on-failure
[Install]
WantedBy=multi-user.target
The systemd unit file exists and matches the Prometheus paths created in the earlier steps.
LET’S BUILD
Download and install node_exporter
node_exporter publishes host metrics such as CPU, memory, filesystem and network counters in Prometheus format. The current official download page lists 1.12.1 as the latest release at the review date.
Install only the binary on the monitoring server for now. You will reuse the same pattern on any additional Linux node that you want to monitor later.
Monitoring server terminal.
(
set -euo pipefail
[ "$(uname -m)" = x86_64 ] || { echo 'This download requires amd64/x86_64' >&2; exit 1; }
work=$(mktemp -d)
cd "$work"
curl -fL --connect-timeout 10 --max-time 180 -o node_exporter-1.12.1.linux-amd64.tar.gz \
https://github.com/prometheus/node_exporter/releases/download/v1.12.1/node_exporter-1.12.1.linux-amd64.tar.gz
printf '%s %s\n' 'b51d8a76aa2a9156a55d501aca6276fae09e262259a5e4e831d2c2222f084e63' 'node_exporter-1.12.1.linux-amd64.tar.gz' | sha256sum --check --strict -
tar -xzf node_exporter-1.12.1.linux-amd64.tar.gz
cd node_exporter-1.12.1.linux-amd64
sudo install -o root -g root -m 0755 node_exporter /usr/local/bin/
node_exporter --version
)SHA256 reports OK before extraction; node_exporter reports 1.12.1. Keep the temporary download directory until validation is complete.
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.
Monitoring server terminal.
sudo nano /etc/systemd/system/node_exporter.serviceThe command completes successfully; stop and inspect any error before continuing.
LET’S BUILD
Create the node_exporter systemd service
Run the basic host collectors on loopback. The optional systemd collector is omitted because service metrics need additional D-Bus access; host CPU, memory and filesystem metrics do not need it.
File contents; save in the named file, not in the shell.
[Unit]
Description=Prometheus 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
Restart=on-failure
[Install]
WantedBy=multi-user.target
The node_exporter systemd unit is present and refers to the installed binary path.
LET’S BUILD
Start Prometheus and node_exporter, then verify exact HTTP 200 responses
Validate as the service user before starting either service. The bounded readiness loop accepts only HTTP 200 and rejects redirects, transport failures and timeouts; service active alone is insufficient.
The Prometheus ready endpoint proves it can serve queries. The next step separately confirms that both targets have actually been scraped.
Monitoring server terminal.
(
set -euo pipefail
sudo chown root:prometheus /etc/prometheus/prometheus.yml
sudo chmod 0640 /etc/prometheus/prometheus.yml
sudo -u prometheus /usr/local/bin/promtool check config /etc/prometheus/prometheus.yml
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus node_exporter
systemctl is-active prometheus node_exporter
ok=0
for attempt in $(seq 1 12); do
if code=$(curl -sS --connect-timeout 2 --max-time 5 -o /dev/null -w '%{http_code}' http://127.0.0.1:9090/-/ready); then
if [ "$code" = 200 ]; then ok=1; break; fi
fi
sleep 2
done
[ "$ok" = 1 ] || { echo 'Endpoint did not become ready: http://127.0.0.1:9090/-/ready' >&2; exit 1; }
printf '%s -> 200\n' 'http://127.0.0.1:9090/-/ready'
ok=0
for attempt in $(seq 1 12); do
if code=$(curl -sS --connect-timeout 2 --max-time 5 -o /dev/null -w '%{http_code}' http://127.0.0.1:9100/metrics); then
if [ "$code" = 200 ]; then ok=1; break; fi
fi
sleep 2
done
[ "$ok" = 1 ] || { echo 'Endpoint did not become ready: http://127.0.0.1:9100/metrics' >&2; exit 1; }
printf '%s -> 200\n' 'http://127.0.0.1:9100/metrics'
)Illustrative success (additional promtool messages omitted):
active
active
http://127.0.0.1:9090/-/ready -> 200
http://127.0.0.1:9100/metrics -> 200Both services report active, and each checked URL prints an exact 200 status code.
Prometheus does not stay active
Inspect the recent journal entries and validate that the configuration file and storage path are readable by the Prometheus service account.
sudo journalctl -u prometheus -n 80 --no-pager
sudo ls -ld /etc/prometheus /var/lib/prometheus
sudo ls -l /etc/prometheus/prometheus.yml
sudo -u prometheus /usr/local/bin/promtool check config /etc/prometheus/prometheus.ymlnode_exporter is not listening on port 9100
Check the service log and confirm that no other process already owns the chosen listen address.
sudo journalctl -u node_exporter -n 80 --no-pager
sudo ss -lntp | grep 9100 || true