Running a homelab without proper monitoring is flying blind. You don’t know when your disk is about to fill up, when your RAM spikes, or when a container silently dies — until something breaks. Grafana and Prometheus fix that. Together, they give you gorgeous real-time dashboards and deep metrics for every server, container, and service you run.
This guide walks you through setting up a complete Grafana + Prometheus monitoring stack using Docker Compose. By the end, you’ll have live dashboards showing CPU, RAM, disk, network, and container stats — all self-hosted, no cloud dependency.
What Is Grafana and Prometheus?
Before diving into config files, a quick primer on how these two tools work together:
- Prometheus is a time-series database and metrics scraper. It pulls (“scrapes”) metrics from targets at regular intervals and stores them. Think of it as the data engine.
- Grafana is the visualization layer. It connects to Prometheus (and many other data sources) and renders that data as interactive dashboards.
- Exporters are small agents you install on hosts or services to expose metrics in a format Prometheus understands. The most common is Node Exporter for Linux host metrics.
The flow is simple: Node Exporter → Prometheus → Grafana. Prometheus scrapes exporters; Grafana queries Prometheus; you see pretty graphs.
Prerequisites
- A server or homelab machine running Linux (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed
- Basic familiarity with Docker Compose files
- Ports 3000 (Grafana) and 9090 (Prometheus) available
If you’re running a mini PC or small server for your homelab, a machine with at least 4GB RAM works well. Popular choices like the Beelink Mini S12 Pro or MINISFORUM UM350 handle this stack without breaking a sweat.
Step 1 — Create the Project Directory
Set up a clean directory structure:
| |
Your directory tree will look like:
~/monitoring/
├── docker-compose.yml
├── prometheus/
│ └── prometheus.yml
└── grafana/
└── provisioning/
├── datasources/
│ └── prometheus.yml
└── dashboards/
└── dashboards.yml
Step 2 — Write the Docker Compose File
Create docker-compose.yml:
| |
Key containers explained:
| Container | Role |
|---|---|
prometheus | Metrics database + scraper |
grafana | Dashboard visualization |
node-exporter | Host OS metrics (CPU, RAM, disk, network) |
cadvisor | Docker container metrics |
Change the Grafana password! Replace
changemewith a strong password before starting.
Step 3 — Configure Prometheus
Create prometheus/prometheus.yml:
| |
This tells Prometheus to scrape metrics from itself, the Node Exporter, and cAdvisor every 15 seconds. The --storage.tsdb.retention.time=30d flag in the Compose file keeps 30 days of history — adjust to taste based on your available disk space.
For reference: a typical homelab setup generates roughly 1–2 GB of Prometheus data per month. Even a small SSD in your server handles this easily.
Step 4 — Configure Grafana Auto-Provisioning
Grafana supports automatic data source and dashboard provisioning. This means your setup is reproducible — no clicking through the UI every time.
Create grafana/provisioning/datasources/prometheus.yml:
| |
Create grafana/provisioning/dashboards/dashboards.yml:
| |
Step 5 — Start the Stack
| |
Check all containers are running:
| |
Expected output:
NAME STATUS PORTS
cadvisor Up 0.0.0.0:8080->8080/tcp
grafana Up 0.0.0.0:3000->3000/tcp
node-exporter Up 0.0.0.0:9100->9100/tcp
prometheus Up 0.0.0.0:9090->9090/tcp
Step 6 — Verify Prometheus Targets
Open Prometheus at http://your-server-ip:9090/targets. You should see all three targets (prometheus, node-exporter, cadvisor) with a green UP status.
If a target shows DOWN, check:
- Container is running:
docker compose logs node-exporter - Network connectivity: all containers share the
monitoringbridge network - Firewall rules: ensure the exporter ports aren’t blocked between containers (Docker handles this internally, but check if you have custom iptables rules)
Step 7 — Set Up Grafana Dashboards
Open Grafana at http://your-server-ip:3000 and log in with admin / your password.
The Prometheus data source is already configured via provisioning. Now import community dashboards instead of building from scratch:
Node Exporter Dashboard (ID: 1860)
This is the gold standard for host metrics:
- Go to Dashboards → Import
- Enter dashboard ID: 1860
- Select your Prometheus data source
- Click Import
You’ll instantly have CPU usage, memory, disk I/O, network throughput, system load, and uptime — all broken down and graphed beautifully.
Docker / cAdvisor Dashboard (ID: 193)
For container-level metrics:
- Dashboards → Import
- Enter dashboard ID: 193
- Select Prometheus
- Import
This shows per-container CPU, memory, network, and block I/O. Extremely useful for spotting runaway containers.
Step 8 — Set Up Alerting (Optional but Recommended)
Prometheus has a companion tool called Alertmanager for routing alerts. But for a simpler setup, Grafana’s built-in alerting works great.
Create an Alert in Grafana
- Open the Node Exporter dashboard
- Find the Disk Space Used panel
- Edit → Alert tab → Create alert rule
Example alert for disk space:
Condition: WHEN avg() OF A IS ABOVE 85
For: 5m
Notifications: send to [your notification channel]
Configure Notification Channels
Grafana supports email, Telegram, Slack, PagerDuty, and many more. For homelab use, Telegram is popular — it’s free and instant.
Go to Alerting → Contact points → Add contact point, select Telegram, and paste your bot token + chat ID.
Step 9 — Monitor Multiple Hosts
Got more than one machine to monitor? Node Exporter runs on each host and reports back to the central Prometheus instance.
On each additional host:
| |
Then add the new host to prometheus/prometheus.yml:
| |
Reload Prometheus config without restarting:
| |
This works because of the --web.enable-lifecycle flag we set earlier.
Step 10 — Secure Your Monitoring Stack
If you’re exposing Grafana to the internet (or even just your local network), a few security steps matter:
Change Default Credentials
Update the Grafana admin password immediately:
| |
Or via the Grafana UI: Profile → Change Password.
Put Grafana Behind a Reverse Proxy
Don’t expose Grafana directly. Use Nginx Proxy Manager, Traefik, or Caddy to terminate HTTPS and proxy to port 3000. This gives you a clean URL like https://grafana.yourdomain.com with a valid SSL certificate.
Update the GF_SERVER_ROOT_URL environment variable to match.
Keep Prometheus Internal
Prometheus has no built-in authentication. Never expose port 9090 to the internet. Keep it internal, accessible only by Grafana and your local network. If you need remote access, use Tailscale or a VPN.
Adding More Exporters
The real power of Prometheus comes from its exporter ecosystem. Once your base stack is running, you can plug in dozens of exporters to monitor virtually anything.
Blackbox Exporter — HTTP/TCP Uptime Checks
The Blackbox Exporter lets Prometheus probe endpoints externally — like a lightweight uptime checker built right into your monitoring stack.
Add it to your docker-compose.yml:
| |
Then in prometheus.yml, add a scrape config for your sites:
| |
Now Prometheus checks your URLs every 15 seconds and alerts you if they go down.
SNMP Exporter — Network Gear Metrics
If you have managed switches or routers that support SNMP (Ubiquiti, MikroTik, etc.), the SNMP Exporter pulls port throughput, error rates, and interface stats directly from the hardware — no agent needed on the device.
PostgreSQL Exporter
Running Postgres? Add the prometheuscommunity/postgres-exporter container to your stack and monitor query throughput, connection pool saturation, replication lag, and table bloat.
Using Grafana Loki for Log Aggregation
Grafana’s ecosystem extends beyond metrics. Loki is a log aggregation system designed to work natively with Grafana — think Elasticsearch but lighter and cheaper to run.
With Loki + Promtail (the log shipper), you can:
- View logs alongside metrics in the same Grafana dashboard
- Search logs with LogQL (similar to PromQL)
- Correlate a CPU spike with the exact log lines that caused it
- Set alerts on log patterns (e.g., “alert me if I see more than 10 auth failures per minute”)
Add Loki and Promtail to your stack:
| |
Once Loki is connected as a data source in Grafana, you get a unified observability platform: metrics, logs, and (with Tempo) traces — all in one place.
Backing Up Your Monitoring Data
After investing time in building dashboards and tuning alerts, you want to protect that work. Here’s what to back up:
Grafana: All dashboards, data sources, and settings live in the grafana_data Docker volume. Back this up regularly:
| |
Prometheus: Time-series data is in prometheus_data. For most setups, you don’t need to back up Prometheus itself — the data is ephemeral and regenerates. What matters is backing up your prometheus.yml config and any recording rules. Store those in Git.
Export Grafana Dashboards as JSON: In Grafana, go to any dashboard → Share → Export → Save to file. Keep these JSON files in a Git repo. You can re-import them instantly on a fresh install.
Useful Prometheus Queries (PromQL)
Once your stack is running, here are some handy PromQL queries to build custom panels:
| |
These form the building blocks of custom dashboards tailored to your setup.
Troubleshooting Common Issues
Grafana shows “No data” on panels
- Check Prometheus targets page — all targets must be UP
- Verify the data source URL in Grafana points to
http://prometheus:9090 - Check time range — make sure you’re not looking at “last 5 minutes” with no recent data
Node Exporter shows wrong disk stats
- Adjust the
--collector.filesystem.mount-points-excluderegex to include your actual mount points - For ZFS or Btrfs filesystems, add additional collector flags
cAdvisor can’t access Docker socket
- Make sure
privileged: trueis set in the Compose file - Check that
/var/lib/dockeris accessible from the container
High memory usage from Prometheus
- Reduce scrape frequency from 15s to 30s for less-critical metrics
- Reduce retention time from 30d to 15d
- Add recording rules to pre-aggregate expensive queries
Storage Considerations
For a serious homelab with multiple hosts, consider the storage requirements:
- Prometheus data: ~1–2 GB/month per host with default settings
- Grafana: minimal (dashboard configs only, actual data lives in Prometheus)
- Minimum recommended: 20 GB SSD for a 3-host setup with 30-day retention
If you’re building out your storage, a fast SSD matters more than raw capacity here. The Samsung 870 EVO or WD Red SA500 are solid NAS-grade options that handle the random I/O Prometheus generates well.
Wrapping Up
You now have a full-featured monitoring stack running:
- ✅ Prometheus scraping host and container metrics every 15 seconds
- ✅ Node Exporter reporting CPU, RAM, disk, and network
- ✅ cAdvisor tracking every Docker container
- ✅ Grafana with beautiful dashboards
- ✅ Optional alerting for disk, CPU, or memory thresholds
This stack scales surprisingly well — from a single Raspberry Pi to a multi-host homelab with dozens of services. And because everything runs in Docker Compose, it’s portable: commit your config to Git and you can rebuild the entire monitoring setup on a new machine in under five minutes.
For next steps, consider adding exporters for specific services: Blackbox Exporter for endpoint uptime checks, PostgreSQL Exporter for database metrics, or Loki (Grafana’s log aggregation tool) to add log search alongside your metrics dashboards.
Found this guide useful? Share it with your homelab community — and let us know in the comments what you’re monitoring!