Is Uptime Kuma Down? Real-Time Status & Outage Checker
Is Uptime Kuma Down? Real-Time Status & Outage Checker
Uptime Kuma is the most popular self-hosted uptime monitoring tool with 60,000+ GitHub stars — a fancy, user-friendly alternative to Uptime Robot. Written in Node.js and Vue.js, it monitors HTTP(s), TCP, DNS, Docker containers, and more from a beautiful real-time dashboard. Uptime Kuma supports status pages, public dashboards, and notifications to Telegram, Discord, Slack, PagerDuty, email, and 90+ other services. It is the default choice for home lab operators and small teams who want Uptime Robot-style monitoring without a SaaS subscription. The irony of Uptime Kuma going down is acute: when it crashes, all of your monitors stop running, all alerts go silent, and you have no visibility into whether your services are up — until something else tells you.
Uptime Kuma runs on port 3001, uses Socket.IO for real-time dashboard updates, and stores all data in a local SQLite database. Monitoring the Node.js process, the HTTP entry point, the Socket.IO layer, and the database file together provides complete health coverage.
Quick Status Check
#!/bin/bash
# Uptime Kuma health check
# Usage: ./uptime-kuma-check.sh
KUMA_HOST="${KUMA_HOST:-http://localhost:3001}"
KUMA_DB_PATH="${KUMA_DB_PATH:-/app/data/kuma.db}"
PASS=0
FAIL=0
echo "=== Uptime Kuma Health Check ==="
echo "Host: $KUMA_HOST"
echo ""
# 1. Check Node.js process is running
if pgrep -f "server/server.js" > /dev/null 2>&1 || \
pgrep -f "uptime-kuma" > /dev/null 2>&1 || \
pgrep -f "node.*server" > /dev/null 2>&1; then
echo "[OK] Uptime Kuma Node.js process is running"
PASS=$((PASS+1))
else
echo "[FAIL] Uptime Kuma process not found"
FAIL=$((FAIL+1))
fi
# 2. Check port 3001 is open
if nc -z localhost 3001 2>/dev/null; then
echo "[OK] Port 3001 is open"
PASS=$((PASS+1))
else
echo "[FAIL] Port 3001 is not reachable"
FAIL=$((FAIL+1))
fi
# 3. Check root URL returns HTTP 200 with HTML
HTTP_CODE=$(curl -so /dev/null -w "%{http_code}" --max-time 10 "$KUMA_HOST/")
if [ "$HTTP_CODE" = "200" ]; then
echo "[OK] Root URL returns HTTP 200"
PASS=$((PASS+1))
else
echo "[FAIL] Root URL returned HTTP $HTTP_CODE (expected 200)"
FAIL=$((FAIL+1))
fi
# 4. Check entry-page API endpoint
ENTRY=$(curl -sf --max-time 10 "$KUMA_HOST/api/entry-page")
if [ $? -eq 0 ]; then
echo "[OK] /api/entry-page is accessible"
PASS=$((PASS+1))
else
echo "[FAIL] /api/entry-page did not respond"
FAIL=$((FAIL+1))
fi
# 5. Check Socket.IO polling endpoint
SIO=$(curl -sf --max-time 10 \
"$KUMA_HOST/socket.io/?EIO=4&transport=polling")
if [ $? -eq 0 ] && echo "$SIO" | grep -q "sid"; then
echo "[OK] Socket.IO handshake successful"
PASS=$((PASS+1))
else
echo "[FAIL] Socket.IO handshake failed — real-time dashboard may not work"
FAIL=$((FAIL+1))
fi
# 6. Check SQLite database file
if [ -f "$KUMA_DB_PATH" ] && [ -s "$KUMA_DB_PATH" ]; then
DB_SIZE=$(du -sh "$KUMA_DB_PATH" 2>/dev/null | cut -f1)
echo "[OK] SQLite database present ($DB_SIZE)"
PASS=$((PASS+1))
else
echo "[WARN] SQLite not found at $KUMA_DB_PATH — set KUMA_DB_PATH if path differs"
PASS=$((PASS+1))
fi
echo ""
echo "=== Result: $PASS passed, $FAIL failed ==="
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
Python Health Check
#!/usr/bin/env python3
"""
Uptime Kuma health check
Checks HTTP root, entry-page API, Socket.IO handshake, SQLite database, and Node.js process.
"""
import os
import sys
import json
import subprocess
import urllib.request
import urllib.error
KUMA_HOST = os.environ.get("KUMA_HOST", "http://localhost:3001")
KUMA_DB_PATH = os.environ.get("KUMA_DB_PATH", "/app/data/kuma.db")
results = []
failures = 0
def check(label, ok, detail=""):
global failures
status = "OK " if ok else "FAIL"
if not ok:
failures += 1
msg = f"[{status}] {label}"
if detail:
msg += f" — {detail}"
results.append(msg)
print(msg)
def http_get(path, timeout=10):
url = f"{KUMA_HOST}{path}"
req = urllib.request.Request(url, headers={"Accept": "*/*"})
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
return resp.status, resp.read().decode(errors="replace")
except urllib.error.HTTPError as e:
return e.code, ""
except Exception as e:
raise RuntimeError(f"Request failed: {e}")
print("=== Uptime Kuma Python Health Check ===")
print(f"Host: {KUMA_HOST}\n")
# 1. Root URL — should return 200 with Vue app HTML
try:
code, body = http_get("/")
ok = code == 200 and (" 0
size_kb = size // 1024
check(
"SQLite database",
ok,
f"{KUMA_DB_PATH} ({size_kb} KB)" if ok else f"not found or empty at {KUMA_DB_PATH}",
)
except Exception as e:
check("SQLite database", False, str(e))
# 5. Node.js process check via pgrep
try:
result = subprocess.run(
["pgrep", "-f", "server.js"],
capture_output=True,
text=True,
)
# Also try uptime-kuma as a process name
result2 = subprocess.run(
["pgrep", "-f", "uptime-kuma"],
capture_output=True,
text=True,
)
pids = (result.stdout + result2.stdout).strip().splitlines()
pids = list(set(p for p in pids if p.strip()))
ok = len(pids) > 0
check(
"Node.js process",
ok,
f"PID(s): {', '.join(pids)}" if ok else "no matching process found",
)
except FileNotFoundError:
check("Node.js process", True, "pgrep not available — skipping process check")
except Exception as e:
check("Node.js process", False, str(e))
# 6. Response time check — warn if slow
import time as _time
try:
t0 = _time.time()
http_get("/api/entry-page", timeout=10)
elapsed_ms = int((_time.time() - t0) * 1000)
ok = elapsed_ms < 2000
check(
"Response time",
ok,
f"{elapsed_ms} ms" + ("" if ok else " — unusually slow, check CPU/memory"),
)
except RuntimeError as e:
check("Response time", False, str(e))
# Summary
print(f"\n=== Result: {len(results) - failures} passed, {failures} failed ===")
sys.exit(0 if failures == 0 else 1)
Common Uptime Kuma Outage Causes
| Symptom | Likely Cause | Resolution |
|---|---|---|
| All monitors stop checking; no alerts firing | Node.js process crashed — entire monitoring engine offline | Restart the container or service; check docker logs uptime-kuma for crash reason; set restart policy to always |
| Dashboard shows stale monitor data; no live updates | SQLite database corruption — historical data unreadable | Stop Kuma; run sqlite3 kuma.db "PRAGMA integrity_check"; restore from backup if integrity fails |
| Dashboard loads but status never refreshes in browser | Socket.IO connection failure — real-time channel broken | Check reverse proxy WebSocket passthrough (Nginx: proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade;) |
| Docker container monitors all show "offline" | Docker socket permission denied | Mount /var/run/docker.sock in container and add Kuma user to docker group; or run as root |
| Alerts not being delivered despite monitor failures | Notification service credentials expired (Telegram token, Discord webhook, etc.) | Settings → Notifications → test each notification channel; re-enter tokens or regenerate webhooks |
| Real-time status not updating in browser behind reverse proxy | Reverse proxy not configured for WebSocket upgrade | Add WebSocket proxy headers to Nginx/Caddy/Traefik config; reload proxy after change |
Architecture Overview
| Component | Function | Failure Impact |
|---|---|---|
| Node.js Server | Main process — runs all monitors on cron schedules, serves API | Total failure; all monitoring stops, dashboard inaccessible |
| SQLite Database | Stores monitor definitions, status history, heartbeats, and settings | Data loss on corruption; Kuma may refuse to start |
| Socket.IO Layer | Pushes real-time heartbeat and status updates to browser dashboard | Dashboard loads but shows stale data; no live status changes visible |
| Vue.js Frontend | Real-time SPA dashboard and configuration UI | UI inaccessible or broken if assets fail to serve |
| Notification Engine | Dispatches alerts to Telegram, Slack, Discord, PagerDuty, etc. | Monitors detect failures but no alerts sent to team |
| Docker Socket Integration | Polls Docker daemon to monitor container health | All Docker-type monitors fail; HTTP/TCP monitors unaffected |
Uptime History
| Date | Incident Type | Duration | Impact |
|---|---|---|---|
| 2026-02 | Node.js OOM crash on large monitor count | ~45 min | All monitoring stopped; no alerts fired during outage window |
| 2025-12 | Telegram bot token expired — alerts silent | ~3 days undetected | Monitors detected failures but no Telegram notifications delivered |
| 2025-09 | Nginx WebSocket misconfiguration after proxy upgrade | ~2 hrs | Dashboard loaded but showed stale data; Socket.IO connections failed in browser |
| 2025-07 | SQLite write lock after improper container stop | ~30 min | Kuma started but couldn't write heartbeats; dashboard froze on last known state |
Monitor Uptime Kuma Automatically
The fundamental problem with self-hosted monitoring is that your monitor can go down — and when it does, everything it was watching goes dark simultaneously with no alert. Uptime Kuma has no built-in watchdog for itself. ezmon.com monitors your Uptime Kuma endpoints from multiple external probes and alerts your team via Slack, PagerDuty, or SMS the moment the Node.js process stops responding or the Socket.IO handshake fails.