Skip to content
+1 (813) 212-3723 support@layeronecloud.com
Self-hosting VPS guides

How to host Uptime Kuma on a VPS with Docker and HTTPS

Deploy an Uptime Kuma VPS with Docker Compose, Caddy HTTPS, explicit firewall rules, realistic sizing, backups, and safe updates.

6 min read

Uptime Kuma is a self-hosted uptime monitor and status-page application. This guide builds a small, production-minded Uptime Kuma VPS on Ubuntu 24.04 LTS, keeps its native port off the public internet, and publishes it through Caddy with an automatically managed TLS certificate.

The monitor should normally live away from the systems it checks. If Uptime Kuma runs beside the website it monitors, a failure of that VPS can take out both the service and the alert. A separate LayerOne VPS gives the monitor a different failure boundary, but it still does not replace checks from a second provider or geographic region when that distinction matters.

Uptime Kuma VPS requirements and LayerOne cost

Item Practical starting point
Minimum RAM 1 GB for the OS, Docker, Caddy, and a small monitor set
Recommended RAM 2 GB for update headroom, longer history, and dozens of checks
Expected CPU usage About 1–3% of one vCPU while idle for a small set; brief 10–30% bursts when many checks run together
Storage requirement 10 GB minimum; plan for 20 GB or more as heartbeat history and logs grow
Exact LayerOne SKU gc.micro — catalog slug layerone-starter, 1 vCPU, 2 GB RAM, 40 GB disk
Expected monthly cost $5.00/month equivalent, metered at $0.0068/hour while the VPS exists

Those CPU figures are planning estimates, not limits or guarantees. Check type, interval, retained history, notification providers, DNS latency, and monitor count all change resource use. A 10-second interval creates six times as many checks as a 60-second interval. Watch docker stats, disk use, and the VPS monitoring guide after importing a real monitor set.

LayerOne meters the VPS hourly; a short calendar month, deletion before 730 hours, extra transfer, or a future catalog change can make the invoice differ from the monthly equivalent. Confirm the current catalog on Pricing before ordering.

Before you install

This walkthrough assumes:

  • a fresh Ubuntu 24.04 LTS server with a public IPv4 address;
  • a DNS A record such as status.example.com pointing to that address;
  • Docker Engine and the Compose plugin installed with Running Docker; and
  • an SSH key, a non-root sudo user, and current security updates. Complete Your first hour on a new server first.

Uptime Kuma v2 requires storage that supports POSIX file locks. Use the local VPS disk for /app/data; do not place its SQLite data directory on NFS.

1. Apply both firewall layers

On the LayerOne server's Networking tab, set inbound policy to DROP and outbound policy to ACCEPT. Allow TCP 22 only from your administration IP or network, then allow TCP 80 and 443 from 0.0.0.0/0. See The cloud firewall.

Apply the same intended policy with UFW inside Ubuntu. Keep the browser console open until a second SSH connection succeeds:

sudo apt update
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from YOUR.ADMIN.IP.ADDRESS to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Docker can insert forwarding rules ahead of UFW. The LayerOne cloud firewall is therefore the authoritative upstream boundary for Docker-published ports. This stack intentionally publishes only 80 and 443; port 3001 remains on the private Compose network.

2. Create the Uptime Kuma stack

Create the project and local data directory:

sudo mkdir -p /opt/uptime-kuma/data
sudo chown -R "$USER":"$USER" /opt/uptime-kuma
cd /opt/uptime-kuma

Create /opt/uptime-kuma/compose.yaml:

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

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    depends_on:
      - uptime-kuma
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:

The 2 image tag follows the supported Uptime Kuma v2 channel. It receives v2 updates without silently crossing to a future major version.

Create /opt/uptime-kuma/Caddyfile, replacing the example hostname:

status.example.com {
    encode zstd gzip
    reverse_proxy uptime-kuma:3001
}

Caddy supports the WebSocket connection Uptime Kuma needs. Uptime Kuma does not support being mounted reliably under a path such as /kuma; give it a hostname or subdomain instead.

Validate the effective Compose configuration before starting it:

cd /opt/uptime-kuma
docker compose config --quiet
docker compose up -d
docker compose ps
docker compose logs --tail=100 uptime-kuma caddy

3. Complete first-run setup and verify it

Open https://status.example.com, create the administrator, and use a unique password. Then enable two-factor authentication under Uptime Kuma's security settings. Do this immediately; the first-run screen is not an access control boundary.

Verify DNS, TLS, the private application port, and container health:

curl -fsSI https://status.example.com
sudo ss -lntp | grep -E ':(80|443|3001)[[:space:]]'
docker compose ps

The socket check should show public listeners for 80 and 443 but not a public 0.0.0.0:3001 listener. Create one HTTPS monitor and one deliberately failing test monitor. Confirm the failure alert and the recovery alert reach an off-server destination. A green dashboard does not prove notification delivery.

If all access is through Caddy, Uptime Kuma's official proxy guide recommends enabling trusted proxy headers in Settings → Reverse Proxy → HTTP Headers so client addresses are interpreted correctly. Do not enable that setting if untrusted clients can bypass the proxy.

4. Back up and restore Uptime Kuma

Uptime Kuma v2 supports backing up the entire data directory, not the removed JSON backup feature. Stop the application briefly so SQLite and its auxiliary files form a consistent set:

cd /opt/uptime-kuma
docker compose stop uptime-kuma
sudo tar -C /opt/uptime-kuma -czf "/root/uptime-kuma-$(date -u +%Y%m%dT%H%M%SZ).tar.gz" data compose.yaml Caddyfile
docker compose start uptime-kuma

Copy that archive to encrypted storage outside the VPS. LayerOne does not take snapshots or backups; read Backups and snapshots.

To restore onto a compatible fresh stack, stop Uptime Kuma, move the current data directory aside, extract the archive under /opt/uptime-kuma, correct ownership if necessary, and start the service. Keep the old directory until the dashboard, monitors, notification providers, and history have been verified.

5. Update safely

Read the Uptime Kuma release notes before every major migration. For updates within v2:

cd /opt/uptime-kuma
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 uptime-kuma

Take an off-server backup first. Do not interrupt a database migration. Confirm the version, dashboard login, a real monitor, and a test notification after the containers return.

Security and operational pitfalls

  • Never mount /var/run/docker.sock just to monitor containers unless you accept that a compromise of Uptime Kuma can become control of the Docker host.
  • Do not put secrets, private hostnames, raw error bodies, or internal ports on a public status page.
  • Keep authentication enabled even if only status pages are public.
  • Monitoring this VPS from itself cannot report loss of the server or its network path. Add an independent outside check.
  • Review retention and du -sh /opt/uptime-kuma/data regularly. A full root filesystem can corrupt databases and stop alerts.

Official and LayerOne references

Still stuck

Chat with us from the portal.

Ask the assistant from the Chat bar. During business hours you can ask for a person and a human joins live.