# How to monitor your sites with Uptime Kuma on a VPS

> Self-host Uptime Kuma on a VPS with Docker Compose, put it behind Caddy with automatic HTTPS and get downtime alerts in Telegram in about 15 minutes.

Uptime Kuma is a free, self hosted monitoring tool with a clean web interface. It checks websites, TCP ports, ping, DNS records and more, down to 20 second intervals, and alerts you through Telegram, Discord, Slack, email and dozens of other services. This guide runs it with Docker Compose, publishes it under your own domain with HTTPS through Caddy and connects Telegram alerts.

## What you need

- **A VPS with Docker installed.** Follow [how to install Docker on Ubuntu](https://datapasa.com/wiki/server-management/install-docker-on-ubuntu) first. Uptime Kuma is light, 1 vCPU and 1 to 2 GB of RAM are enough for dozens of monitors.
- **A domain or subdomain**, for example `status.example.com`, with an **A record** pointing to the server IP.
- **A Telegram account** for alerts.

> **Monitor from a separate server.** A monitoring tool cannot report that its own server is down. Run Uptime Kuma on a small VPS that is separate from the servers and sites it watches.

## Step 1. Start Uptime Kuma with Docker Compose

Create a folder and a Compose file:

```bash
mkdir -p ~/uptime-kuma && cd ~/uptime-kuma
nano compose.yaml
```

This is the official Compose file with one change: the port is bound to `127.0.0.1`, so Kuma is reachable only through the reverse proxy and not directly from the internet. Docker published ports bypass UFW, so this binding matters.

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

Start it:

```bash
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:3001
```

The container should be `running`, and curl should get an HTTP answer. All data is kept in `~/uptime-kuma/data`. Uptime Kuma does not support network filesystems such as NFS for this folder, keep it on the local disk.

## Step 2. Install Caddy as a reverse proxy

Caddy gets and renews a Let's Encrypt certificate automatically and proxies WebSocket connections, which the Kuma interface needs, without extra settings. Install it from the official repository:

```bash
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
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 chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
```

The package starts Caddy as a systemd service named `caddy`.

## Step 3. Point your domain to Uptime Kuma

Replace the contents of `/etc/caddy/Caddyfile`:

```bash
sudo nano /etc/caddy/Caddyfile
```

```text
status.example.com {
    reverse_proxy 127.0.0.1:3001
}
```

Open the web ports if UFW is active, then reload Caddy:

```bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo systemctl reload caddy
```

Caddy needs port 80 and 443 reachable and the DNS record in place to get the certificate. If something is wrong, `journalctl -u caddy -n 50` shows the reason.

## Step 4. Create the admin account

Open `https://status.example.com`. On the first visit Uptime Kuma 2 asks which database to use. **SQLite** is a simple database file recommended for small setups, and the Docker image also includes an embedded MariaDB that needs no settings. Either works for a personal monitor.

Then create your admin account with a strong password. In **Settings > Security** you can also enable two factor authentication.

Because Kuma is only reachable through Caddy, go to **Settings > Reverse Proxy** and set **Trust Proxy** to **Yes**. Logs will then show real visitor IPs instead of `127.0.0.1`.

## Step 5. Connect Telegram notifications

1. In Telegram, open [@BotFather](https://t.me/BotFather), send `/newbot` and follow the prompts. Copy the bot token.
2. Open a chat with your new bot and send it any message, so it is allowed to write to you.
3. In Uptime Kuma go to **Settings > Notifications** and click **Set Up Notification**.
4. Choose **Telegram** as the notification type and paste the token into **Bot Token**.
5. Click **Auto Get** next to **Chat ID** to fill in your chat ID automatically.
6. Enable **Default enabled** so new monitors use it, and optionally **Apply on all existing monitors**.
7. Click **Test**. A test message should arrive in Telegram. Then save.

## Step 6. Add your first monitors

Click **Add New Monitor** and choose the **Monitor Type**:

| Type | Use it for |
|---|---|
| HTTP(s) | Websites and APIs. Checks the status code and can also warn before the TLS certificate expires. |
| HTTP(s) Keyword | Pages that must contain a specific text, to catch error pages returned with status 200. |
| TCP Port | Services like SSH, databases or a game server port. |
| Ping | Plain reachability of a server. |
| Push | Cron jobs and backups: the job calls a URL, and Kuma alerts if the call does not arrive in time. |

Give it a **Friendly Name**, set the URL or host and the **Heartbeat Interval**, then save. A Push monitor pairs well with a nightly [restic backup](https://datapasa.com/wiki/server-management/back-up-your-vps): add a `curl` to the push URL after the backup, and you hear about it when a backup silently stops running.

## Status pages

Under **Status Pages** you can publish a public page with selected monitors, for example to show your users whether your service is up. Each page gets its own slug, and you can map a separate domain to it.

## Update Uptime Kuma

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

Back up `~/uptime-kuma/data` before major upgrades. It holds all monitors, history and settings.

## Summary

Uptime Kuma now runs in Docker, is reachable only through Caddy with HTTPS, and sends alerts to Telegram. Add a monitor for every site, API and important port you run, and you will learn about problems before your users do.
