Uptime Kuma is a free, self-hosted monitoring tool that checks your websites and services at regular intervals and alerts you when they go down. It supports HTTP(S), keyword, TCP port, ping and DNS checks, sends notifications to email, Telegram, Discord, Slack and many other services, and can publish public status pages. In this tutorial you will run Uptime Kuma with Docker Compose on Ubuntu 24.04, put it behind Nginx with a Let's Encrypt certificate, and create your first monitors and alerts.

Prerequisites

To follow this tutorial you need:

  • A server running Ubuntu 24.04 LTS with at least 1 GB of RAM, for example a CubePath VPS. Run the monitor on a different server from the sites it watches, otherwise an outage takes down the monitor too.
  • A non-root user with sudo privileges.
  • Docker Engine with the Docker Compose plugin installed from Docker's official repository. The docker compose version command must work.
  • A domain or subdomain, status.your_domain in this guide, with a DNS A record pointing to the server's public IP.

Step 1 - Creating the Docker Compose project

Create a directory for Uptime Kuma in your home directory and move into it:

mkdir ~/uptime-kuma
cd ~/uptime-kuma

Create the Compose file:

nano compose.yaml

Add the following content:

services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    container_name: uptime-kuma
    restart: unless-stopped
    volumes:
      - ./data:/app/data
    ports:
      - "127.0.0.1:3001:3001"

A few details matter here:

  • The 2 tag follows the latest 2.x release, so you get fixes when you pull the image without jumping to a new major version.
  • All monitors, settings and history are stored in ./data, which makes backups a matter of copying one directory.
  • The port is published only on 127.0.0.1. Docker bypasses UFW for published ports, so binding to localhost is what keeps the unencrypted port 3001 off the Internet. Nginx will be the only public entry point.

Step 2 - Starting Uptime Kuma

Start the container in the background:

docker compose up -d

Check that it is running and healthy. The first start can take a minute:

docker compose ps
NAME          IMAGE                    COMMAND                  SERVICE       CREATED          STATUS                    PORTS
uptime-kuma   louislam/uptime-kuma:2   "/usr/bin/dumb-init …"   uptime-kuma   45 seconds ago   Up 44 seconds (healthy)   127.0.0.1:3001->3001/tcp

Confirm that the application answers locally:

curl -sI http://127.0.0.1:3001
HTTP/1.1 302 Found

If the container is not healthy, read its logs with docker compose logs -f.

Step 3 - Installing Nginx as a reverse proxy

Install Nginx and Certbot, then open HTTP, HTTPS and SSH in UFW:

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx
sudo ufw allow OpenSSH
sudo ufw allow "Nginx Full"
sudo ufw enable

Create a server block for Uptime Kuma:

sudo nano /etc/nginx/sites-available/uptime-kuma

Add this configuration, replacing status.your_domain. The Upgrade and Connection headers are required because the Uptime Kuma interface communicates over WebSockets:

server {
    listen 80;
    listen [::]:80;
    server_name status.your_domain;

    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;
    }
}

Enable the site, test the configuration and reload Nginx:

sudo ln -s /etc/nginx/sites-available/uptime-kuma /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Step 4 - Enabling HTTPS

Request a Let's Encrypt certificate. Certbot adds the TLS settings to the server block and, if you accept, a redirect from HTTP to HTTPS:

sudo certbot --nginx -d status.your_domain

Check that the site now answers over HTTPS:

curl -sI https://status.your_domain
HTTP/1.1 302 Found
Server: nginx/1.24.0 (Ubuntu)

Certbot's systemd timer renews the certificate automatically. You can test renewal with sudo certbot renew --dry-run.

Step 5 - Completing the initial setup

Open https://status.your_domain in your browser. The setup wizard appears the first time:

  1. If you are asked to choose a database, SQLite is enough for a single server monitoring dozens of sites.
  2. Create the administrator account with a strong password.

After logging in, go to Settings > Reverse Proxy and set Trust Proxy to Yes, so that Uptime Kuma reads the real client IP from the headers Nginx sends. Then go to Settings > Security and enable two-factor authentication for your account.

Step 6 - Adding your first monitor

Click Add New Monitor and fill in:

  • Monitor Type: HTTP(s) to check that a URL returns a successful status code, or HTTP(s) - Keyword to also require a word in the page, which catches error pages served with a 200 code.
  • Friendly Name: a name such as Main website.
  • URL: the full address, for example https://your_domain.
  • Heartbeat Interval: how often to check, in seconds. 60 is a good default.
  • Retries: how many consecutive failures are needed before the monitor is marked as down. 2 or 3 avoids alerts caused by a single timeout.

Click Save. The monitor appears in the left column and turns green after the first successful check. Other useful types are TCP Port (for SSH, databases or mail servers), Ping and DNS.

HTTP(s) monitors also track TLS certificates. Under Settings > Notifications you can enable the TLS Certificate Expiry warning to be alerted days before a certificate expires.

Step 7 - Configuring notifications

A monitor is only useful if someone learns about the outage. Go to Settings > Notifications and click Setup Notification. Choose a notification type, such as Email (SMTP), Telegram or Discord, and fill in the fields for that service. Tick Default enabled so that new monitors use it automatically, and Apply on all existing monitors to attach it to the ones you already created.

Click Test before saving. You should receive a test message within a few seconds. If it does not arrive, check the credentials, and for SMTP, the port and security setting your provider requires.

Step 8 - Publishing a status page

Status pages show the state of your services to your users without giving them access to the dashboard. Click Status Pages in the top menu, then New Status Page, give it a name and a slug such as main, and add the monitors you want to show. Save it, and the page is available at https://status.your_domain/status/main.

Updating and backing up Uptime Kuma

To update to the latest 2.x release, pull the image and recreate the container from the project directory:

cd ~/uptime-kuma
docker compose pull
docker compose up -d

All data lives in ~/uptime-kuma/data. To back it up consistently, stop the container, archive the directory and start it again:

cd ~/uptime-kuma
docker compose stop
sudo tar -czf ~/uptime-kuma-backup-$(date +%F).tar.gz data
docker compose start

Copy the archive to another server or to object storage.

Troubleshooting

  • The page loads but stays on a spinner: WebSocket connections are failing. Make sure the Upgrade and Connection headers are in the Nginx configuration and reload Nginx.
  • 502 Bad Gateway from Nginx: the container is not running or not listening. Check docker compose ps and docker compose logs in ~/uptime-kuma.
  • Monitors flap between up and down: increase Retries and the Request Timeout of the monitor, and check whether the target rate limits the monitor's IP.

Conclusion

Uptime Kuma is now watching your websites from your own server over HTTPS, with alerts and a public status page. As next steps, add TCP monitors for services such as SSH or your database, set up a second notification channel so that alerts still arrive if one fails, and schedule the backup of ~/uptime-kuma/data.