Self-host Uptime Kuma with Docker and HTTPS
Run Uptime Kuma 2 in Docker Compose, claim it privately over an SSH tunnel, put Caddy in front for HTTPS, then add monitors, alerts and a status page.
Tested on Ubuntu 24.04 LTS
Before you start
- A server with Docker Engine and the Compose plugin
- A domain or subdomain for the dashboard and status page
- Root or a user with sudo
- SSH access from your computer
To self-host Uptime Kuma, run the louislam/uptime-kuma:2 image with Docker Compose, bind its port 3001 to 127.0.0.1, create the admin account through an SSH tunnel, and then put Caddy in front to serve the dashboard and status page over HTTPS. It runs comfortably on the smallest server: one container, one volume, about fifteen minutes of work.
Uptime Kuma checks websites, TCP ports, DNS records, Docker containers and more on a schedule, and alerts you through email, Telegram, Discord, Slack, ntfy and many other services when something stops answering.
| What | In this tutorial |
|---|---|
| The domain | status.example.com |
| The server's public IPv4 address | 203.0.113.10 |
| The project directory | /opt/uptime-kuma |
Put it on the right server
A monitor can't report that its own server is down. Run Uptime Kuma on a different server from the sites it watches, ideally with a different provider or in a different location. If you only have one server, it still catches crashed services, expired certificates and full disks on others, but pair it with an outside check for the server itself.
Pick the image tag
Uptime Kuma 2 is the current release line (2.5.6 at the time of writing). Its Docker image tags are not what you'd guess:
| Tag | What it runs |
|---|---|
louislam/uptime-kuma:latest |
Version 1, the old line |
louislam/uptime-kuma:1 |
Version 1 |
louislam/uptime-kuma:2 |
The newest 2.x release |
louislam/uptime-kuma:2.5.6 |
Exactly 2.5.6 |
So latest gives you version 1. Use 2 to get every 2.x update when you pull, or an exact version like 2.5.6 to choose when you upgrade. Check the releases page for the newest one.
Run Uptime Kuma with Docker Compose
Create a directory and the Compose file:
sudo mkdir -p /opt/uptime-kuma
cd /opt/uptime-kuma/opt/uptime-kuma/compose.yaml:
services:
uptime-kuma:
image: louislam/uptime-kuma:2.5.6
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- uptime-kuma:/app/data
volumes:
uptime-kuma:The 127.0.0.1: in front of the port matters. Docker's published ports bypass ufw, so "3001:3001" would put the setup page on the internet, where the first visitor gets to create the admin account. Bound to localhost, only the server itself (and Caddy, later) can reach it.
Start it:
sudo docker compose up -dCheck it worked
sudo docker compose ps
curl -I http://127.0.0.1:3001After about thirty seconds ps shows the container (healthy), and curl gets HTTP/1.1 302 Found with Location: /setup-database: it is waiting for you to finish the setup.
Claim it over an SSH tunnel
From your own computer, forward a local port to the server's port 3001 through SSH:
ssh -L 3001:127.0.0.1:3001 root@203.0.113.10Leave that session open and browse to http://localhost:3001.
- Database. Uptime Kuma 2 asks where to keep its data first. Choose SQLite: a single file in the volume, nothing else to run or back up. Embedded MariaDB suits very large setups with hundreds of monitors. Use MariaDB/MySQL only if you already run a database server you look after.
- Admin account. Create the admin user with a long password.
- Two-factor login. Under Settings, Security, turn on 2FA.
Put Caddy in front for HTTPS
You need HTTPS to reach the dashboard without a tunnel and to publish a status page. Point an A record (and an AAAA record, if the server has IPv6) for status.example.com at the server, then install Caddy from its repository:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddyReplace the contents of /etc/caddy/Caddyfile with:
status.example.com {
reverse_proxy 127.0.0.1:3001
}Open the web ports and reload:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddyCaddy gets a Let's Encrypt certificate and passes the websocket connection the dashboard uses without extra settings. If the server sits behind a panel firewall, allow 80 and 443 there too.
Then, in Uptime Kuma's Settings, Reverse Proxy, set Trust Proxy to Yes, so it logs visitors' real addresses instead of 127.0.0.1, and under General set Primary Base URL to https://status.example.com, so links in notifications point to the right place.
Check it worked
curl -I https://status.example.comIt answers HTTP/2 302 with a redirect to /dashboard. Open the address in a browser and log in.
Add monitors, alerts and a status page
- Notifications first. In Settings, Notifications, set up at least one channel and press Test. A monitor without a notification only changes color on a page you're not looking at.
- Monitors. Add New Monitor: HTTP(s) for a website (it can also warn before the certificate expires, under Advanced), TCP Port for SSH or a database port, DNS for a record that must not change, Ping for a host. An interval of 60 seconds with two or three retries avoids alerts for one dropped request.
- Status page. Status Pages, New Status Page, pick a slug, add the monitors you want to show and save. It's public at
https://status.example.com/status/<slug>; the dashboard still needs a login.
Back it up
With SQLite, everything (monitors, history, settings, users) is in the uptime-kuma volume. Compose prefixes the project name, so the volume is called uptime-kuma_uptime-kuma. The database runs in WAL mode, so stop the container for a consistent copy:
cd /opt/uptime-kuma
sudo docker compose stop
sudo docker run --rm -v uptime-kuma_uptime-kuma:/data -v /root:/backup alpine tar czf /backup/uptime-kuma-$(date +%F).tgz -C /data .
sudo docker compose startThat takes a few seconds of downtime. Copy the archive off the server; Back up your server shows how to do it nightly.
Update, and upgrade from version 1
For a new 2.x release, back up, change the tag in compose.yaml, then:
cd /opt/uptime-kuma
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune -fIf you run version 1 today (from :1, :latest, or a VPSNine one-click install made before 2026-10-21; newer ones run :2), version 2 migrates the database on its first start. Back up the volume first. Point the Compose file at your existing volume by declaring it external, using the name docker volume ls shows for it (here, uptime-kuma):
volumes:
uptime-kuma:
external: trueThen remove the old container and start the new one:
sudo docker rm -f uptime-kuma
sudo docker compose up -d
sudo docker compose logs -fThe log shows [MIGRATION] lines while it converts the data. With months of history, that can take a long time; let it finish and don't restart the container halfway. The project's migration notes list the changes.
Troubleshooting
The browser at http://localhost:3001 says the connection was refused. The SSH tunnel isn't open, or something on your computer already uses port 3001. Use another local port: ssh -L 13001:127.0.0.1:3001 root@203.0.113.10 and browse to http://localhost:13001.
The dashboard loads but shows a spinner forever, or "Cannot connect to the socket server". The websocket connection doesn't get through. Caddy handles it without settings; with nginx, add proxy_http_version 1.1 and the Upgrade and Connection headers.
After an upgrade, the page sits on a migration screen. The database migration from version 1 is running. sudo docker compose logs -f shows progress; wait for it.
You lost the admin password. Reset it from the server:
cd /opt/uptime-kuma
sudo docker compose exec uptime-kuma npm run reset-passwordNext steps
- Run more apps behind one proxy: Docker Compose with a reverse proxy.
- Learn what to watch on the server itself in Monitor your server.
- Read Uptime Kuma's own documentation wiki.