Monitoring and ObservabilityUptime and StatusIntermediate2-3 hoursLab

Create an Uptime Kuma and Grafana Homelab Monitor with Prometheus Metrics

Deploy Uptime Kuma v2 for endpoint checks and status pages, scrape its supported /metrics endpoint with Prometheus, and visualize response-time/status metrics in Grafana without...

Last reviewed8/19/2026
Grafana uptime dashboardsUptime Kuma status pagesPrometheus integration
Docker Compose v2Uptime Kuma v2PrometheusGrafana

Expected Outcome

A homelab monitoring stack in which Uptime Kuma owns checks and notifications, Prometheus collects supported metrics, and Grafana queries Prometheus for dashboards.

Assumptions

  • A Linux host with Docker Engine and Docker Compose v2.

  • At least one low-impact HTTP or TCP service you can monitor.

  • A reviewed Grafana and Prometheus image tag for the Lab.

  • A secure place to store the Uptime Kuma metrics API key.

Bill of Materials

  • Uptime Kuma v2 container image.

  • Prometheus container image.

  • Grafana container image.

  • One intentionally testable endpoint whose temporary outage will not affect users.

Build Steps

  1. Verify Compose v2 and create the stack directory

    Use the current Docker Compose plugin rather than the retired standalone docker-compose executable.

    Changes system state: review before running

    docker --version
    docker compose version
    mkdir -p ~/homelab-monitor/{prometheus,.secrets} && cd ~/homelab-monitor
  2. Start Uptime Kuma v2 first

    Run Uptime Kuma with local persistent storage. Uptime Kuma's documentation warns that NFS-backed /app/data is unsupported, so use a local Docker volume or local filesystem path.

    Changes system state: review before running

    cat > compose.yaml <<'EOF'
    services:
      uptime-kuma:
        image: louislam/uptime-kuma:2
        restart: unless-stopped
        ports:
          - "3001:3001"
        volumes:
          - uptime-kuma-data:/app/data
    volumes:
      uptime-kuma-data:
    EOF
    docker compose config --quiet
    docker compose up -d uptime-kuma
    docker compose ps
  3. Create the first monitor and notification path

    Open Uptime Kuma, create the administrator account, and add one low-impact HTTP or TCP monitor. Configure a notification method you can safely test. Uptime Kuma can send notifications and publish status pages, but it is not a general multi-stage incident-escalation engine; document any true escalation policy outside the tool if your workflow requires one.

  4. Create an API key for Prometheus metrics

    Uptime Kuma supports a Prometheus-format /metrics endpoint. Create an API key in Uptime Kuma settings, then store the key in a root-readable/local secret file. Uptime Kuma documents API-key authentication as the password side of HTTP Basic Auth with an unused username.

    Changes system state: review before running

    printf '%s' '<UPTIME_KUMA_API_KEY>' > .secrets/kuma-metrics-key
    chmod 600 .secrets/kuma-metrics-key
  5. Configure Prometheus to scrape Uptime Kuma

    Use the supported /metrics endpoint rather than querying Uptime Kuma's SQLite database. The documented metrics include monitor status and response time with labels such as monitor name/type/URL.

    Read-only command: verify target and scope

    cat > prometheus/prometheus.yml <<'EOF'
    global:
      scrape_interval: 30s
    scrape_configs:
      - job_name: uptime-kuma
        metrics_path: /metrics
        static_configs:
          - targets: ['uptime-kuma:3001']
        basic_auth:
          username: ''
          password_file: /run/secrets/kuma_metrics_key
    EOF
  6. Add Prometheus and Grafana to Compose

    Replace the image placeholders with reviewed tags. Prometheus reads the Uptime Kuma key through a Compose secret, while Grafana reads only Prometheus—not Uptime Kuma's internal data store.

    Read-only command: verify target and scope

    cat >> compose.yaml <<'EOF'
      prometheus:
        image: prom/prometheus:<reviewed-tag>
        restart: unless-stopped
        command: ['--config.file=/etc/prometheus/prometheus.yml']
        volumes:
          - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
        secrets:
          - kuma_metrics_key
        ports:
          - "127.0.0.1:9090:9090"
      grafana:
        image: grafana/grafana:<reviewed-tag>
        restart: unless-stopped
        volumes:
          - grafana-data:/var/lib/grafana
        ports:
          - "3000:3000"
        depends_on:
          - prometheus
    volumes:
      grafana-data:
    secrets:
      kuma_metrics_key:
        file: ./.secrets/kuma-metrics-key
    EOF
    docker compose config --quiet
  7. Start the metrics path and verify scraping

    Bring up Prometheus and Grafana, then verify Prometheus sees the Uptime Kuma target as healthy before building a Grafana dashboard.

    Changes system state: review before running

    docker compose up -d
    docker compose ps
    curl -fsS 'http://127.0.0.1:9090/api/v1/query?query=up%7Bjob%3D%22uptime-kuma%22%7D'
  8. Add Prometheus as the Grafana data source and build two panels

    In Grafana, add Prometheus at http://prometheus:9090. Create a status panel from monitor_status and a response-time panel from monitor_response_time, grouped by monitor_name. This makes the integration explicit and supportable.

  9. Create and validate a Uptime Kuma status page

    Publish a status page only for monitors whose names and availability you are comfortable exposing to the intended audience. A public status page can disclose internal service names or topology, so keep it internal unless external publication is intentional.

  10. Run a controlled outage test

    Temporarily stop or block only the disposable test endpoint. Confirm Uptime Kuma changes state and sends the configured notification, Prometheus reflects monitor_status, and Grafana displays the change. Restore the endpoint and confirm recovery is observed.

Validation

  • Uptime Kuma v2 is running with local persistent storage and at least one real monitor.

  • Prometheus successfully authenticates to Uptime Kuma's supported `/metrics` endpoint.

  • Grafana uses Prometheus as its data source rather than Uptime Kuma's internal database.

  • The dashboard displays `monitor_status` and `monitor_response_time` for the test monitor.

  • A controlled endpoint outage produces an Uptime Kuma state change/notification and a corresponding Prometheus/Grafana metric change.

  • Any status page exposes only information intentionally approved for its audience.

Troubleshooting

  • If Prometheus returns 401 from `/metrics`, verify the API key and Uptime Kuma's current metrics-authentication settings. Do not disable authentication merely to make scraping easy.

  • If Grafana has no data, query Prometheus directly for `up{job="uptime-kuma"}`, `monitor_status`, and `monitor_response_time` before changing Grafana panels.

  • If Uptime Kuma fails after moving its data to network storage, return `/app/data` to supported local storage; the project explicitly warns that NFS is unsupported.

Cleanup or Rollback

  • Restore the controlled test endpoint before ending the Lab.

  • Delete or revoke the Uptime Kuma API key if you remove Prometheus integration.

  • Stop the stack with `docker compose down`; preserve Uptime Kuma/Grafana volumes unless you have intentionally decided to destroy monitor history and dashboards.

Next Improvements

  • Add a second monitor type such as TCP or keyword checking to compare metrics behavior.

  • Put Uptime Kuma and Grafana behind an internal HTTPS reverse proxy before wider use.

  • Define actual escalation/on-call policy outside Uptime Kuma if the environment needs staged incident response.

References

Keep Moving

Build on what you just completed

Continue with a related Lab or return to this build path for a different implementation.