DEV Community

Cover image for Installing Uptime Kuma: server monitoring behind Traefik
serverkueche.de
serverkueche.de

Posted on • Originally published at serverkueche.de

Installing Uptime Kuma: server monitoring behind Traefik

Traefik is up – now we hang the first real app behind it. Uptime Kuma is ideal for that: tiny, immediately useful and without a database. It monitors your services and raises the alarm when one fails – from now on you notice first that something is stuck, not your users. Along the way you learn the pattern every further app repeats.

What are we building?

By the end, Uptime Kuma 2.4 runs at https://status.YOUR_DOMAIN, secured via Traefik with automatic HTTPS. You've set up the first monitor (which checks every minute whether a service responds), connected a notification and optionally a public status page. For the first time we bind a service that doesn't listen on port 80 – an important detail for all the following apps.

Prerequisites

Step by step

Step 1: The compose.yaml

Own folder, own file:

mkdir -p ~/uptime-kuma && cd ~/uptime-kuma
Enter fullscreen mode Exit fullscreen mode
services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    volumes:
      - kuma-data:/app/data
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.kuma.rule=Host(`status.YOUR_DOMAIN`)"
      - "traefik.http.routers.kuma.entrypoints=websecure"
      - "traefik.http.routers.kuma.tls.certresolver=le"
      - "traefik.http.services.kuma.loadbalancer.server.port=3001"
    restart: unless-stopped

volumes:
  kuma-data:

networks:
  proxy:
    external: true
Enter fullscreen mode Exit fullscreen mode

You know this from the Traefik tutorial – except for one new, decisive line:

      - "traefik.http.services.kuma.loadbalancer.server.port=3001"
Enter fullscreen mode Exit fullscreen mode

Uptime Kuma listens internally on port 3001, not on 80. This line tells Traefik which port to forward the requests to. Without it, Traefik guesses wrong and you get a Bad Gateway. Remember the label – every app that doesn't run on port 80 needs it.

The rest is the familiar pattern: no ports: (only reachable via Traefik), proxy network, named volume for the data.

Step 2: Start and first login

docker compose up -d
docker compose logs -f uptime-kuma
Enter fullscreen mode Exit fullscreen mode

When Kuma is ready, the log ends with this line – from here the service accepts requests (Ctrl+C only ends the following):

[SERVER] INFO: Welcome to Uptime Kuma
[SERVER] INFO: Uptime Kuma Version: 2.4.0
[SETUP-DATABASE] INFO: Listening on:
[SETUP-DATABASE] INFO: -  http://localhost:3001
Enter fullscreen mode Exit fullscreen mode

On the first start, Kuma creates its database in the volume – that takes a few seconds. Then open https://status.YOUR_DOMAIN in the browser. Uptime Kuma 2.x first asks for the database – for a setup like ours, SQLite is the right, simplest choice (select it, click Next). Right after that you create the admin account (username + strong password).

Uptime Kuma's initial setup: choose the language and create the admin account

⚠️ Create the admin account immediately

As long as no admin account exists, anyone who opens the page can create one. Do this right after the first start – not "later".

Step 3: Create the first monitor

A monitor is a recurring check. Click Add New Monitor and create one for Traefik itself:

  • Monitor type: HTTP(s)
  • Friendly name: Traefik Dashboard
  • URL: https://traefik.YOUR_DOMAIN
  • Heartbeat interval: 60 seconds
  • Authentication: the Traefik dashboard is protected by basic auth (step 7 of the Traefik tutorial) – so choose HTTP Basic Auth as the authentication method below and enter the user and password. Without credentials, Kuma only gets 401 and reports the monitor as Down.

Save – after a few seconds the monitor is Up (green) and shows the response time.

The Uptime Kuma dashboard with two running monitors – both green with 100% availability and

Besides the simple HTTP(s) check, it pays to choose the matching monitor type:

  • HTTP(s) – Keyword: additionally checks whether a certain word appears in the response text. This detects "the server responds, but shows an error page".
  • TCP port: for services without a web interface (e.g. a database, an SSH port). Only checks whether the port is open.
  • Ping: the simplest reachability test via ICMP.
  • Docker container: checks the container status directly via the Docker socket – handy for internal services without their own domain.
  • Push: here the monitored service calls Kuma regularly. Ideal for cron jobs and backups: if the script doesn't report in time, Kuma raises the alarm ("dead man's switch").

Create the matching monitor for every important service.

💡 Tip

Check public services via their real domain (https://…), not via localhost. This way you simultaneously test that Traefik and the certificate work from outside – not just that the container is running.

For the HTTP(s) monitor, the option "certificate expiry notification" is also worth it: Kuma then warns in good time before a TLS certificate expires. For services behind Traefik, Let's Encrypt renews automatically – but this very automation occasionally fails silently (a DNS record is changed, port 80 accidentally closed). The monitor is your safety net and reports in while there are still days to fix it, instead of visitors suddenly facing a certificate warning.

Step 4: Set up notifications (email and Telegram)

A monitor without an alarm is just a pretty chart. Under Settings → Notifications → Setup Notification you create a channel. Uptime Kuma supports over 90 – we set up the two most common completely: email for the classic message and Telegram for push straight to the phone.

Email (SMTP)

Choose "Email (SMTP)" as the notification service and enter your mail provider's data:

  • Hostname / port: e.g. smtp.YOUR_PROVIDER.com and 587
  • Security: STARTTLS (port 587) or TLS/SSL (port 465)
  • Username / password: your SMTP credentials
  • From / to address: which address the warning comes from and which it's sent to

The email notification (SMTP) in Uptime Kuma: hostname, port, security and from address

Click Test – within a few seconds a test message lands in the mailbox. Only when it really arrives are the credentials and port correct. Don't forget to save.

Telegram

Telegram is ideal for instant push alerts to the phone – without your own mail server. You need two pieces of information:

  1. Bot token: message @BotFather in Telegram, send /newbot, assign a name – BotFather replies with the token.
  2. Chat ID: send your new bot any message, then open https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates in the browser and read the chat.id from the response.

Enter the token and chat ID into the Telegram notification (Uptime Kuma links both helpers directly in the dialog) and click Test – the message should appear in the chat immediately.

The Telegram notification in Uptime Kuma: bot token and chat ID, with a direct link to the BotFather

⚠️ Otherwise the alarm stays silent

A configured notification does not take effect automatically. Enable it in each monitor (checkbox in the monitor form) or, in the notification dialog, turn on "Enabled by default" and "Apply on all existing monitors".

If you want push messages entirely under your own control (without a Telegram server), ntfy comes later – self-hosted, with its own recipe in the series.

Step 5: A public status page (optional)

Kuma can publish a status page where visitors see whether your services are running. Here's how:

  1. Status Pages → New Status Page, then assign a name (e.g. "Serverküche Status") and a slug (the URL, e.g. serverkueche) and click Next.
  2. In the editor, Add Group (e.g. "Services"), and below it, add the desired monitors via the selection field.
  3. Save at the top right – done. The page is then publicly reachable at https://status.YOUR_DOMAIN/status/serverkueche.

Only include what really everyone may see – better leave internal services out.

The public status page

Step 6: Avoid false alarms – fine-tune the alarm behavior

A monitor that raises the alarm at every brief network hiccup is quickly ignored – and then you miss the real outage. In the monitor form you set the behavior appropriately:

  • Retries: the service only counts as "Down" after n failed checks. 23 filters out individual dropouts without obscuring real outages for long.
  • Heartbeat interval on failure: Kuma may check more often in the error case (e.g. every 20 seconds) to detect recovery quickly.
  • Resend notification: Kuma can remind you every x minutes as long as a service is down – useful so an outage at night doesn't get lost in a single mail.

💡 Plan maintenance windows

If you plan an update with downtime, create a maintenance window under Maintenance. Kuma then pauses the alarms for the affected monitors – so you (and the status page) don't get false alarms while you're at work.

Step 7: Monitor cron jobs with a push monitor

Classic monitors check from outside whether a service responds. For things that run silently in the background – a nightly backup, a sync script, a cron job – the push monitor flips the principle: not Kuma asks, but your script reports in. If the report fails to come, Kuma raises the alarm – the classic "dead man's switch".

Create a monitor of type Push. Kuma then shows you a unique push URL:

https://status.YOUR_DOMAIN/api/push/YOUR_TOKEN?status=up&msg=OK&ping=
Enter fullscreen mode Exit fullscreen mode

You call this URL at the end of your script – for example after a successfully completed backup:

# ... your backup command ...
curl -fsS "https://status.YOUR_DOMAIN/api/push/YOUR_TOKEN?status=up&msg=Backup+OK" > /dev/null
Enter fullscreen mode Exit fullscreen mode

Set the check interval in Kuma a bit more generously than your cron cadence (if the backup runs hourly, give Kuma e.g. 90 minutes of tolerance). If no curl comes in that time, the monitor goes to Down and you're notified – so you learn about a backup that did not run, not only when you urgently need it.

Step 8: Secure the admin login with 2FA

Your Kuma login protects access to all monitors, the stored notification credentials and the status-page configuration – and it's publicly on the net. So enable two-factor authentication: under Settings → Security → Two-Factor Authentication. Kuma shows a QR code you scan with an authenticator app (e.g. Aegis or 2FAS); to activate, you enter the generated code once.

💡 Secure the recovery

Keep the TOTP secret or a second authenticator in a safe place (password manager). If you lose your phone and have no copy, you can otherwise only get back in via the database in the kuma-data volume.

When things go wrong

Bad Gateway (502) when opening status.YOUR_DOMAIN. Almost always the port label traefik.http.services.kuma.loadbalancer.server.port=3001 is missing or has a wrong port. Traefik then reaches the container but knocks on the wrong port. Check the label and run docker compose up -d again.

404 page not found instead of Kuma. As with every app behind Traefik: traefik.enable=true set? Container on the proxy network? Is the domain in the Host(...) rule correct and does the DNS record status.YOUR_DOMAIN point to the server? The Traefik dashboard shows under "HTTP Routers" whether kuma is registered.

The interface loads, but the live update stutters / breaks off. Kuma uses WebSockets. Traefik forwards those correctly by default – if the problem still occurs, it's usually an upstream CDN/proxy (e.g. Cloudflare in "proxy" mode) that blocks WebSockets. For direct operation behind Traefik, no extra configuration is needed.

After a re-setup all monitors are gone. The kuma-data volume was deleted (e.g. by docker compose down -v). All configuration and history lives solely in this volume – that's why it's at the top of the next section.

Maintenance & backups

  • Back up: the complete heart of Kuma is the kuma-data volume (a SQLite database). Back it up regularly – if it's gone, all monitors and the history are gone. We build the off-site backup for it in the Restic tutorial.
  • Updates: the tag :2 stays on the 2.x series and brings bug fixes with docker compose pull && docker compose up -d. Before a jump to a new major version (e.g. later :3), read the release notes and back up the volume first.
  • Coming from 1.x? The switch to :2 migrates the SQLite database automatically on the first start – that can take a moment, and going back to :1 is not intended afterwards. So back up the kuma-data volume beforehand, then you're on the safe side. New installations (like above) aren't affected.
  • Honest limitation: a monitor that runs on the same server as the monitored services can't warn you when the whole server fails – then Kuma is offline too. For that case, add an external watcher. Two cheap ways: a second Uptime Kuma on a small server (or at home) that only monitors this instance via HTTP – or a free external ping service that pings your public status page. This way you also get a notice when the whole host is gone – the only case a local monitor inherently can't cover.

With that you've internalized the app pattern and monitor everything you hang behind Traefik from now on. What every further app requires are encrypted off-site backups with Restic – so your data survives a server crash.


This post first appeared on serverkueche.de.

Top comments (0)