VPS Monitoring & Observability Series
    Part 2 of 5

    Uptime Kuma — Uptime & Status Pages

    Monitor HTTP, TCP, DNS, and certificate expiry from outside your infrastructure. Build public status pages your users can check themselves.

    35 minutes
    $4/mo VPS sufficient
    Prerequisites

    RamNode VPS ($4/mo+), Docker & Docker Compose

    Time to Complete

    30–40 minutes

    Best Practice

    Deploy on a separate VPS from production for accurate external checks

    Internal monitoring like Beszel answers the question "is my server healthy?" Uptime Kuma answers a different question: "can my users actually reach my services?"

    These are not the same thing. A web server can have low CPU and available memory while being completely unreachable due to a misconfigured firewall rule, a failed DNS record, a hung process that is no longer accepting connections, or an expired SSL certificate. Beszel would not catch any of those. Uptime Kuma would.

    What Uptime Kuma Monitors

    Monitor typeWhat it checks
    HTTP / HTTPSStatus code, response time, optional keyword
    TCP portWhether a port is open and accepting connections
    PingICMP reachability
    DNSResolution of a hostname, expected record value
    Docker containerContainer running/stopped state via Docker socket
    DatabaseMySQL, PostgreSQL, Redis, MongoDB connectivity
    Certificate expiryDays until SSL cert expires
    PushHeartbeat monitor (your app pings Uptime Kuma)
    Steam game serverGame server query protocol

    Architecture

    Uptime Kuma VPS (monitoring server)
      - Checks every N seconds/minutes
      - Sends HTTP requests, TCP connections, pings
      - Stores results in SQLite
      - Publishes status page
    
    Production VPS (app server)
      - Receives checks from Uptime Kuma
      - No agent required
      - No configuration changes needed

    For a typical RamNode setup, deploy Uptime Kuma on a separate low-cost VPS in a different region from your main servers. This way, a full regional outage affecting your production server will also show up as a downtime event.

    Deployment

    Step 1 — Create the project directory

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

    Step 2 — Write the Compose file

    /opt/uptime-kuma/docker-compose.yml
    services:
      uptime-kuma:
        image: louislam/uptime-kuma:1
        container_name: uptime-kuma
        restart: unless-stopped
        ports:
          - "3001:3001"
        volumes:
          - ./uptime-kuma-data:/app/data
          - /var/run/docker.sock:/var/run/docker.sock:ro

    The docker.sock mount is only needed if you plan to monitor Docker containers on this same host.

    Step 3 — Start and configure

    docker compose up -d

    Open http://YOUR_SERVER_IP:3001. Create your admin account immediately — the setup page is publicly accessible until you do.

    Step 4 — Reverse proxy

    Caddy:

    Caddyfile
    status.yourdomain.com {
        reverse_proxy localhost:3001
    }

    nginx:

    nginx.conf
    server {
        listen 443 ssl;
        server_name status.yourdomain.com;
    
        ssl_certificate /etc/letsencrypt/live/status.yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/status.yourdomain.com/privkey.pem;
    
        location / {
            proxy_pass http://127.0.0.1:3001;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_read_timeout 3600;
        }
    }

    The proxy_read_timeout 3600 is important — Uptime Kuma uses WebSockets for live dashboard updates.

    Setting Up Monitors

    HTTP / HTTPS monitor

    Click Add New Monitor, select HTTP(s). Key settings:

    • Heartbeat Interval — 60 seconds default; 30 seconds for critical services
    • Retries — Set to 1 or 2 to prevent single slow responses from triggering downtime
    • Keyword monitoring — Verify actual page content, not just HTTP status code

    TCP port monitor

    Useful for non-HTTP services: game server ports, mail server ports (25, 587, 993), custom application ports.

    DNS monitor

    Monitor your primary domain's A record and set the expected value to your server IP. If someone accidentally changes your DNS, you get alerted immediately.

    SSL certificate expiry

    Enter your domain, set a warning threshold (30 days is sensible). Especially useful if you manage certs across multiple servers.

    Push monitor (heartbeat)

    Push monitors invert the checking model — your service sends a periodic HTTP request to Uptime Kuma. If the request stops coming, the monitor goes down. Use for cron jobs, background workers, and services behind firewalls.

    # At the end of your cron job
    curl -s "https://status.yourdomain.com/api/push/TOKEN?status=up&msg=OK" > /dev/null

    Notification Channels

    Discord (quickest setup)

    1. In Discord, go to your server's channel settings
    2. Integrations > Webhooks > New Webhook
    3. Copy the webhook URL
    4. In Uptime Kuma, add a Discord notification and paste the URL

    Slack

    Create a Slack app at api.slack.com/apps, enable Incoming Webhooks, add a webhook to your workspace and paste it into Uptime Kuma's Slack notification settings.

    Email (SMTP)

    SMTP Host: smtp.mailgun.org (or your provider's host)
    SMTP Port: 587
    Security: STARTTLS
    Username: your SMTP username
    Password: your SMTP password
    From: alerts@yourdomain.com
    To: your@email.com

    After creating a notification channel, edit each monitor and select the channel under Notifications. You can assign multiple channels per monitor.

    Status Pages

    Status pages let your users check service health themselves, reducing support load during incidents.

    Go to Status Page > New Status Page. Add groups to organize your monitors — "Website", "Infrastructure", "Third-party Services".

    Custom domain for status page

    Point a CNAME from status.yourcompany.com to your Uptime Kuma domain:

    Caddyfile
    status.yourcompany.com {
        reverse_proxy localhost:3001
    }

    Set the custom domain in the status page settings. Uptime Kuma will serve that status page on requests from that hostname.

    Maintenance Windows

    Go to Maintenance > Create Maintenance. Options include manual start/stop, single time, and recurring schedules.

    For planned RamNode VPS reboots or kernel updates, create a 30-minute maintenance window starting 5 minutes before you begin. Your status page will show "Scheduled Maintenance" rather than downtime.

    Backup and Restore

    Uptime Kuma stores everything in SQLite. Stop-and-copy method:

    docker compose stop
    cp -r /opt/uptime-kuma/uptime-kuma-data /backups/uptime-kuma-$(date +%Y%m%d)
    docker compose start

    Or use SQLite's online backup to avoid downtime:

    docker exec uptime-kuma sqlite3 /app/data/kuma.db ".backup /app/data/kuma.db.bak"
    cp /opt/uptime-kuma/uptime-kuma-data/kuma.db.bak /backups/uptime-kuma-$(date +%Y%m%d).db

    Combining With Beszel

    If you are running both Beszel (from Part 1) and Uptime Kuma, they complement each other without overlap:

    QuestionTool
    Is my server's CPU spiking?Beszel
    Is my web service responding to HTTP?Uptime Kuma
    Is my disk almost full?Beszel
    Is my SSL cert about to expire?Uptime Kuma
    Is that container using too much memory?Beszel
    Are my users able to reach my app right now?Uptime Kuma
    What happened at 3 AM last Tuesday?Both (different angles)

    Run both. The combined RAM footprint on even a $4/month VPS is well under 200 MB.

    What's Next

    Beszel and Uptime Kuma cover reactive monitoring — you know when something breaks. Part 3 introduces a different philosophy: Gatus, a YAML-driven health monitoring tool built for teams that want their monitoring configuration version-controlled alongside their infrastructure code.

    Part 3 covers:

    • Health checks defined as code in YAML
    • Condition expression syntax with JSON body inspection
    • CI/CD pipeline for auto-deploying config changes
    • Environment variable substitution for secrets