Skip to main content

Open-source alternatives guide

How to Self-Host Uptime Kuma: Website Monitoring 2026

Self-host Uptime Kuma for website and API monitoring in 2026, with Docker, HTTPS, alerts, status pages, backups, security hardening, and updates.

·OSSAlt Team
Share:
Hero image for How to Self-Host Uptime Kuma: Website Monitoring 2026

TL;DR

Uptime Kuma is an MIT-licensed, self-hosted uptime monitoring tool with a polished real-time dashboard. It monitors websites, APIs, TCP ports, DNS records, Docker containers, databases, and scheduled jobs. You can run frequent checks, route alerts to the channels your team already uses, and publish customizable status pages without paying per monitor.

Key Takeaways

  • Uptime Kuma: MIT-licensed, Node.js-based uptime monitoring with a focused UI
  • Monitor types: HTTP/HTTPS, TCP port, Ping, DNS, Docker container, Push (for cron jobs)
  • Status pages: Public status pages — share uptime with customers or team
  • Alerts: 90+ notification services (Slack, Discord, Telegram, PagerDuty, ntfy, email)
  • Intervals: 20-second intervals
  • Certificates: TLS certificate expiry monitoring with alerts

Part 1: Docker Setup

# docker-compose.yml
services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    container_name: uptime-kuma
    restart: unless-stopped
    ports:
      - "127.0.0.1:3001:3001"
    volumes:
      - uptime_kuma_data:/app/data
      # Optional: grants broad visibility into the Docker host.
      # Add only when Docker container-state monitoring is required:
      # - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      TZ: America/Los_Angeles

volumes:
  uptime_kuma_data:
docker compose up -d

Visit http://your-server:3001 → create admin account.

Binding port 3001 to 127.0.0.1 keeps the admin service off the public network. If you enable Docker container monitoring, treat the socket mount as privileged access: mounting the socket :ro does not make Docker API operations read-only. Prefer endpoint health checks unless container-state monitoring is essential.


Part 2: HTTPS with Caddy

status.yourdomain.com {
    reverse_proxy localhost:3001
}

Caddy forwards Uptime Kuma's WebSocket traffic automatically. After applying the configuration, validate and reload it, then confirm that the dashboard and status page continue updating without browser reconnect errors:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://status.yourdomain.com

Part 3: Monitor Types

HTTP/HTTPS (websites and APIs)

  1. + Add New Monitor
  2. Monitor Type: HTTP(S)
  3. URL: https://yourdomain.com
  4. Heartbeat interval: 60 seconds
  5. Retries: 3
  6. Save

Advanced options:

  • Expected HTTP status: 200 (alert if not 200)
  • Expected keyword: "Welcome" (alert if keyword missing — useful for detecting fake 200s)
  • Certificate expiry notification: Alert 30 days before cert expires
  • Authentication: Basic auth or bearer token

TCP port monitoring

Monitor SSH, databases, mail servers:

Monitor Type: TCP Port
Hostname: your-server.com
Port: 22      ← SSH
Port: 5432    ← PostgreSQL
Port: 3306    ← MySQL
Port: 25      ← SMTP

Use native PostgreSQL, MySQL/MariaDB, or Redis monitors when you need an authenticated application-level check rather than a simple open-port test. Store dedicated least-privilege monitoring credentials and never reuse an application owner account.

Docker container monitoring

Checks if a Docker container is running:

Monitor Type: Docker Container
Container Name: nginx
Docker Host: /var/run/docker.sock (local)

DNS monitoring

Check that DNS resolves correctly:

Monitor Type: DNS
Hostname: yourdomain.com
Record Type: A
Resolver: 1.1.1.1

Expected value: YOUR.SERVER.IP

Push monitoring (heartbeats for cron jobs)

For scheduled tasks — Uptime Kuma alerts if the job doesn't check in:

Monitor Type: Push
Generate a Push URL → copy the URL

# In your cron job, ping the URL on success:
0 2 * * * /opt/scripts/backup.sh && \
  curl -s "https://status.yourdomain.com/api/push/UNIQUE_TOKEN?status=up&msg=OK"

Other built-in monitor types

Use a purpose-built monitor when it proves more than a port being open. Uptime Kuma also supports HTTP keyword and JSON-query checks, WebSocket checks, database checks, MQTT, gRPC, Steam/game servers, and other service-specific monitors. For an API, prefer a health endpoint plus an expected keyword or JSON value; for a database, use a dedicated least-privilege monitoring account.


Part 4: Notifications

Slack

  1. Settings → Notification → Add notification
  2. Type: Slack
  3. Webhook URL: https://hooks.slack.com/services/...
  4. Channel: #alerts
  5. Test → save

Telegram

Type: Telegram
Bot Token: 1234567890:AAHdqTcvCH1vGWJxfSeofSs0K7MDk (from @BotFather)
Chat ID: -1001234567890 (your channel/group ID)

ntfy (self-hosted push)

Type: ntfy
Server URL: https://ntfy.yourdomain.com
Topic: uptime-alerts
Priority: High

PagerDuty (for production)

Type: PagerDuty
Integration Key: your-pagerduty-routing-key

Test every notification channel before assigning it. Route only critical customer-facing monitors to PagerDuty; send lower-priority checks to Slack, email, Telegram, or ntfy to avoid paging fatigue. Creating a notification does not apply it globally, so verify the intended channel is assigned on each monitor.

Email (SMTP)

Type: Email (SMTP)
Host: mail.yourdomain.com
Port: 587
Security: TLS
Username: alerts@yourdomain.com
Password: your-email-password
From: alerts@yourdomain.com
To: you@yourdomain.com

Generic webhook

Choose the Webhook notification type to send Uptime Kuma events to n8n or another incident workflow. Use an HTTPS endpoint that accepts only the expected method and payload, keep any authentication secret out of the monitor name or message, and use Uptime Kuma's Test action before assigning the webhook to production monitors.


Part 5: Maintenance Windows

Create a maintenance window before planned work so expected downtime does not create noisy incident alerts:

  1. Maintenance → Add Maintenance
  2. Name the change and choose a one-time or recurring schedule
  3. Select only the affected monitors
  4. Confirm the window's time zone and start/end times

After the work, verify the monitors recover and notifications resume. Maintenance windows should suppress expected alerts, not replace a post-change health check.


Part 6: Status Pages

Create a public status page for customers or team:

  1. Status Pages → + New Status Page
  2. Slug: status (page at /status/status on the Kuma host; a custom domain can map it to /)
  3. Title: YourProduct Status
  4. Description: Real-time uptime and incident status

Add monitors to page

  1. Status Page → Edit → + Add group
  2. Group name: Core Services
  3. Add monitors: website, API, database

Custom domain

status.yourproduct.com {
    reverse_proxy localhost:3001
}

In Uptime Kuma → Status Pages → [page] → Custom Domain: status.yourproduct.com

Incident reporting

  1. Status Page → + Create incident
  2. Title: API degraded performance
  3. Content: We are investigating elevated error rates in the API.
  4. Status: Investigating → Identified → Monitoring → Resolved

Part 7: Monitor Groups and Tags

Organize many monitors:

Groups:
├── Production
│   ├── Website (https://yourdomain.com)
│   ├── API (https://api.yourdomain.com/health)
│   └── Database port (TCP 5432)
├── Development
│   ├── Staging (https://staging.yourdomain.com)
│   └── Dev API
└── Infrastructure
    ├── VPS SSH (TCP 22)
    └── Mail server (TCP 25)

Tags for filtering: production, critical, customer-facing

Failure-Domain Planning

A self-hosted Uptime Kuma instance checks services from the network where it runs. If the Kuma host, its internet connection, and the monitored service fail together, it may be unable to send the alert. For critical public endpoints, run Kuma on separate infrastructure or pair it with a small external check. A single Kuma instance is not a substitute for multi-region synthetic monitoring.


Part 8: Prometheus Metrics Integration

Uptime Kuma exposes Prometheus-format metrics at /metrics. Protect the endpoint with the metrics credentials configured in Uptime Kuma, then add it as a scrape target when you need longer-term response-time charts or Grafana dashboards alongside Kuma's incident view.

scrape_configs:
  - job_name: "uptime_kuma"
    metrics_path: /metrics
    basic_auth:
      username: "uptime-kuma-metrics"
      password_file: /run/secrets/uptime_kuma_metrics_password
    static_configs:
      - targets: ["status.yourdomain.com"]

Keep this integration focused on Uptime Kuma metrics. Designing a full Uptime Kuma, Prometheus, Grafana, and Loki architecture is a separate job from this setup guide.


Maintenance

# Review release notes and back up before updating:
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 uptime-kuma

# For a consistent simple backup, stop writes before copying /app/data:
docker compose stop uptime-kuma
DATA_VOLUME="$(docker inspect uptime-kuma \
  --format '{{range .Mounts}}{{if eq .Destination "/app/data"}}{{.Name}}{{end}}{{end}}')"
test -n "$DATA_VOLUME"
mkdir -p backups
docker run --rm \
  -v "$DATA_VOLUME:/source:ro" \
  -v "$PWD/backups:/backup" \
  alpine tar -czf "/backup/uptime-kuma-$(date +%Y%m%d).tar.gz" -C /source .
docker compose start uptime-kuma

# Logs:
docker compose logs -f uptime-kuma

Keep the Compose file, reverse-proxy configuration, and encrypted credentials backup with the data archive. At least monthly, restore an archive into a separate named volume and temporary Compose project, start it on a different localhost port, and verify that monitors, notifications, and status pages load. A backup is not complete until that restore test succeeds.

Why Self-Host Uptime Kuma?

The case for self-hosting Uptime Kuma comes down to three practical factors: data ownership, cost at scale, and operational control.

Data ownership is the fundamental argument. When you use a SaaS version of any tool, your data lives on someone else's infrastructure subject to their terms of service, their security practices, and their business continuity. If the vendor raises prices, gets acquired, changes API limits, or shuts down, you're left scrambling. Self-hosting Uptime Kuma means your data and configuration stay on infrastructure you control — whether that's a VPS, a bare metal server, or a home lab.

Cost control improves when monitor count would otherwise push a hosted service into a paid tier. Uptime Kuma does not charge per monitor, but self-hosting still has infrastructure, backup, update, and operator-time costs. Compare that full operating cost with the current hosted plans you would actually use.

Operational control is the third factor. The Docker Compose configuration gives you direct control over networking, persistent storage, update timing, backups, and access policy.

The honest tradeoff: you're responsible for updates, backups, and availability. For teams running any production workloads, this is familiar territory. For individuals, the learning curve is real but the tooling (Docker, Caddy, automated backups) is well-documented and widely supported.

Server Requirements and Sizing

Before deploying Uptime Kuma, assess capacity with the real monitor count, check intervals, and history retention you plan to use. Start with a small current Linux host, then measure docker stats uptime-kuma, volume growth, and reverse-proxy latency after importing the monitor set. Leave enough memory and disk headroom for updates and database maintenance rather than relying on a universal monitors-to-RAM formula.

Storage planning: The /app/data volume contains Uptime Kuma's persistent application state. Keep it on supported local storage rather than NFS, monitor its growth, and make sure the host or attached volume can be expanded before disk pressure becomes an incident.

Operating system: Use a currently supported 64-bit Linux distribution with Docker Engine and the Docker Compose plugin. Verify the installed versions with docker --version and docker compose version, and follow the Uptime Kuma release notes for current image and platform requirements.

Network: Bind Uptime Kuma's internal port to localhost and publish the application through the reverse proxy. Public web traffic normally needs only HTTP/HTTPS; restrict SSH separately to trusted administration paths, and do not expose databases or other internal service ports to the internet.

Backup and Disaster Recovery

Running Uptime Kuma without a tested backup strategy is an unacceptable availability risk. Docker volumes are not automatically backed up — if you delete a volume or the host fails, data is gone with no recovery path.

What to back up: The named Docker volume containing Uptime Kuma's database and application state, your Compose and reverse-proxy configuration, and any separate secret files used by the deployment.

Backup approach: For the default Compose setup in this guide, stop the container, archive /app/data, then restart. If you deliberately use another supported datastore or snapshot system, follow its consistency procedure rather than copying live database files.

For a complete automated backup workflow that ships snapshots to S3-compatible object storage, see the Restic + Rclone backup guide. Restic handles deduplication and encryption; Rclone handles multi-destination uploads. The same setup works for any Docker volume.

Backup cadence: Daily backups to remote storage are a reasonable baseline for actively used tools. Use a 30-day retention window minimum — long enough to recover from mistakes discovered weeks later. For critical data, extend to 90 days and use a secondary destination.

Restore testing: A backup that has never been restored is a backup you cannot trust. Once a month, restore your Uptime Kuma backup to a separate Docker Compose stack on different ports and verify the data is intact. This catches silent backup failures, script errors, and volume permission issues before they matter in a real recovery.

Security Hardening

Self-hosting means you are responsible for Uptime Kuma's security posture. The Docker Compose setup provides a functional base; production deployments need additional hardening.

Always use a reverse proxy: Never expose Uptime Kuma's internal port directly to the internet. The docker-compose.yml binds to localhost; Caddy or Nginx provides HTTPS termination. Direct HTTP access transmits credentials in plaintext. A reverse proxy also centralizes TLS, access policy, and request logging.

Strong credentials: Change default passwords immediately after first login. For secrets in docker-compose environment variables, generate random values with openssl rand -base64 32 rather than reusing existing passwords.

Protect the admin surface: Enable two-factor authentication in Uptime Kuma's security settings. Keep the dashboard private behind a VPN, identity-aware proxy, or IP allowlist when practical; publish only the status pages that customers need. The dashboard reveals monitored hostnames, incident history, and any credentials configured for authenticated checks.

Minimize Docker socket access: Do not mount /var/run/docker.sock only for convenience. The socket exposes powerful host-level Docker operations even when mounted read-only. Prefer HTTP, TCP, and push monitors, or place a restricted socket proxy between Uptime Kuma and the Docker API.

Firewall configuration:

ufw default deny incoming
ufw allow from YOUR.ADMIN.IP to any port 22 proto tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Internal service ports (databases, admin panels, internal APIs) should only be reachable from localhost or the Docker network, never directly from the internet.

Network isolation: Docker Compose named networks keep Uptime Kuma's services isolated from other containers on the same host. Database containers should not share networks with containers that don't need direct database access.

VPN access for sensitive services: For internal-only tools, restricting access to a VPN adds a strong second layer. Headscale is an open source Tailscale control server that puts your self-hosted stack behind a WireGuard mesh, eliminating public internet exposure for internal tools.

Update discipline: Watch Uptime Kuma's GitHub releases, review release notes before updating, and use a regular maintenance window so fixes do not accumulate unnoticed.

Troubleshooting Common Issues

Container exits immediately or won't start

Check logs first — they almost always explain the failure:

docker compose logs -f uptime-kuma

Common causes: a missing required environment variable, a port already in use, or a volume permission error. Port conflicts appear as bind: address already in use. Find the conflicting process with ss -tlpn | grep PORT and either stop it or change Uptime Kuma's port mapping in docker-compose.yml.

Cannot reach the web interface

Work through this checklist:

  1. Confirm the container is running: docker compose ps
  2. Test locally on the server: curl -I http://localhost:PORT
  3. If local access works but external doesn't, check your firewall: ufw status
  4. If using a reverse proxy, verify it's running and the config is valid: caddy validate --config /etc/caddy/Caddyfile

Permission errors on volume mounts

If a bind mount or restored archive has the wrong ownership, the container may be unable to write to /app/data. Inspect the container logs and the numeric ownership on the restored files, then apply the UID/GID required by the image and your host policy. Do not assume 1000:1000, and do not recursively change a Docker-managed volume until you have a backup.

High resource usage over time

Check current usage with docker stats uptime-kuma, review container logs, inspect /app/data growth, and compare the change with monitor count and interval changes. Add host-level alerts or carefully tested container limits so the monitoring service cannot exhaust a shared host. For ongoing resource trends, use Prometheus + Grafana or Netdata.

Data disappears after container restart

Data stored in the container's writable layer — rather than a named volume — is lost when the container is removed or recreated. This happens when the volume mount path in docker-compose.yml doesn't match where the application writes data. Verify mount paths against the tool's documentation and correct the mapping. Named volumes persist across container removal; only docker compose down -v deletes them.

A service is reachable from the host but down from Uptime Kuma

Check Docker networking before changing retries. Containers on separate custom networks cannot resolve each other's service names. Add Uptime Kuma to the monitored application's network or use a stable address reachable from the Kuma container, then test from inside the container.

Notification tests pass but outage alerts never arrive

A notification channel must be assigned to each intended monitor. Reopen the monitor, verify the channel is selected, and trigger a controlled failure. For push monitors, set the heartbeat grace interval slightly longer than the job schedule so normal runtime and clock drift do not cause false alerts.

Certificate expiry shows the wrong certificate

Uptime Kuma checks the certificate served to it over the network. If the domain sits behind a CDN or load balancer, that may be the edge certificate rather than the origin certificate. Test the same hostname from the Kuma host, confirm DNS resolution and SNI, and monitor the origin separately only when that certificate is independently reachable and operationally relevant.

Startup is slow after an update

Database migrations can extend startup time. Follow the logs instead of repeatedly restarting the container. If migrations fail, stop and restore the pre-update backup rather than deleting the data volume.

Keeping Uptime Kuma Updated

Review Uptime Kuma releases regularly so security and compatibility fixes do not accumulate. The update process with Docker Compose is straightforward:

docker compose pull          # Download updated images
docker compose up -d         # Restart with new images
docker image prune -f        # Remove old image layers (optional)

Read the changelog before major version updates. Some releases include database migrations or breaking configuration changes. For major version bumps, test in a staging environment first — run a copy of the service on different ports with the same volume data to validate the migration before touching production.

Version pinning: For stability, pin to a specific image tag in docker-compose.yml instead of latest. Update deliberately after reviewing the changelog. This trades automatic patch delivery for predictable behavior — the right call for business-critical services.

Post-update verification: Confirm the container is healthy, open the dashboard through the reverse proxy, check that recent heartbeats continue, send a test notification, and load every public status page. Keep an external check outside this Uptime Kuma host so a failed update can still alert you.


See also: Healthchecks — for monitoring cron jobs specifically

See all open source monitoring tools at OSSAlt.com/categories/devops.

See open source alternatives to Uptime Kuma on OSSAlt.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.