Best Monitoring Stacks 2025: Complete Observability Guide
Compare monitoring approaches from minimal to full observability. Prometheus, Grafana, Netdata, and more.
Your homelab runs 15+ services across 3 servers. When something breaks at 2 AM, you wake up to angry family members complaining about “the internet being down.” You have no idea which service failed, when it started, or why.
Welcome to the world of homelab observability. This guide compares three monitoring approaches: Minimal (Uptime Kuma), Standard (Prometheus + Grafana), and Full (LGTM stack). We’ll show you exactly what to monitor, how much resources each option consumes, and which stack fits your needs.
What You’ll Learn:
- Three monitoring stack tiers (Minimal, Standard, Full)
- Resource requirements and performance impact
- What metrics actually matter for homelabs
- Alerting setup and notification strategies
- Dashboard configurations and best practices
- Cost-benefit analysis of each approach
Time Investment: 15 minutes to read | 1-4 hours to deploy (depending on stack)
Table of Contents
- Executive Summary
- The Three Tiers
- Minimal Stack: Uptime Kuma
- Standard Stack: Prometheus + Grafana
- Full Stack: LGTM
- Resource Requirements
- Alerting Strategies
- Dashboard Best Practices
- Which Stack to Choose
- Conclusion
Executive Summary
TL;DR - Which monitoring stack should you deploy?
| If You Want… | Choose | Why |
|---|---|---|
| Simple uptime checks | Uptime Kuma | Beautiful UI, 5-minute setup, under 100MB RAM |
| Metrics + Dashboards | Prometheus + Grafana | Industry standard, rich ecosystem |
| Full observability | LGTM Stack | Logs + Metrics + Traces + Dashboards |
| Just starting out | Uptime Kuma | Start simple, upgrade later |
The Honest Truth: Most homelabs only need uptime monitoring. Start with Uptime Kuma. Upgrade to Prometheus+Grafana when you need detailed metrics. Only deploy LGTM if you’re running production-like services or learning enterprise observability.
2025 Trend: Observability is becoming accessible to homelabs. Tools like Grafana Cloud Free Tier and Uptime Kuma make monitoring trivial to deploy.
The Three Tiers
Complexity & Features ↑
|
Full Observability |
(LGTM Stack) |───────────────────────┐ (Enterprise-grade)
| | • Logs (Loki)
| | • Metrics (Prometheus)
| | • Traces (Tempo)
| | • Dashboards (Grafana)
| | Resource: ~2GB RAM
Standard |───────────────────┐ |
(Prometheus | | |
+ Grafana) | | | • Metrics collection
| | | • Custom dashboards
| | | • Alerting rules
| | | Resource: ~800MB RAM
Minimal |───────────┐ | |
(Uptime Kuma) | | | | • Uptime checks
| | | | • Status pages
| | | | • Notifications
| | | | Resource: ~100MB RAM
└────────────┴────────┴────┘
→
Simplicity & Resource Usage Minimal Stack: Uptime Kuma
What it is: Self-hosted uptime monitoring with beautiful UI.
Philosophy: “Just tell me if my services are up”
Features
- ✅ HTTP/HTTPS monitoring
- ✅ TCP port monitoring
- ✅ Ping/DNS checks
- ✅ Keyword monitoring (check page content)
- ✅ Certificate expiration alerts
- ✅ Multi-channel notifications (Discord, Slack, Email, Telegram, etc.)
- ✅ Public status pages
- ✅ Response time tracking
- ✅ Beautiful modern UI
Deployment
Docker Compose:
# docker-compose.yml
version: '3.8'
services:
uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptime-kuma
restart: unless-stopped
ports:
- "3001:3001"
volumes:
- ./data:/app/data docker-compose up -d
# Access at http://localhost:3001 Setup Time: 5 minutes Resource Usage: 70-100MB RAM
Configuration Example
Monitoring Jellyfin:
- Open Uptime Kuma UI
- Click ”+ Add New Monitor”
- Configure:
- Monitor Type: HTTP(s)
- Friendly Name: Jellyfin
- URL: https://jellyfin.homelab.local
- Check Interval: 60 seconds
- Keyword: (optional - check for “Jellyfin” on page)
- Accepted Status Codes: 200
- Add notification endpoint (Discord/Slack/Email)
- Save
What you get:
- Green/red status indicator
- Response time graph
- Uptime percentage (24h, 7d, 30d)
- Certificate expiration countdown
- Instant alerts on downtime
Pros & Cons
Pros:
- ✅ Extremely simple setup (5 minutes)
- ✅ Beautiful, modern UI
- ✅ Minimal resource usage (under 100MB RAM)
- ✅ Public status pages (share with users)
- ✅ No configuration files (all via GUI)
- ✅ Multi-channel notifications
Cons:
- ❌ No detailed metrics (CPU, RAM, disk)
- ❌ Limited historical data (90 days default)
- ❌ No custom dashboards
- ❌ Basic uptime checks only
Best for: Personal homelabs, simple uptime monitoring, public status pages
Standard Stack: Prometheus + Grafana
What it is: Industry-standard metrics collection and visualization.
Philosophy: “Measure everything, visualize anything”
Components
Prometheus: Time-series database and metrics collector
- Scrapes metrics from exporters
- Stores time-series data
- Provides query language (PromQL)
- Built-in alerting
Grafana: Visualization and dashboarding
- Connects to Prometheus as data source
- Pre-built dashboard library (15,000+ dashboards)
- Custom dashboards with drag-and-drop
- Advanced alerting and notifications
Exporters: Collect metrics from services
- Node Exporter: System metrics (CPU, RAM, disk, network)
- cAdvisor: Container metrics
- Blackbox Exporter: Endpoint probes (uptime checks)
- Service-specific exporters (nginx, MySQL, PostgreSQL, etc.)
Deployment
Docker Compose Stack:
# docker-compose.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_INSTALL_PLUGINS=grafana-clock-panel
volumes:
- grafana_data:/var/lib/grafana
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
privileged: true
volumes:
prometheus_data:
grafana_data: Prometheus Configuration:
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
# Prometheus itself
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Node Exporter (system metrics)
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
# cAdvisor (container metrics)
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
# Add your services here
- job_name: 'jellyfin'
static_configs:
- targets: ['jellyfin:8096']
metrics_path: '/metrics' # if service exports Prometheus metrics Setup Steps
- Deploy stack:
docker-compose up -d - Access Grafana: http://localhost:3000 (admin/admin)
- Add Prometheus data source:
- Configuration → Data Sources → Add Prometheus
- URL:
http://prometheus:9090 - Save & Test
- Import dashboards:
- Dashboards → Import
- Popular IDs:
- 1860: Node Exporter Full
- 893: Docker Container & Host Metrics
- 11074: Node Exporter for Prometheus
- Configure alerts (optional):
- Alerting → Notification channels
- Add Discord/Slack webhook
- Create alert rules
Setup Time: 1-2 hours (with dashboard customization) Resource Usage: ~800MB RAM total
Key Metrics to Monitor
System Health:
- CPU usage per core
- Memory usage (used, free, cached)
- Disk I/O (read/write rates)
- Network traffic (ingress/egress)
- Disk usage (percentage full)
Container Health:
- Container CPU usage
- Container memory usage
- Container restart count
- Network traffic per container
Application Health:
- HTTP request rate
- Response times (p50, p95, p99)
- Error rates (4xx, 5xx)
- Active connections
Sample PromQL Queries
# CPU usage per core
rate(node_cpu_seconds_total{mode!="idle"}[5m])
# Memory usage percentage
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
# Disk usage percentage
(node_filesystem_size_bytes - node_filesystem_free_bytes) / node_filesystem_size_bytes * 100
# Container CPU usage
rate(container_cpu_usage_seconds_total[5m])
# HTTP request rate
rate(http_requests_total[5m]) Pros & Cons
Pros:
- ✅ Industry standard (transferable skills)
- ✅ Rich ecosystem (15k+ Grafana dashboards)
- ✅ Powerful querying (PromQL)
- ✅ Service-specific exporters available
- ✅ Long-term metric retention
- ✅ Highly customizable
Cons:
- ❌ More complex setup (2+ hours initially)
- ❌ Higher resource usage (~800MB RAM)
- ❌ Requires learning PromQL
- ❌ No built-in log aggregation
- ❌ Dashboard creation has learning curve
Best for: Serious homelabs, users wanting detailed metrics, those learning DevOps/SRE skills
Full Stack: LGTM
What it is: Complete observability stack (Logs + Metrics + Traces + Dashboards)
LGTM = Loki + Grafana + Tempo + Mimir (or Prometheus)
Components
- Loki: Log aggregation (like “Prometheus for logs”)
- Grafana: Dashboards and visualization
- Tempo: Distributed tracing
- Mimir (or Prometheus): Metrics storage
Why LGTM?
- Unified observability platform
- Correlate logs, metrics, and traces
- Production-grade debugging capabilities
- Enterprise-level insights
Deployment
Docker Compose (Simplified LGTM):
# docker-compose.yml
version: '3.8'
services:
# Loki - Log aggregation
loki:
image: grafana/loki:latest
container_name: loki
restart: unless-stopped
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki_data:/loki
# Promtail - Log shipper
promtail:
image: grafana/promtail:latest
container_name: promtail
restart: unless-stopped
volumes:
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
# Tempo - Tracing
tempo:
image: grafana/tempo:latest
container_name: tempo
restart: unless-stopped
command: -config.file=/etc/tempo.yaml
ports:
- "3200:3200" # Tempo API
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
volumes:
- ./tempo.yaml:/etc/tempo.yaml
- tempo_data:/tmp/tempo
# Prometheus - Metrics
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
# Grafana - Dashboards
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
volumes:
- grafana_data:/var/lib/grafana
- ./grafana-datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml
volumes:
loki_data:
tempo_data:
prometheus_data:
grafana_data: Grafana Data Sources Config:
# grafana-datasources.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
- name: Loki
type: loki
access: proxy
url: http://loki:3100
- name: Tempo
type: tempo
access: proxy
url: http://tempo:3200 What You Get
Logs (Loki):
- Aggregate logs from all containers
- Search across all services
- Filter by time, service, level
- Tail logs in real-time
- Correlate with metrics
Metrics (Prometheus):
- Same as Standard Stack
- Integrated with logs and traces
Traces (Tempo):
- Distributed request tracing
- Visualize request flow across services
- Identify bottlenecks
- Root cause analysis
Dashboards (Grafana):
- Unified view of logs, metrics, traces
- Jump from metric spike to related logs
- Trace requests end-to-end
Setup Time: 3-4 hours (complex configuration) Resource Usage: ~2GB RAM total
Pros & Cons
Pros:
- ✅ Complete observability (logs + metrics + traces)
- ✅ Production-grade debugging
- ✅ Correlate data across sources
- ✅ Enterprise-level insights
- ✅ Learn industry-standard tools
Cons:
- ❌ Complex setup (3-4 hours minimum)
- ❌ High resource usage (~2GB RAM)
- ❌ Overkill for simple homelabs
- ❌ Steep learning curve
- ❌ Requires instrumenting applications for tracing
Best for: Advanced users, production-like deployments, learning enterprise observability, microservices architectures
Resource Requirements
Comparison Table
| Stack | RAM Usage | CPU Usage | Disk (30 days) | Setup Time | Complexity |
|---|---|---|---|---|---|
| Uptime Kuma | 70-100 MB | ~1% | ~100 MB | 5 min | ⭐ Easy |
| Prometheus + Grafana | 700-900 MB | 2-5% | 2-5 GB | 1-2 hrs | ⭐⭐⭐ Medium |
| LGTM Stack | 1.8-2.5 GB | 5-10% | 10-20 GB | 3-4 hrs | ⭐⭐⭐⭐⭐ Hard |
Hardware Recommendations
For Uptime Kuma:
- Minimum: 512MB RAM, 1 CPU core, 1GB disk
- Recommended: 1GB RAM, 1 CPU core, 5GB disk
- Deployment: Run on any homelab server
For Prometheus + Grafana:
- Minimum: 2GB RAM, 2 CPU cores, 20GB disk
- Recommended: 4GB RAM, 2 CPU cores, 50GB disk
- Deployment: Dedicated monitoring VM or powerful server
For LGTM Stack:
- Minimum: 4GB RAM, 4 CPU cores, 50GB disk
- Recommended: 8GB RAM, 4 CPU cores, 100GB disk
- Deployment: Dedicated monitoring server
Alerting Strategies
Alert Fatigue Prevention
Rule of thumb: Only alert on actionable issues.
Bad alerts (cause fatigue):
- ❌ “Disk is 50% full” (not urgent)
- ❌ “CPU spiked to 80% for 10 seconds” (normal)
- ❌ “Service restarted” (if auto-restart works)
Good alerts (require action):
- ✅ “Service down for >5 minutes”
- ✅ “Disk is 90% full”
- ✅ “SSL certificate expires in 7 days”
- ✅ “Backup failed 2 consecutive nights”
Alert Tiers
Tier 1: Critical (Wake me up)
- Service completely down
- Data loss imminent (disk 95% full)
- Security breach detected
Delivery: SMS, phone call, loud alarm
Tier 2: Warning (Tell me soon)
- Service degraded (high error rate)
- Resource usage trending toward limit
- Certificate expiring in 7 days
Delivery: Discord, Slack, email
Tier 3: Info (I’ll check tomorrow)
- Successful backups
- Service restarts (if auto-recover works)
- Performance trends
Delivery: Dashboard, email digest
Alert Configuration Examples
Uptime Kuma:
- Configure in UI per monitor
- Choose notification channels
- Set retry count before alert
Prometheus Alertmanager:
# alert-rules.yml
groups:
- name: homelab_alerts
interval: 30s
rules:
# Service down
- alert: ServiceDown
expr: up == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Service {{ $labels.job }} is down"
# High memory usage
- alert: HighMemoryUsage
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "Memory usage >90% on {{ $labels.instance }}"
# Disk space low
- alert: DiskSpaceLow
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "Disk {{ $labels.device }} is 90% full"
# SSL certificate expiring
- alert: SSLCertExpiring
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 7
for: 1h
labels:
severity: warning
annotations:
summary: "SSL cert for {{ $labels.instance }} expires in under 7 days" Dashboard Best Practices
Design Principles
- Start with a system overview (CPU, RAM, disk, network)
- Group related metrics (e.g., all Docker metrics together)
- Use consistent color schemes (red = bad, green = good)
- Add context (thresholds, baselines, annotations)
- Keep it simple (5-7 panels per dashboard max)
Recommended Dashboards
System Overview:
- CPU usage (per core + total)
- Memory usage (used, free, cached)
- Disk usage (all partitions)
- Network traffic (ingress/egress)
- System load (1m, 5m, 15m)
Container Dashboard:
- Container count (running, stopped)
- CPU per container
- Memory per container
- Network per container
- Restart count
Application Dashboard (per service):
- Request rate (req/s)
- Response time (p50, p95, p99)
- Error rate (4xx, 5xx)
- Active connections
Import vs Build
Import pre-built dashboards for:
- System metrics (Node Exporter Full - ID 1860)
- Container metrics (cAdvisor - ID 893)
- Standard services (Nginx, MySQL, etc.)
Build custom dashboards for:
- Application-specific metrics
- Business KPIs (e.g., “Media Server Usage”)
- Combined overview pages
Which Stack to Choose
Decision Flowchart
START: Need monitoring for homelab
↓
How many services?
├─ 1-5 services → **UPTIME KUMA**
│ Simple uptime checks sufficient
│
├─ 6-20 services → Do you need detailed metrics?
│ ├─ YES → **PROMETHEUS + GRAFANA**
│ │ Full metrics, dashboards, alerts
│ └─ NO → **UPTIME KUMA**
│ Start simple, upgrade later
│
└─ 20+ services OR microservices → **LGTM STACK**
Need logs + metrics + traces Recommendations by Scenario
Personal Homelab (3-10 services):
- Start: Uptime Kuma (5-minute setup)
- Upgrade to: Prometheus + Grafana (when you want detailed metrics)
- Skip: LGTM (overkill)
Production-like Homelab (10-30 services):
- Start: Prometheus + Grafana
- Add: Loki for logs (if debugging often)
- Consider: Full LGTM (if learning enterprise tools)
Learning/Career Development:
- Deploy: LGTM Stack
- Why: Industry-standard observability stack
- Benefit: Resume-worthy skills
Conclusion
The 2025 Monitoring Landscape:
| Stack | Best For | Key Strength | Resources |
|---|---|---|---|
| Uptime Kuma | Simple monitoring | Beautiful UI, 5-min setup | ~100MB RAM |
| Prometheus + Grafana | Detailed metrics | Industry standard, rich ecosystem | ~800MB RAM |
| LGTM | Full observability | Logs + metrics + traces | ~2GB RAM |
Our Recommendations:
For 90% of homelabbers: Start with Uptime Kuma
- Deploy in 5 minutes
- Get instant uptime visibility
- Beautiful status pages
- Minimal resource usage
- Upgrade later if needed
For serious homelabbers: Prometheus + Grafana
- Learn industry-standard tools
- Get detailed system metrics
- Build custom dashboards
- Transferable DevOps/SRE skills
- Worth the 2-hour setup investment
For advanced users / career development: LGTM Stack
- Enterprise-grade observability
- Correlate logs, metrics, traces
- Production debugging capabilities
- Resume-worthy experience
- 3-4 hour initial investment
Practical Progression:
- Week 1: Deploy Uptime Kuma (5 min) - get basic uptime visibility
- Month 1: Add Prometheus + Grafana (2 hrs) - when you need metrics
- Month 3+: Add Loki for logs (1 hr) - when debugging complex issues
- Month 6+: Add Tempo for traces (optional) - for microservices only
Remember: Start simple. You can always upgrade. Don’t over-engineer.
The best monitoring stack is the one you actually use and maintain.
Additional Resources
Official Documentation:
Pre-built Dashboards:
- Grafana Dashboard Library
- Node Exporter Full (ID 1860)
- Docker + System Monitoring (ID 893)
Learning Resources:
Related Guides:
- Alerting Best Practices (homelabbing.io)
- High Availability Monitoring (homelabbing.io)
- Incident Response Runbooks (homelabbing.io)
Questions? Join the discussion or visit our community Discord.
Deploy monitoring today. Know when things break before your users do.
Now go build that observability stack. Your future self (debugging at 2 AM) will thank you.