
Understanding the Core Advantage of Self-Hosted Monitoring
Self-hosting UptimeKuma places the entirety of your monitoring infrastructure under your direct authority. Unlike third-party services that impose usage caps, data retention limits, and subscription fees, a self-hosted instance ensures no external party has visibility into your uptime data, server IPs, or failure patterns. UptimeKuma is an open-source, Docker-based monitoring tool that tracks HTTP, TCP, ICMP, DNS, and numerous other protocols while offering a polished, real-time dashboard. By hosting it yourself, you eliminate recurring costs, control data sovereignty, and gain the ability to customize every monitoring parameter.
Prerequisites for a Production-Ready Deployment
Before deploying UptimeKuma, verify you have a Linux server with a static public or private IP address. A minimum of 1GB RAM and 10GB disk space is adequate for monitoring up to 100 endpoints, though scaling higher requires proportional resources. Install Docker and Docker Compose using your distribution’s package manager. For example, on Ubuntu 22.04, run sudo apt update && sudo apt install docker.io docker-compose-v2. Ensure the Docker daemon is active with sudo systemctl enable --now docker. A registered domain name (e.g., monitor.yourdomain.com) and a reverse proxy like Nginx or Caddy are strongly recommended for secure HTTPS access and proper WebSocket support.
Step-by-Step UptimeKuma Installation via Docker Compose
Create a dedicated directory for UptimeKuma and its persistent data: mkdir -p ~/uptime-kuma && cd ~/uptime-kuma. Inside this directory, create a docker-compose.yml file with the following content:
version: '3.8'
services:
uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptimekuma
ports:
- "3001:3001"
volumes:
- ./data:/app/data
restart: unless-stopped
environment:
- NODE_ENV=production
- UPTIME_KUMA_PROXY=false
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
Save the file, then deploy the container with sudo docker compose up -d. Verify the container is running with sudo docker compose ps. Access the application at http://your-server-ip:3001 to confirm the initial setup page loads. The ./data volume mounts UptimeKuma’s SQLite database, configuration, and notification states, ensuring persistence across container restarts and updates.
Configuring a Reverse Proxy with HTTPS and WebSocket Support
Direct HTTP access to port 3001 is insecure and blocks WebSocket connections needed for real-time updates. Configure a reverse proxy using Nginx. Install Nginx: sudo apt install nginx. Create a new site configuration: sudo nano /etc/nginx/sites-available/uptime-kuma. Insert the following block, replacing your-domain.com with your actual domain and adjusting the proxy_pass if UptimeKuma runs on a different host:
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/private.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
Enable the site: sudo ln -s /etc/nginx/sites-available/uptime-kuma /etc/nginx/sites-enabled/. Obtain an SSL certificate using Certbot: sudo apt install certbot python3-certbot-nginx && sudo certbot --nginx -d your-domain.com. Restart Nginx: sudo systemctl restart nginx. Your UptimeKuma instance is now accessible over HTTPS with full WebSocket support.
Advanced Monitoring Strategies and Protocol Configuration
UptimeKuma supports over a dozen monitor types beyond basic HTTP. For HTTP(S) monitors, configure keyword checks, status code expectations, and TLS certificate expiration alerts. Set a “Keyword” monitor to search for specific strings in the response body—useful for verifying that a login page renders correctly or a payment gateway returns a success flag. For TCP port monitors, define the port and expected response bytes. ICMP ping monitors are ideal for network latency tracking. DNS monitors can query specific record types (A, AAAA, MX, CNAME) and validate correct resolution. Multi-step monitors (HTTP with POST data, authentication headers, and JSON path extraction) enable complex API health verification.
Each monitor accepts a custom interval from 20 seconds to 24 hours. For critical services, set 60-second intervals with 3 retries and a 5-second timeout. Use the “Tags” feature to group monitors by environment (production, staging, development), region, or team responsibility. Tags enable filtered dashboard views and streamlined notification routing.
Notification Channels: A Deep Dive into Configuring Alerts
UptimeKuma offers 90+ notification providers, from email (SMTP) and Slack to Telegram, Discord, Gotify, and Pushover. To configure email alerts, navigate to Settings > Notifications > Add Notification. Select “SMTP Mail”, enter your SMTP server credentials (e.g., Gmail App Password or SendGrid API key), and define the sender email. For Telegram, create a bot via BotFather, obtain the bot token, and find your chat ID. UptimeKuma supports advanced notification templates using LiquidJS syntax. For instance, preconfigure multiple notification groups: a “Critical” group alerted via phone push (Gotify) and SMS (Twilio), a “Warning” group via Slack, and a “Info” group via email digest. Each monitor can be assigned to one or multiple notification groups, ensuring the right stakeholders receive appropriate severity alerts.
Webhook notifications allow integration with incident management platforms like PagerDuty or custom automation. The webhook payload includes monitor ID, status, and timestamps. Use the “Test Notification” button after configuration to verify delivery.
User Management and Multi-Tenant Access Control
For teams, create multiple users with granular permissions. From Settings > Users, add users with roles: “Administrator” (full access), “Viewer” (read-only dashboard), or “Manager” (can add/edit monitors but not change settings). Assign specific monitors or tag groups to each user via the “Access Control” tab. This is essential for agencies monitoring client servers—create a “Client A” tag group, restrict that user to only seeing monitors with that tag, and prevent them from viewing other clients’ data. Enable two-factor authentication (2FA) for all administrative accounts under User Settings > Security. UptimeKuma stores 2FA secrets encrypted in its SQLite database.
Performance Tuning and Resource Monitoring for the Host
Running extensive monitoring can strain the host server. Limit Docker container resource usage by editing the docker-compose.yml to include:
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
Monitor the host’s CPU and RAM with docker stats uptimekuma. For large deployments (500+ monitors), switch the database backend from SQLite to PostgreSQL for better concurrency. To migrate, use UptimeKuma’s built-in backup feature, then configure a PostgreSQL container in docker-compose.yml and update the DB_TYPE, DB_HOST, DB_USER, and DB_PASSWORD environment variables. Enable health checks on the UptimeKuma container by adding:
healthcheck:
test: ["CMD", "node", "e2e/health-check.js"]
interval: 30s
timeout: 10s
retries: 3
Backup, Restore, and Disaster Recovery Procedures
UptimeKuma’s data resides entirely in the mounted ./data directory. For automated backups, create a cron job that compresses and syncs this directory to offsite storage. As root, edit the crontab: sudo crontab -e. Add:
0 3 * * * tar -czf /backups/uptime-kuma-$(date +%F).tar.gz /home/user/uptime-kuma/data && rclone copy /backups/uptime-kuma-*.tar.gz remote:bucket/backups/
Test restoration by stopping the container (docker compose down), replacing ./data with a backup, then restarting (docker compose up -d). Document the exact steps in a runbook, including how to regenerate SSL certificates and reinitialize notifications after a full server rebuild. Perform a restore drill quarterly.
Security Hardening for the Monitoring Server
Expose only the reverse proxy port (443) to the public internet. Configure a firewall with ufw or iptables to block all inbound ports except 443 (and 22 for SSH). For the UptimeKuma container, disable the built-in autoSSL feature since Nginx handles TLS. Set UPTIME_KUMA_PROXY=false in environment variables to prevent redirect loops. Use Docker’s built-in user namespace remapping to run the container as a non-root user. Enable fail2ban to rate-limit failed login attempts. Regularly update the Docker image: docker compose pull && docker compose up -d. Subscribe to UptimeKuma’s GitHub releases or use Watchtower for automated updates.
Integrating with External Monitoring Tools
UptimeKuma can act as a data source for Grafana dashboards via Prometheus metrics. Enable the Prometheus exporter in Settings > General > Prometheus. Install Prometheus on a separate machine, targeting https://your-monitor-domain.com/api/push. Import the pre-built UptimeKuma Grafana dashboard (ID 15218) to visualize uptime percentages, response times, and certificate expiry trends. For alert aggregation, configure a webhook notification to send alerts to a central alertmanager or Slack channel. Integrate with Home Assistant via RESTful sensors to show monitor status on a smart home dashboard.
Scaling to Hundreds of Monitors Without Performance Degradation
As your monitor count grows, optimize polling. Increase the CHECK_INTERVAL for non-critical monitors to reduce load. Use the “Group by” feature on the dashboard to collapse monitors into logical categories, improving UI performance. For distributed monitoring, run multiple UptimeKuma instances in different geographic regions and use a central instance to proxy check results to a single dashboard via the “Status Page” feature. Consider SQLite’s performance ceiling at roughly 1,000 concurrent monitors; beyond that, migrate to PostgreSQL. Enable compression on Nginx with gzip on; to reduce bandwidth for dashboard updates.
Custom Status Pages for Client and Public Consumption
UptimeKuma can generate public status pages without exposing the admin interface. Navigate to Settings > Status Page > Add Status Page. Configure the page title, description, and select which monitor tags (e.g., “Public”, “Client-A” ) to display. Customize the theme color, add your company logo, and set a custom subdomain (e.g., status.yourcompany.com). The status page updates in real-time via WebSocket and can display historical uptime graphs. For clients, generate a dedicated status page URL, allowing them to check their services without seeing other clients’ data.
Troubleshooting Common Self-Hosted Issues
If WebSocket connections fail, verify the Nginx proxy_set_header Upgrade and Connection directives are present and that no additional firewalls block port 443. If the dashboard loads blank, clear browser cache or test with a private window. For database corruption, stop the container and run sqlite3 /path/to/data/kuma.db "PRAGMA integrity_check;". If errors appear, restore from backup. If monitors show consistent false positives, adjust the “Retry” count from 0 to 2 and increase timeout values. For SSL certificate alerts, ensure the monitor’s URL matches the certificate exactly—use https:// and include the port if non-standard. Debug container logs with docker logs uptimekuma --tail 50 -f.