A useful self-hosted monitoring stack should answer two different questions: are services reachable, and are the host and containers becoming unhealthy? This guide shows how to combine Uptime Kuma for availability checks with Prometheus and Grafana for metrics, then turn the data into a recurring maintenance routine for services, containers, certificates, storage, and capacity.
Overview
Uptime Kuma, Prometheus, and Grafana solve related but different monitoring problems. Uptime Kuma is best for simple status checks: an HTTP endpoint responds, a TCP port accepts connections, a DNS record resolves, or a scheduled heartbeat arrives. It gives you a practical view of whether users can reach a service.
Prometheus collects time-series metrics. With the right exporters, it can record CPU usage, memory pressure, disk capacity, network traffic, container resource consumption, and application-specific measurements. Grafana turns those metrics into dashboards and alerts that help explain why a service is slow or unavailable.
Using both layers is more useful than treating either as a complete observability system. An uptime check can tell you that a reverse proxy is returning errors, while Prometheus may show that the host ran out of memory or that a container restarted repeatedly. Conversely, a server can report healthy CPU and memory levels while an application endpoint is returning an error. Availability checks and metrics should therefore be designed together.
This approach works on a home server, a homelab, or a VPS for self-hosting. It also fits a Docker Compose workflow, provided the monitoring services are given access only to the data and endpoints they actually need. Before exposing any dashboard, review your access controls and server firewall. The self-hosted server hardening checklist is a useful companion for that work.
What to track
Service availability
Start with the services that matter to you rather than monitoring every container immediately. In Uptime Kuma, create checks for public web applications, internal dashboards, authentication services, APIs, and important network endpoints. HTTP checks should target a meaningful health or landing page where possible. A port check only confirms that something is listening; it does not confirm that the application is functioning.
For a service behind a reverse proxy, monitor the actual hostname and scheme used by clients. This can reveal certificate, routing, and application errors that a direct container-port check would miss. If your stack uses Nginx Proxy Manager, Traefik, or Caddy, monitor both the public route and, where practical, an internal endpoint. The public check tests the user path; the internal check helps separate proxy failures from application failures. See the comparison of reverse proxy options for self-hosting if you are still choosing that layer.
Certificates and scheduled jobs
Track TLS certificate expiration with an appropriate Uptime Kuma certificate monitor or an equivalent check. An expiry warning is most useful when it arrives early enough to investigate renewal, DNS, firewall, or proxy problems. Also monitor scheduled jobs that do not expose an HTTP endpoint, such as backups, imports, synchronization tasks, and certificate renewals. A heartbeat monitor can mark a job as failed when it does not report completion within its expected window.
Host and container resources
Prometheus needs exporters or application endpoints that expose metrics. A common Docker-based arrangement includes:
- Prometheus: scrapes and stores time-series metrics.
- Grafana: provides dashboards and alert views.
- Node Exporter: exposes host-level metrics such as CPU, memory, filesystem, and network data.
- cAdvisor or an equivalent container metrics source: exposes container-level resource usage.
Track filesystem capacity separately from filesystem health. A full disk is often more immediately damaging than high CPU usage because databases, logs, and Docker layers may be unable to write. Watch the filesystem containing Docker data, the filesystem containing application volumes, and any location used for backups. If they are separate, give them separate alerts.
For containers, watch restart counts, exit states, memory usage, CPU usage, and network traffic. A restart is not automatically a failure: some containers restart during planned deployments. A pattern of repeated restarts, however, deserves investigation. Container metrics should complement, not replace, application logs and Docker health checks.
Prometheus and Grafana themselves
Monitor the monitoring stack. Check whether Prometheus is running, whether targets are being scraped successfully, and whether its storage is writable. In Grafana, verify that dashboards can reach Prometheus and that alert notifications are being delivered. An alerting system that silently stops collecting data creates false confidence.
A practical Docker Compose pattern
The exact image versions, paths, and network names should be selected for your environment and maintained deliberately. A simplified Compose structure might look like this:
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
ports:
- 9090:9090
grafana:
image: grafana/grafana
volumes:
- grafana_data:/var/lib/grafana
ports:
- 3000:3000
uptime-kuma:
image: louislam/uptime-kuma
volumes:
- uptime_kuma_data:/app/data
ports:
- 3001:3001
volumes:
prometheus_data:
grafana_data:
uptime_kuma_data:This is a starting layout, not a production-ready security policy. Pin image versions according to your update process, avoid exposing administrative ports directly to the internet, and place dashboards behind authentication or a private network. Configure Prometheus targets in a separate file and validate that the monitoring containers can resolve the service names they need to scrape. For broader deployment patterns, see the Docker deployment guide for self-hosting on a VPS.
Cadence and checkpoints
Monitoring becomes more valuable when it is reviewed on a schedule instead of only during an outage. Use the following routine as a starting point.
Daily or on each alert
- Confirm whether an alert is a genuine outage, a planned change, or a noisy check.
- Check the affected service path from the client perspective.
- Review recent container restarts and relevant logs.
- Record the cause and corrective action when an incident is not self-explanatory.
Weekly
- Review Uptime Kuma history for repeated short outages and slow responses.
- Look at Prometheus and Grafana panels for memory pressure, disk growth, CPU saturation, and unusual network activity.
- Check failed scrape targets and confirm that expected containers are still being monitored.
- Verify that backup jobs and their heartbeat checks completed successfully.
Monthly
- Review alert thresholds and silence rules. Remove alerts for retired services.
- Check certificate expiration dates and renewal logs.
- Compare storage usage with the previous month and estimate when capacity may become a constraint.
- Confirm that Grafana, Prometheus, Uptime Kuma, exporters, and related images are included in your update plan.
- Test access to monitoring dashboards from the administration path you would use during an incident.
Quarterly
- Run a restore test for monitoring data and verify that dashboards or configuration can be recreated.
- Review who can access monitoring data, especially when hostnames, internal addresses, or service labels reveal private infrastructure.
- Revisit retention and storage settings. Retain enough history to identify trends without allowing metrics to consume the application disk.
- Simulate a simple failure, such as stopping a test container, and confirm that the expected notification arrives.
Monitoring data is not a substitute for backups. Preserve the configuration, Compose files, dashboard definitions, and alert rules in a backed-up location. Apply the same restore discipline to monitoring as to other self-hosted apps; the Docker backup strategy guide covers volumes, databases, and restore testing.
How to interpret changes
A dashboard is useful only when a change leads to a decision. Start by separating symptoms from causes. A rising response time may result from application work, database latency, a saturated disk, or a reverse proxy issue. Compare the time range around the event and look for correlated changes in CPU, memory, filesystem, network, and container restarts.
Thresholds should be treated as starting points rather than universal rules. For example, a filesystem alert might warn when available space falls below a defined percentage and also when the rate of consumption suggests that the disk will fill soon. A CPU alert is more meaningful when sustained over a period than when triggered by a short deployment spike. Memory alerts should consider swap activity, out-of-memory events, and container restarts rather than relying on a single percentage.
For a small self-hosted environment, useful initial questions include:
- Is the service unavailable, or only slow?
- Did the issue affect one container, one host, or several services?
- Did a deployment, backup, certificate renewal, or scheduled job occur at the same time?
- Is the pattern recurring at a predictable hour?
- Is storage growth caused by application data, logs, database files, images, or backups?
False alerts are usually a design problem, not a reason to disable monitoring. Increase a delay, adjust a threshold, monitor a better endpoint, or add maintenance windows. Keep alerts actionable: a notification should identify the service, the condition, the affected host, and a useful link to the relevant dashboard or log view.
When to revisit
Revisit this monitoring stack whenever the environment changes, not only when an incident occurs. Adding a new public application should trigger an availability check, a certificate check where relevant, and an assessment of its resource profile. Moving workloads between a home server and a VPS may require new network reachability checks, exporters, firewall rules, or notification paths.
Use a monthly review to remove stale monitors and confirm that current alerts still match the services you operate. Use a quarterly review to assess capacity trends, retention, access permissions, backup recovery, and notification delivery. Revisit immediately after a serious outage: the missing signal may be more important than the failed service itself.
To put the guide into practice, begin with three monitors for your most important services, one host dashboard, and alerts for disk capacity, failed scrapes, certificate expiry, and repeated container restarts. Run a controlled test, document what each alert means, and record the next review date. As the stack grows, add checks because they reduce uncertainty—not simply because another metric is available. That discipline keeps a self-hosted monitoring stack useful, maintainable, and aligned with the Docker and infrastructure you actually run.