How to Install Uptime Kuma on Ubuntu 24.04 — Self-Hosted Uptime Monitoring
When a customer tells you your site is down before your monitoring does, you already lost the round. Uptime Kuma fixes that without the $50-200/month bill of a hosted monitoring service. This guide walks you through installing Uptime Kuma on an Ubuntu 24.04 VPS — from first SSH connection to a production-ready deployment with HTTP checks, Discord and Telegram alerts, and a public status page behind Nginx with TLS.
Prefer a hands-off setup? Deploy Uptime Kuma on a pre-tuned Starter VPS in minutes. Plenty of headroom for hundreds of monitors.
Table of Contents
What is Uptime Kuma?
Uptime Kuma is an open-source, self-hosted monitoring tool created by Louis Lam. It is a fast drop-in replacement for hosted services like Pingdom, BetterUptime (Better Stack), StatusCake, and UptimeRobot. The project has more than 60,000 GitHub stars, an active contributor community, and a release cadence measured in weeks.
At its core, Uptime Kuma runs periodic probes against things you care about — websites, APIs, databases, DNS records, TCP ports, Docker containers — and fires alerts through your chosen notification channels when a probe fails. It stores state in a single SQLite database (MariaDB is optional from 2.x), exposes a clean Vue-based web UI, and renders public or private status pages with historical uptime, incident annotations, and certificate expiry tracking.
The monitor catalogue is broad. HTTP(s) monitors verify status codes, response bodies, and TLS certificate validity. Keyword monitors fail when a response does or does not contain a given string — useful for detecting soft failures where the status code is 200 but the page shows an error message. TCP port monitors confirm raw socket availability for services like Postgres, Redis, SSH, and SMTP. Ping (ICMP) monitors verify network reachability. DNS monitors confirm a record resolves to the expected value from a chosen resolver. Push monitors invert the model — your service POSTs a heartbeat to Uptime Kuma on a schedule, and Kuma alerts if the heartbeat stops (ideal for cron jobs and background workers behind firewalls). Docker container monitors check that a named container is running on a connected Docker host. gRPC, MQTT, RADIUS, Steam game server, and JSON query monitors cover the long tail.
Why Self-Host Instead of Pingdom or BetterUptime?
Hosted uptime monitoring is convenient, but the economics stop making sense quickly once you have more than a handful of services or strict data-residency requirements.
- Cost at scale. Pingdom starts around $15/month for 10 monitors and climbs to $199/month for 100 monitors with minute-level checks. BetterUptime charges per monitor with similar economics. Uptime Kuma on a EUR 4.49/mo Starter VPS runs 200+ monitors at 20-second intervals for a single flat fee.
- Data ownership. Every check URL, hostname, status page, and incident note lives in SaaS databases you do not control. Self-hosted Kuma keeps all of it on infrastructure you own, which matters for internal URLs, customer identifiers embedded in paths, and GDPR posture.
- Probe location flexibility. Hosted services probe from their regions. Self-hosted Kuma probes from wherever you run it — including inside your VPN or private cloud, which is the only way to monitor truly internal services without exposing them publicly.
- No vendor rate limits or tier walls. Features like keyword matching, status pages, and API access are often gated behind higher tiers on SaaS products. Kuma ships every feature to every user.
- Extensibility. Kuma has more than 90 built-in notification integrations, a Prometheus metrics endpoint, and a REST API. Modifying behavior is one Docker rebuild away, not a feature-request ticket.
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- At least 2 GB of RAM (4 GB recommended once you pass a few dozen monitors)
- At least 10 GB of free disk space for Docker, Kuma, and several weeks of check history
- A domain name pointing to your VPS (optional, but required for TLS and a nice status page URL)
Recommended Plan: Starter>
For a typical install with up to a few hundred monitors, we recommend the Starter VPS plan:>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Unmetered bandwidth>
This gives Kuma plenty of room while leaving headroom for Nginx, backups, and a few other small services on the same host.
Connect to your server via SSH:
ssh root@your-server-ipStep 1: Update System Packages
sudo apt update && sudo apt upgrade -yIf a new kernel is installed, reboot before continuing:
sudo rebootReconnect once the server comes back up.
Step 2: Install Docker
Docker is the cleanest way to run Uptime Kuma. Updates become a one-line docker pull, state is isolated in a named volume, and you avoid dragging Node.js and its toolchain onto the host.
Install prerequisites and add the official Docker apt repository:
sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpgecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verify:
sudo docker run --rm hello-worldYou should see the standard "Hello from Docker!" banner.
Step 3: Run Uptime Kuma with Docker
Create a named volume so Kuma's state survives container upgrades, then start the container:
sudo docker volume create uptime-kuma
sudo docker run -d \ --name uptime-kuma \ --restart=always \ -p 3001:3001 \ -v uptime-kuma:/app/data \ louislam/uptime-kuma:1
Flag breakdown:
-d— run detached (background).--name uptime-kuma— fixed name sodocker logsand upgrades are predictable.--restart=always— restart on crash and on host reboot.-p 3001:3001— publish the web UI on port 3001. Change the left-hand number to remap (e.g.-p 127.0.0.1:3001:3001to bind only to localhost when using a reverse proxy).-v uptime-kuma:/app/data— persistent volume. Every setting, monitor, and history row lives here.louislam/uptime-kuma:1— pinned to the 1.x major so a future 2.x release does not upgrade you surprise-style. Swap to:2when you explicitly want to move.
sudo docker ps --filter name=uptime-kumaExpected:
CONTAINER ID IMAGE STATUS PORTS NAMES
a1b2c3d4e5f6 louislam/uptime-kuma:1 Up 30 seconds 0.0.0.0:3001->3001/tcp uptime-kumaIf you want to also let Kuma monitor Docker containers on the same host, add a bind mount for the Docker socket:
-v /var/run/docker.sock:/var/run/docker.sockBe aware: exposing the Docker socket to any container is effectively granting root. Only do this if you trust Kuma (and anyone who can log into Kuma) with that level of access.
Alternative: Install with Node.js and PM2
If you prefer a bare-metal install — for example, on a server where you do not want Docker — Kuma also runs directly on Node.js.
Install Node.js 20 (the LTS required by Kuma 1.x):
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs git build-essentialClone the repository and install dependencies:
sudo mkdir -p /opt/uptime-kuma sudo chown $USER:$USER /opt/uptime-kuma cd /opt/uptime-kuma git clone https://github.com/louislam/uptime-kuma.git . git checkout $(git tag | grep -E '^1\.' | sort -V | tail -n1)
npm run setup
npm run setup installs production dependencies and builds the frontend. This step takes 3-5 minutes.
Install PM2 and launch Kuma as a managed process:
sudo npm install -g pm2
pm2 start server/server.js --name uptime-kuma pm2 save pm2 startup systemd -u $USER --hp $HOME
Run the final sudo env ... command PM2 prints — it installs a systemd unit that resurrects Kuma on boot.
Alternatively, skip PM2 and write a small systemd service yourself at /etc/systemd/system/uptime-kuma.service pointing ExecStart at /usr/bin/node /opt/uptime-kuma/server/server.js. Either approach works; PM2 is slightly faster to set up and gives you pm2 logs uptime-kuma for free.
Step 4: Create the First Admin Account
Open your browser and navigate to:
http://your-server-ip:3001The first time you load the UI you will see a one-shot setup screen asking for:
- Language
- Username
- Password (minimum 6 characters — choose something stronger; this is your entire auth surface)
Lock it down before adding it to DNS. Kuma on0.0.0.0:3001with no firewall in place is internet-reachable the moment Docker starts it. Create the admin account immediately, or restrict port 3001 with UFW (sudo ufw deny 3001) until you have Nginx + auth in front of it.
Step 5: Add Monitors
Click "Add New Monitor" in the top-right corner. The monitor form is dense but the important fields are:
- Monitor Type — the probe kind (HTTP(s), TCP, Ping, DNS, Push, Docker Container, Keyword, etc.)
- Friendly Name — what shows up in the dashboard and notifications
- Heartbeat Interval — how often to probe (default 60s; you can go as low as 20s)
- Retries — failed probes before the monitor is marked down and notifications fire
- Notifications — which channels to alert
HTTP(s) Monitors
The workhorse. Point it at a URL and Kuma records status code, response time, and TLS certificate expiry on every check.
- URL:
https://your-site.com/healthz(prefer a dedicated health endpoint over the homepage — it is cheaper to serve and easier to keep truthful) - Accepted Status Codes:
200-299by default. Narrow to200exactly if your endpoint should never redirect. - Ignore TLS Errors: leave off. A broken cert is a real incident.
- Certificate Expiry Notification: enable. Kuma will warn you 7, 14, and 21 days out.
Keyword Monitors
Same as HTTP(s), with an extra "Keyword" field. The monitor fails if the response body does (or does not, when inverted) contain that string. Perfect for catching pages that return 200 with a maintenance banner.
TCP Port Monitors
Confirm a raw socket is open. Useful for databases and internal services that do not speak HTTP:
- Postgres: port 5432
- Redis: port 6379
- SMTP: port 25 or 587
- SSH: port 22
Ping (ICMP) Monitors
Simple network reachability. Requires ICMP to not be blocked between Kuma and the target.
DNS Monitors
Confirm a DNS record still resolves to the expected value. Helpful after DNS migrations or when a record is managed by a third party you do not fully trust.
- Hostname:
www.example.com - Resolver Server:
1.1.1.1(Cloudflare) or8.8.8.8(Google) - Record Type:
A,AAAA,CNAME,MX,TXT, etc.
Push Monitors
Inverted model: instead of Kuma probing your service, your service POSTs a heartbeat to a Kuma-generated URL on a schedule. Kuma fires an alert if the heartbeat stops arriving within the expected window.
Push monitors are the only reliable way to watch cron jobs, queue workers, and anything behind a firewall Kuma cannot reach. Ship the push URL as a curl one-liner at the end of your cron job:
/5 * /opt/myjob.sh && curl -fsS -m 10 --retry 5 https://kuma.example.com/api/push/abc123?status=upDocker Container Monitors
If you mounted the Docker socket in Step 3, add a Docker host (Settings -> Docker Hosts -> unix:///var/run/docker.sock) and then create a Docker Container monitor referencing a specific container name. It goes down the moment the container exits.
Step 6: Configure Notification Channels
Notifications live under Settings -> Notifications. Create them once, then assign to individual monitors or apply as defaults for all future monitors.
Discord
#ops-alerts.Slack
https://api.slack.com/messaging/webhooks for the channel you want.Telegram
@BotFather in Telegram and run /newbot. Follow the prompts to get a bot token.https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates in a browser and copy the chat.id from the JSON response.PagerDuty
For real on-call escalation. Create a service in PagerDuty (Services -> New Service -> Events API v2) and copy the integration key. In Kuma pick PagerDuty as the notification type, paste the integration key, and set severity (critical, error, warning). Failed monitors trigger PagerDuty incidents; recovery automatically resolves them.
SMTP (Email)
Kuma can speak plain SMTP — useful when you want alerts in a shared mailbox or routed into a ticketing system.
- Hostname: your SMTP server (e.g.
smtp.gmail.com,smtp.sendgrid.net) - Port: 587 (STARTTLS) or 465 (TLS)
- Username / Password: SMTP credentials
- From Email / To Email: sender and recipient
Apply as Default
In each notification, tick "Default enabled" and "Apply on all existing monitors" to backfill. Without this, new notifications only fire on monitors you explicitly attach them to.
Step 7: Publish Status Pages
Status pages let customers (or your team) see the current health of your services without logging into Kuma.
Acme Corp Status) and a Slug (e.g. acme). The page will live at https://your-kuma/status/acme.status.yourdomain.com instead of the slug path — configure the DNS CNAME and Nginx server block to match.For private internal status pages, create a second Status Page, keep it unpublished, and tick "Require authentication". Only logged-in Kuma users see it.
You can embed incident messages ("Investigating elevated latency on the API...") at the top of the page, and Kuma records them in the page's incident history.
Step 8: Schedule Maintenance Windows
Scheduled maintenance stops Kuma from paging you during planned downtime.
During an active window, Kuma continues probing but suppresses notifications and marks the monitor Maintenance (blue) rather than Down (red) on status pages.
Step 9: Nginx Reverse Proxy with TLS and WebSocket
Exposing Kuma on :3001 over plain HTTP is fine for testing, but for production you want a real domain, HTTPS, and proper forwarded headers. Kuma's real-time UI relies on Socket.IO, so the proxy config must forward WebSocket upgrades.
Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxCreate the site config:
sudo tee /etc/nginx/sites-available/uptime-kuma > /dev/null <<'EOF' server { listen 80; server_name status.yourdomain.com; return 301 https://$host$request_uri; }server { listen 443 ssl http2; server_name status.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/status.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/status.yourdomain.com/privkey.pem;
# Security headers add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; add_header Referrer-Policy strict-origin-when-cross-origin always;
client_max_body_size 20m;
location / { proxy_pass http://127.0.0.1:3001; proxy_http_version 1.1;
# WebSocket upgrade — required for Kuma's real-time UI 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;
# Long timeouts so idle WebSockets do not get killed proxy_read_timeout 300s; proxy_send_timeout 300s; } } EOF
Enable the site and issue a certificate:
sudo ln -s /etc/nginx/sites-available/uptime-kuma /etc/nginx/sites-enabled/
sudo certbot --nginx -d status.yourdomain.com
sudo nginx -t && sudo systemctl reload nginxNow rebind Kuma so it only listens on localhost (Nginx is the only thing that should reach it):
sudo docker rm -f uptime-kuma
sudo docker run -d \
--name uptime-kuma \
--restart=always \
-p 127.0.0.1:3001:3001 \
-v uptime-kuma:/app/data \
louislam/uptime-kuma:1Confirm externally that port 3001 is closed and https://status.yourdomain.com serves the UI with a valid cert.
Backups and Upgrades
Backup
All state lives in the uptime-kuma Docker volume mounted at /app/data. A cold tarball is the most robust backup:
sudo docker stop uptime-kuma
sudo tar czf /root/backups/uptime-kuma-$(date +%F).tgz -C /var/lib/docker/volumes/uptime-kuma/_data .
sudo docker start uptime-kumaShip the tarball off-box to object storage or another VPS. Automate with a cron entry nightly.
Upgrade
Upgrades within a major line (1.x -> 1.y) are one command:
sudo docker pull louislam/uptime-kuma:1
sudo docker rm -f uptime-kuma
sudo docker run -d \
--name uptime-kuma \
--restart=always \
-p 127.0.0.1:3001:3001 \
-v uptime-kuma:/app/data \
louislam/uptime-kuma:1Because the volume persists, the new container picks up all existing state. Check the release notes before upgrading — especially when moving from 1.x to 2.x, which involves a schema migration.
FAQ
Is Uptime Kuma free to use?
Yes. Uptime Kuma is open source under the MIT license. You can run unlimited monitors, notification channels, and status pages on your own VPS without any licensing fees or per-monitor charges. Your only cost is the VPS itself.
How many monitors can a single Uptime Kuma instance handle?
A small VPS with 2 GB RAM comfortably handles 100-200 monitors at 60-second intervals. On a Starter plan with 4 GB RAM, most users run 500+ monitors without issue. Beyond 1,000 monitors, consider splitting across multiple instances (regional shards), migrating to the MariaDB backend available in Kuma 2.x, or upgrading to more RAM and CPU.
Does Uptime Kuma support multi-user accounts?
As of the 1.x release line, Uptime Kuma has a single admin account. Multi-user access with role-based permissions is planned for 2.x. For shared team access today, front Kuma with an SSO reverse proxy like Authelia, Authentik, or Cloudflare Access — anyone allowed through the proxy lands in the same admin session, so it is appropriate for small trusted teams rather than customer-facing access.
Can Uptime Kuma monitor internal services that are not publicly reachable?
Yes. Uptime Kuma probes from wherever it is running. Install it on a VPS inside your private network, a WireGuard mesh, or your corporate VPN, and it can monitor internal hostnames and private IPs directly. For services where you cannot place Kuma in-network at all, use the Push monitor type — your service POSTs a heartbeat outbound, so no inbound reachability is required.
How is Uptime Kuma different from Pingdom or BetterUptime?
Uptime Kuma is self-hosted and free; Pingdom and BetterUptime are SaaS with per-monitor pricing that ranges from $15 to $200+ per month. Self-hosting means you own the data, control probe locations (including inside private networks), and never pay per check. The tradeoff is you run the infrastructure yourself — if the Kuma host goes down, Kuma cannot tell you. Point a free external watcher (UptimeRobot, BetterUptime free tier) at your Kuma instance to cover that gap.
Does Uptime Kuma integrate with Prometheus and Grafana?
Yes. Uptime Kuma exposes a Prometheus-compatible metrics endpoint at /metrics, protected by an API key generated in Settings. Scrape it from your Prometheus server and build Grafana dashboards showing per-monitor uptime, response-time percentiles, and certificate expiry. If you already run an observability stack, see our guides on installing Prometheus on Ubuntu, installing Grafana on Ubuntu, and installing Alertmanager on Ubuntu to wire Kuma into it.
How do I back up Uptime Kuma?
All state lives in the Docker volume mounted at /app/data. A tarball of that directory while the container is stopped is a complete backup. You can also take a hot SQLite copy using sqlite3 /app/data/kuma.db ".backup /tmp/kuma-backup.db" without stopping the container. Restore by extracting the archive into a fresh uptime-kuma volume and starting a new container against it — monitors, notifications, status pages, and history all come back intact.
Next Steps
Now that Uptime Kuma is watching your services, here are good follow-ups:
- Read the official wiki. The Uptime Kuma wiki on GitHub is the authoritative reference for every monitor type, notification integration, and configuration environment variable.
- Ship Kuma metrics to Prometheus. Scrape
/metricsinto Prometheus for long-term storage and SLO tracking. - Build dashboards in Grafana. Import one of the community Kuma dashboards into Grafana for a unified pane across infrastructure and uptime.
- Route alerts through Alertmanager. For teams already using Alertmanager, send Kuma's Prometheus-exposed monitor state through Alertmanager routing rules to reuse existing on-call schedules and silences.
- Add a watcher for the watcher. Point a free external monitor (UptimeRobot, BetterUptime free tier) at
https://status.yourdomain.comso you know if Kuma itself disappears. - Scripted provisioning. Kuma has a REST API (and an unofficial Python library,
uptime-kuma-api) so you can create monitors programmatically when new services are deployed — treating uptime checks as infrastructure-as-code.
Skip the Manual Install — Get a Monitoring-Ready VPS>
Our Starter VPS plans give Uptime Kuma everything it needs: fast NVMe storage, low-latency networking for clean probe results, and enough RAM for hundreds of monitors. Deploy in minutes and get your first alerts flowing the same afternoon.>
- 2 vCPU cores and 4 GB RAM
- 50 GB NVMe SSD
- Unmetered bandwidth
- Ubuntu 24.04 LTS preinstalled>
Deploy Your Monitoring VPS Now.