← Self-Hosting · Foundations 8 of 8 · Replaces: guessing why the server feels slow
What You'll Build
The same monitoring tools that real companies use, running on your home server:
node-exporter ──► Prometheus ──► Grafana
(reads CPU, RAM, (saves a reading (turns the history
disk, network) every 15 seconds) into dashboards)
This is also great practice for IT and security jobs — "set up Prometheus and Grafana" is a real skill employers ask for.
Ports: Grafana 3003, Prometheus 9090 · Time: 45 minutes · Difficulty: Medium
Step 1: Tell Prometheus What to Collect
mkdir -p ~/stacks/monitoring && cd ~/stacks/monitoring
nano prometheus.yml
# How often to take a reading from every target
global:
scrape_interval: 15s
# The list of things to read metrics from
scrape_configs:
- job_name: "prometheus" # Prometheus monitoring itself
static_configs:
- targets: ["localhost:9090"]
- job_name: "homeserver" # the server's hardware, via node-exporter
static_configs:
- targets: ["node-exporter:9100"]
Step 2: The Three-Container Stack
nano compose.yaml
services:
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
command: ["--path.rootfs=/host"] # read the real server, not the container
pid: host
volumes:
- /:/host:ro,rslave
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.retention.time=30d" # keep 30 days of history
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3003:3000" # 3000 is taken by Homepage
volumes:
- grafana-data:/var/lib/grafana
volumes:
prometheus-data:
grafana-data:
docker compose up -d
Check Prometheus at http://192.168.1.50:9090 → Status → Targets. Both targets should say UP.
Step 3: Connect Grafana to Prometheus
- Open
http://192.168.1.50:3003. Log in withadmin/admin; you're forced to set a new password. - Connections → Data sources → Add data source → Prometheus.
- Prometheus server URL:
http://prometheus:9090(containers in the same stack find each other by name) → Save & test.
Step 4: Import a Ready-Made Dashboard
- Dashboards → New → Import.
- Enter dashboard ID 1860 ("Node Exporter Full", from grafana.com) → Load.
- Pick your Prometheus data source → Import.
You now have graphs of CPU, memory, disk space and speed, network traffic, and temperatures (if your hardware reports them). Star it so it's on your Grafana home page.
Step 5: Alert When the Disk Is Nearly Full
- Alerting → Contact points → Add: choose your notification method (the same ntfy topic from Uptime Kuma works via a Webhook).
- Alerting → Alert rules → New alert rule. Query (switch to Code mode):
# Percentage of disk space USED on the root filesystem
100 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} * 100)
- Condition: IS ABOVE 85, evaluate every 5m for 15m, send to your contact point → Save.
Troubleshooting
- Target shows DOWN — a typo in
prometheus.yml, or the container name differs. After editing,docker compose restart prometheus. - Dashboard panels say "No data" — pick the right data source and job at the top of the dashboard, and give it a few minutes to collect.
- Want Docker container stats too? Add cAdvisor as another scrape target — a good next project.
What's Next?
The foundations are done. Time for the fun part — the apps:
Browse the Self-Hosted Apps →