Uptime Kuma is a self-hosted monitoring tool that checks websites, ports, DNS records and other services at a fixed interval, notifies you when one goes down, and publishes public status pages. It has a web interface for everything, so there are no configuration files to maintain. 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, create your first monitors and notifications, publish a status page, and set up backups.

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 it on a different server or provider from the services you monitor, otherwise an outage can take down the monitor too.
  • A non-root user with sudo privileges and UFW enabled with SSH allowed.
  • Docker Engine and the Docker Compose plugin installed from Docker's official repository.
  • A domain name, your_domain in this guide (for example status.example.com), with an A record pointing to the server's IP.

Step 1 - Creating the Docker Compose project

Keep everything related to Uptime Kuma, including its data, in one directory so it is easy to back up:

sudo mkdir -p /opt/uptime-kuma
cd /opt/uptime-kuma

Create the Compose file:

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

Two details matter here:

  • The port is published on 127.0.0.1 only. Docker writes its own iptables rules, and a port published on all interfaces is reachable from the internet even when UFW has no rule for it. Nginx on the same host will be the only public entry point.
  • ./data holds the database, uploaded logos and settings. Everything you need to back up or migrate Uptime Kuma lives in that directory.

The 2 tag follows the latest 2.x release. If you are upgrading an existing 1.x installation, back up its data directory first, because the first 2.x start migrates the database and can take a while on large installations.

Step 2 - Starting Uptime Kuma

Pull the image and start the container in the background:

sudo docker compose up -d

Check that the container is running and healthy. The image includes a health check, which reports starting for the first seconds:

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

Confirm it answers locally:

curl -sI http://127.0.0.1:3001 | head -n 1
HTTP/1.1 302 Found

If the container keeps restarting, read its log with sudo docker compose logs -f uptime-kuma.

Step 3 - Configuring Nginx as a reverse proxy

Uptime Kuma updates its dashboard over a WebSocket connection (Socket.IO), so the proxy must forward the Upgrade and Connection headers. Install Nginx:

sudo apt update
sudo apt install -y nginx

Create a server block for your domain:

sudo nano /etc/nginx/sites-available/uptime-kuma
server {
    listen 80;
    listen [::]:80;
    server_name 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 syntax 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 with Let's Encrypt

Open HTTP and HTTPS in the firewall. Port 80 is needed for the certificate challenge and for the redirect to HTTPS:

sudo ufw allow 'Nginx Full'

Install Certbot with its Nginx plugin and request a certificate. Certbot adds the TLS configuration to the server block and sets up the HTTP to HTTPS redirect:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain

The package installs a systemd timer that renews the certificate automatically. Check that renewal works:

sudo certbot renew --dry-run

Step 5 - Completing the initial setup

Open https://your_domain in your browser. The setup wizard asks which database to use. SQLite is the right choice for most single-server installations with up to a few hundred monitors; it is stored in ./data with everything else.

Next, create the administrator account with a strong password. There is only one account, so treat these credentials like any other admin password.

After logging in, open Settings and review two options:

  • General > Primary Base URL: set it to https://your_domain. Uptime Kuma uses it in notification links.
  • Reverse Proxy > Trusted Proxies: set Trust Proxy to Yes, so Uptime Kuma reads the client IP from the X-Forwarded-For header sent by Nginx instead of logging 127.0.0.1 for every login.

Enabling two-factor authentication under Settings > Security is also recommended, since the dashboard is public on the internet.

Step 6 - Adding monitors

Click Add New Monitor. Each monitor has a type, a target, a check interval and a retry count. A monitor only switches to DOWN after the configured number of consecutive failures, which avoids alerts for a single lost packet. These are the monitors most setups need:

Monitor typeTarget exampleWhat it verifies
HTTP(s)https://example.comThe URL returns a 2xx status code within the timeout.
HTTP(s) - Keywordhttps://example.com/health, keyword okThe response body contains (or does not contain) a string.
TCP Portdb.example.com, port 5432A TCP connection can be established.
Ping203.0.113.10The host answers ICMP echo requests.
DNSexample.com, record type AThe name resolves, optionally through a specific resolver.

For your first monitor, create an HTTP(s) monitor for your main website:

  1. Friendly Name: Website.
  2. URL: https://your_website.
  3. Heartbeat Interval: 60 seconds, and Retries: 2.
  4. Under Advanced, enable Certificate Expiry Notification. Uptime Kuma then warns you before the TLS certificate expires, by default at 7, 14 and 21 days.
  5. Click Save.

The monitor appears in the left column. Within a minute it shows a green heartbeat bar and the response time graph starts filling.

Step 7 - Setting up notifications

Monitors are only useful if someone is told when they fail. Go to Settings > Notifications > Setup Notification and choose a notification type. Uptime Kuma supports many services; the most common are:

  • Email (SMTP): enter your SMTP server, port 587 with STARTTLS (or 465 with TLS), username, password, and the sender and recipient addresses. Outbound port 25 is blocked on many cloud servers, so use your mail provider's submission port.
  • Slack, Discord or Microsoft Teams: paste an incoming webhook URL created in the chat application.
  • Telegram: enter a bot token from @BotFather and your chat ID.
  • Webhook: Uptime Kuma sends a POST request with a JSON body to any URL, for integrations with your own tools.

Click Test before saving; a test message should arrive within seconds. Enable Default enabled so the notification is attached to every new monitor, and Apply on all existing monitors to attach it to the ones you already created.

To verify the full alert path, edit the Website monitor, change the URL to a path that does not exist on a site that returns 404, and save. After the retries, the monitor turns red and you receive a DOWN notification. Restore the URL and you receive an UP notification.

Step 8 - Publishing a status page

A status page shows your users the current state and recent uptime of selected monitors without giving them access to the dashboard.

  1. Go to Status Pages > New Status Page.
  2. Enter a name, for example Example Status, and a slug such as example. The page will be available at https://your_domain/status/example.
  3. In the editor, add a group (for example Website or API) and add monitors to it. Only the monitors you add are shown.
  4. Optionally add a description, a logo and a footer text, then click Save.

Open the page in a private browser window to see it as your users will. To show planned work on the page, schedule a window under Maintenance: affected monitors are shown as under maintenance and do not send DOWN notifications during that time.

Step 9 - Backing up and updating

All state lives in /opt/uptime-kuma/data. The safest backup is a copy taken while the container is stopped, because the database may be mid-write while running. Stopping for a few seconds only delays the next checks:

cd /opt/uptime-kuma
sudo docker compose stop
sudo tar -czf "/root/uptime-kuma-$(date +%F).tar.gz" -C /opt/uptime-kuma data
sudo docker compose start

Copy the archive off the server, for example with scp or to object storage. To restore on a new server, extract it into /opt/uptime-kuma, create the same compose.yaml and run sudo docker compose up -d.

To update to the latest 2.x release, take a backup first, then pull the new image and recreate the container:

cd /opt/uptime-kuma
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune -f

Troubleshooting

The dashboard loads but stays on "Cannot connect to the socket server". The WebSocket upgrade is not reaching the container. Check that the proxy_http_version, Upgrade and Connection lines are in the Nginx location block, and that no other proxy in front of Nginx strips them.

502 Bad Gateway from Nginx. The container is not running or not listening on 127.0.0.1:3001. Check sudo docker compose ps and sudo docker compose logs uptime-kuma.

You lost the admin password. Reset it from inside the container, then follow the prompts:

sudo docker exec -it uptime-kuma npm run reset-password

Ping monitors always fail. The target may block ICMP, or an upstream firewall filters it. Use a TCP Port or HTTP monitor instead, which also better reflects whether the service works.

Many monitors show DOWN at the same time. Before assuming a mass outage, check the monitoring server itself: DNS resolution (resolvectl query example.com), outbound connectivity (curl -sI https://example.com), and the container log (sudo docker compose logs --tail 50 uptime-kuma).

Conclusion

You now have Uptime Kuma running in Docker on Ubuntu 24.04, reachable over HTTPS through Nginx, with HTTP and certificate monitoring, alert notifications and a public status page, and a simple backup and update procedure.

As next steps, add monitors for every public endpoint and critical internal port, use Push monitors to get alerted when a cron job or backup stops reporting in, and schedule the backup commands above with a systemd timer so copies are taken automatically.