Jesse A. Green / notebook

Uptime Kuma Administrator & Developer Guide

Generated May 2026 from louislam/uptime-kuma at 43b143c

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide covers the full operational surface of Uptime Kuma 2.2.1 for administrators, SREs, security engineers, and developers who deploy, scale, secure, and extend the platform. Every fact is derived from source code at commit 43b143c (2026-04-17).

Note

Uptime Kuma 2.x introduces a knex-based database abstraction layer supporting both SQLite and MariaDB, a plugin-based monitor-type system, and a restructured migration pipeline. This guide documents 2.x behavior exclusively unless a section explicitly references 1.x.

1. Architecture Overview

1.1 High-Level Topology

Uptime Kuma runs as a single Node.js process serving both an Express HTTP(S) server and a Socket.IO WebSocket gateway on the same port (default 3001). The Vue 3 SPA frontend is compiled by Vite and served as static assets by Express.

Client Browser
    │
    ▼ HTTP + Socket.IO (WSS)
┌──────────────────────────────────────────────────────────────────┐
│  Express App  (server/server.js)                                 │
│  ├── Static file serving (Vue 3 SPA, compiled by Vite)           │
│  ├── API Router (server/routers/api-router.js)                   │
│  │   ├── /api/push/:pushToken          Push monitor receiver     │
│  │   ├── /api/entry-page               Landing page config       │
│  │   └── /api/badge/:id/*              SVG badge endpoints       │
│  ├── Status Page Router (server/routers/status-page-router.js)   │
│  │   ├── /status/:slug                 Public status page        │
│  │   ├── /status/:slug/rss             RSS feed                  │
│  │   └── /api/status-page/:slug/*      Status page API           │
│  ├── /metrics                          Prometheus scrape target  │
│  └── Socket.IO Server                                            │
│      └── 10 Socket Handlers                                      │
│          ├── general-socket-handler     Auth, monitors, settings  │
│          ├── maintenance-socket-handler Maintenance windows       │
│          ├── status-page-socket-handler Status page CRUD          │
│          ├── cloudflared-socket-handler Tunnel management         │
│          ├── docker-socket-handler      Docker host management    │
│          ├── proxy-socket-handler       Proxy CRUD                │
│          ├── database-socket-handler    DB info, shrink, migrate  │
│          ├── remote-browser-socket-handler Playwright browsers    │
│          ├── api-key-socket-handler     API key management        │
│          └── chart-socket-handler       Chart data retrieval      │
├──────────────────────────────────────────────────────────────────┤
│  Monitor Engine                                                   │
│  ├── Monitor model (server/model/monitor.js) — heartbeat loop     │
│  ├── 23 MonitorType plugins (server/monitor-types/*.js)           │
│  ├── Monitor Conditions evaluator (server/monitor-conditions/)    │
│  └── UptimeCalculator (server/uptime-calculator.js) — stats       │
├──────────────────────────────────────────────────────────────────┤
│  Notification System                                              │
│  ├── Dispatcher (server/notification.js)                          │
│  └── 93 NotificationProvider subclasses                           │
├──────────────────────────────────────────────────────────────────┤
│  Database Layer                                                   │
│  ├── Database (server/database.js) — SQLite or MariaDB via knex   │
│  ├── 48 knex migrations (db/knex_migrations/)                     │
│  └── 13 ORM models (server/model/) via redbean-node               │
├──────────────────────────────────────────────────────────────────┤
│  Background Jobs                                                  │
│  ├── clear-old-data.js — prune heartbeat history                  │
│  └── incremental-vacuum.js — SQLite PRAGMA incremental_vacuum     │
├──────────────────────────────────────────────────────────────────┤
│  Singleton Lifecycle: UptimeKumaServer (server/uptime-kuma-server)│
│  Graceful Shutdown: http-graceful-shutdown (30s timeout)           │
│  Signals: SIGINT, SIGTERM                                         │
└──────────────────────────────────────────────────────────────────┘
         │
         ▼
   SQLite (default) or MariaDB
   DATA_DIR/kuma.db  or  remote MariaDB instance

Note

Socket.IO is the primary API surface, not REST. The REST endpoints are limited to badge generation, push monitor ingestion, status pages, metrics, and setup info. All monitor CRUD, settings management, authentication, and real-time data flow happen over Socket.IO events.

1.2 Request Flow

  1. HTTP requests hit Express middleware (rate limiting, CORS, security headers, static file serving).
  2. Badge and push endpoints are handled by api-router.js without authentication (public).
  3. Status page requests are handled by status-page-router.js (public, with 5-minute cache on badges).
  4. /metrics requires HTTP Basic Auth against the Uptime Kuma user credentials.
  5. All other operations flow through Socket.IO: the client connects, authenticates via login or loginByToken, and then emits events for every action.

1.3 Singleton Pattern

UptimeKumaServer (server/uptime-kuma-server.js) is the application singleton. It owns:

  • The Express app and HTTP(S) server instances
  • The Socket.IO server
  • The monitor map (all active monitors keyed by ID)
  • Cloudflared tunnel process
  • Background job scheduler
  • Graceful shutdown orchestration

All socket handlers and models access this singleton to coordinate state.

1.4 Database Architecture

The database layer (server/database.js) abstracts SQLite and MariaDB behind knex. The ORM layer uses redbean-node for model access.

Tables (23 total, defined in db/knex_init_db.js):

Table Purpose
user Admin accounts (single-user or multi-user)
monitor Monitor definitions and configuration
heartbeat Individual check results with status, ping, message
incident Status page incidents
maintenance Maintenance windows with scheduling
status_page Public status page definitions
group Monitor groups for status pages
proxy HTTP/SOCKS proxy definitions
docker_host Docker daemon connections
api_key API keys with expiry dates
tag Tags for monitor organization
monitor_tag Many-to-many: monitors ↔ tags
monitor_notification Many-to-many: monitors ↔ notification channels
notification Notification channel definitions (provider + config JSON)
setting Key-value settings store
notification_sent_history Deduplication for notification delivery
domain_expiry Cached domain/TLS expiry data
remote_browser Remote Playwright browser connections
maintenance_timeslot Computed maintenance time ranges
monitor_maintenance Many-to-many: monitors ↔ maintenance windows
stat_minutely Aggregated per-minute statistics
stat_hourly Aggregated per-hour statistics
stat_daily Aggregated per-day statistics

Migration system: 48 migration files in db/knex_migrations/ run sequentially on startup. The knex_migrations and knex_migrations_lock meta-tables track state. Set SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE=1 to force the aggregate-table migration if it was interrupted.

2. System Requirements

2.1 Runtime

Component Requirement
Node.js >= 20.4.0. Explicitly blocked: all versions below 18, and 20.0.0 through 20.3.x
npm Bundled with Node.js
Operating System Linux (recommended), macOS, Windows (with caveats for ping and system service monitors)
Architecture amd64, arm64, armv7 (Docker multi-arch)
Memory ~150 MB base + ~1 MB per active monitor (SQLite); MariaDB adds its own footprint
Disk SQLite database grows with heartbeat retention; plan 1-5 GB for 100+ monitors over months

Important

The Node.js version check in server/server.js calls process.exit(1) immediately if the runtime is below 18 or falls in the 20.0.x-20.3.x range. These versions have known bugs affecting SQLite bindings and DNS resolution. There is no override.

2.2 Optional Dependencies

Feature Dependency
Ping monitors System ping command (or ping6 for IPv6)
Chromium/Real Browser monitors Playwright-compatible Chromium install, or remote browser via remote_browser table
Game server monitors gamedig npm package (bundled)
RADIUS monitors node-radius-client (bundled)
SIP monitors sipsak system binary
System service monitors systemctl (Linux only)
SNMP monitors net-snmp (bundled)
Embedded MariaDB UPTIME_KUMA_ENABLE_EMBEDDED_MARIADB=1 (downloads and manages a local MariaDB instance)
Cloudflare Tunnel node-cloudflared-tunnel (bundled), no external binary needed

2.3 Database Backend Selection

Backend When to Use
SQLite (default) Single-instance deployments. Zero config. File-based at DATA_DIR/kuma.db. WAL mode enabled.
MariaDB Multi-instance setups (future HA), large-scale deployments, or when you need a centralized DB. Set via UPTIME_KUMA_DB_TYPE=mariadb.

Warning

PostgreSQL and MySQL (non-MariaDB) are not supported. The knex configuration in server/setup-database.js only handles sqlite and mariadb client types. Passing an unsupported UPTIME_KUMA_DB_TYPE value causes a startup crash.

3. Configuration Reference

3.1 Environment Variables — Complete Reference

All configuration is done through environment variables. There is no configuration file. Variables are read at startup; changes require a restart.

Server & Network

Variable Default Description
UPTIME_KUMA_PORT 3001 HTTP(S) listen port
UPTIME_KUMA_HOST / HOST 0.0.0.0 Bind address
UPTIME_KUMA_SSL_KEY / SSL_KEY (none) Path to TLS private key file (enables HTTPS)
UPTIME_KUMA_SSL_CERT / SSL_CERT (none) Path to TLS certificate file
UPTIME_KUMA_SSL_KEY_PASSPHRASE / SSL_KEY_PASSPHRASE (none) Passphrase for encrypted TLS key
UPTIME_KUMA_WS_ORIGIN_CHECK cors-like WebSocket origin validation mode. Options: cors-like (default, checks Origin header against server URL), bypass (disables check)
UPTIME_KUMA_DISABLE_FRAME_SAMEORIGIN (unset) When set, removes X-Frame-Options: SAMEORIGIN header (required for embedding in iframes)

Database

Variable Default Description
DATA_DIR ./data/ Directory for SQLite database, TLS certs, and uploaded assets
UPTIME_KUMA_DB_TYPE sqlite Database backend: sqlite or mariadb
UPTIME_KUMA_DB_HOSTNAME (none) MariaDB hostname
UPTIME_KUMA_DB_PORT (none) MariaDB port
UPTIME_KUMA_DB_NAME (none) MariaDB database name
UPTIME_KUMA_DB_SOCKET (none) MariaDB Unix socket path (alternative to host:port)
UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS (knex default) Maximum connections in the knex connection pool
UPTIME_KUMA_ENABLE_EMBEDDED_MARIADB (unset) Enable embedded MariaDB server (downloads and manages a local instance)
SQL_LOG (unset) Enable SQL query logging to stdout
SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE (unset) Force the aggregate table migration to re-run (recovery from interrupted migration)

Important

When using MariaDB, all four connection variables (DB_HOSTNAME, DB_PORT, DB_NAME, and either DB_SOCKET or host+port) must be set. The knex client is mysql2 under the hood — connection strings are not supported, only discrete parameters.

Tunnel & Remote Access

Variable Default Description
UPTIME_KUMA_CLOUDFLARED_TOKEN (none) Pre-configured Cloudflare Tunnel token for automatic tunnel startup
UPTIME_KUMA_IS_CONTAINER (auto-detected) Indicates container environment; affects Cloudflared binary path resolution

Monitoring & Debugging

Variable Default Description
UPTIME_KUMA_LOG_FORMAT default Log output format. Used in src/util.js
UPTIME_KUMA_HIDE_LOG (none) Comma-separated log tags to suppress (test usage)
UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID (none) Monitor ID whose HTTP response bodies should be logged (debug only)
UPTIME_KUMA_ALLOW_ALL_CHROME_EXEC (unset) Allow custom Chromium executable paths for Real Browser monitors (security risk)
TIMELOGGER (unset) Enable performance timing logs in server/util-server.js
DEBUG (unset) Enable debug output for the API cache module

Runtime

Variable Default Description
NODE_ENV production Node.js environment. Set to development for Vite dev server proxying
NODE_TLS_REJECT_UNAUTHORIZED 1 Set to 0 to disable TLS certificate verification globally (not recommended)
TZ (system) Timezone for the process. Read by server/uptime-kuma-server.js for display
NOTIFICATION_PROXY / notification_proxy (none) HTTP(S)/SOCKS proxy URL for all outbound notification requests

3.2 In-App Settings (stored in setting table)

Beyond environment variables, many operational settings are stored in the setting key-value table and managed via the Socket.IO setSettings event. These include:

  • keepDataPeriodDays — Heartbeat retention period in days. The clear-old-data background job uses this to prune old heartbeats.
  • entryPage — Default landing page: dashboard or a status page slug.
  • searchEngineIndex — Whether to allow search engine indexing (controls robots.txt).
  • primaryBaseURL — Base URL for badge and status page links.
  • steamAPIKey — API key for Steam game server monitoring via GameDig.
  • dnsCache — Enable/disable DNS result caching.
  • tlsExpiryNotifyDays — Days before TLS certificate expiry to trigger alerts.
  • trustProxy — Whether Express should trust X-Forwarded-* headers (required behind reverse proxies).
  • checkUpdate — Enable update check notifications.

Tip

The trustProxy setting is critical when running behind a reverse proxy (nginx, Traefik, Caddy). Without it, rate limiting and IP-based features see the proxy's IP instead of the client's. Set it via Settings > General in the UI or via the setSettings Socket.IO event.

3.3 Monitor Configuration Schema

The monitor table has 60+ columns. Key configuration fields per monitor:

Column Type Default Description
type string — Monitor type identifier (e.g., http, ping, dns, docker, push, mqtt)
active boolean 1 Whether the monitor is running
interval integer 20 Check interval in seconds
retry_interval integer 0 Seconds between retries on failure (0 = same as interval)
maxretries integer 0 Number of retries before marking down
upside_down boolean 0 Invert status logic (UP becomes DOWN)
url string — Target URL for HTTP/keyword/JSON monitors
hostname string — Target hostname for TCP/ping/DNS/SMTP monitors
port integer — Target port
keyword string — Expected keyword in response body
method string GET HTTP method
body text — HTTP request body
headers text — HTTP request headers (JSON)
basic_auth_user string — HTTP Basic Auth username
basic_auth_pass string — HTTP Basic Auth password
accepted_statuscodes_json text ["200-299"] JSON array of accepted HTTP status codes/ranges
maxredirects integer 10 Maximum HTTP redirects to follow
ignore_tls boolean 0 Skip TLS certificate verification for this monitor
proxy_id FK — Proxy to route checks through
docker_host FK — Docker host for container monitors
docker_container string — Docker container name/ID
dns_resolve_type string — DNS record type (A, AAAA, CNAME, MX, NS, PTR, SOA, SRV, TXT, CAA)
dns_resolve_server string — Custom DNS server for resolution
push_token string — Unique token for push-type monitors
conditions text — JSON condition expressions for conditional alerting
resend_interval integer 0 Seconds between re-sending notifications while down
packet_size integer 56 Ping packet size in bytes
ip_family string — Force IPv4 or IPv6
mqtt_* various — MQTT-specific fields (topic, username, password, success message)
database_* various — Database monitor fields (connection string, query)
grpc_* various — gRPC fields (URL, metadata, body, method, service name, enable TLS)
radius_* various — RADIUS fields (username, password, secret, called/calling station)
oauth_* various — OAuth2 fields (client_id, client_secret, token_url, scopes, auth_method)
tls_ca / tls_cert / tls_key text — Client TLS certificate material
snmp_* various — SNMP fields (OID, community, version, auth/priv protocol)
rabbitmq_* various — RabbitMQ node health fields
kafka_* various — Kafka producer fields (brokers, topic, message, SASL, TLS)
game string — Game identifier for GameDig monitors
manual_status integer — Current status for Manual monitor type
system_service_name string — systemd service name
ping_numeric boolean — Use numeric output for ping
ping_count integer — Number of ping packets per check
ping_per_request_timeout integer — Ping timeout per packet

Validation Constraints

Monitor.validate() enforces these constraints before save:

  • interval: bounded by MIN_INTERVAL_SECOND to MAX_INTERVAL_SECOND
  • retry_interval: same bounds as interval
  • Response body max length: 0 to RESPONSE_BODY_LENGTH_MAX bytes
  • Screenshot delay (Real Browser): must be non-negative, less than 0.8x timeout, and less than 0.5x interval
  • JSON fields (kafkaProducerBrokers, kafkaProducerSaslOptions, rabbitmqNodes, conditions, headers, accepted_statuscodes): validated as parseable JSON

4. Deployment & Scaling

The official Dockerfile is at docker/dockerfile. Multi-arch builds support linux/amd64, linux/arm64, and linux/arm/v7.

docker run -d \
  --name uptime-kuma \
  --restart=unless-stopped \
  -p 3001:3001 \
  -v uptime-kuma-data:/app/data \
  louislam/uptime-kuma:2

With SSL termination:

docker run -d \
  --name uptime-kuma \
  --restart=unless-stopped \
  -p 3001:3001 \
  -v uptime-kuma-data:/app/data \
  -v /path/to/certs:/certs:ro \
  -e UPTIME_KUMA_SSL_KEY=/certs/privkey.pem \
  -e UPTIME_KUMA_SSL_CERT=/certs/fullchain.pem \
  louislam/uptime-kuma:2

With MariaDB backend:

docker run -d \
  --name uptime-kuma \
  --restart=unless-stopped \
  -p 3001:3001 \
  -v uptime-kuma-data:/app/data \
  -e UPTIME_KUMA_DB_TYPE=mariadb \
  -e UPTIME_KUMA_DB_HOSTNAME=mariadb-host \
  -e UPTIME_KUMA_DB_PORT=3306 \
  -e UPTIME_KUMA_DB_NAME=uptime_kuma \
  louislam/uptime-kuma:2

Development compose (docker/docker-compose-dev.yml):

services:
  uptime-kuma:
    build:
      context: ..
      dockerfile: docker/dockerfile
    ports:
      - "3001:3001"
    volumes:
      - ./data:/app/data

Docker Healthcheck

The container includes a compiled Go binary at extra/healthcheck.go that performs an HTTP GET to the configured host and port. It reads UPTIME_KUMA_HOST, UPTIME_KUMA_PORT, and SSL variables to construct the health URL. The Dockerfile's HEALTHCHECK directive calls this binary.

4.2 Bare-Metal Deployment

git clone https://github.com/louislam/uptime-kuma.git
cd uptime-kuma
npm run setup
# Installs production deps, builds frontend, sets up DB

node server/server.js
# Or use a process manager:
pm2 start server/server.js --name uptime-kuma

Tip

For production bare-metal, use pm2 or systemd to manage the process. The application handles SIGINT and SIGTERM for graceful shutdown (30-second timeout via http-graceful-shutdown), so both process managers can stop it cleanly.

4.3 Reverse Proxy Configuration

Uptime Kuma requires WebSocket support from any reverse proxy. The critical path is the Socket.IO transport upgrade from HTTP to WebSocket.

nginx example:

server {
    listen 443 ssl http2;
    server_name status.example.com;

    ssl_certificate     /etc/letsencrypt/live/status.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/status.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Warning

Uptime Kuma does not support running under a subdirectory path (e.g., example.com/uptime/). It must be served at the root of its hostname. See GitHub issue #7279. The Express static file serving and Vue router both assume root-level mounting.

Traefik labels (Docker Compose):

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.uptime-kuma.rule=Host(`status.example.com`)"
  - "traefik.http.routers.uptime-kuma.entrypoints=websecure"
  - "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
  - "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"

After deploying behind a reverse proxy, enable trustProxy in Settings > General so Express reads X-Forwarded-* headers correctly.

4.4 Cloudflare Tunnel

Uptime Kuma has built-in Cloudflare Tunnel support via node-cloudflared-tunnel. Configuration options:

  1. UI-managed: Go to Settings > Reverse Proxy, enter your Cloudflare Tunnel token. The cloudflared-socket-handler manages the tunnel lifecycle.
  2. Environment variable: Set UPTIME_KUMA_CLOUDFLARED_TOKEN for automatic tunnel startup on boot.

The tunnel process is managed by UptimeKumaServer and is stopped during graceful shutdown.

4.5 Scaling Considerations

Uptime Kuma is architected as a single-instance application. The monitor heartbeat loop, in-memory monitor map, and Socket.IO session state are all process-local.

  • Horizontal scaling is not supported with SQLite. Two instances writing to the same SQLite file will corrupt data.
  • MariaDB enables read replicas but active-active write is not implemented — there is no distributed lock or leader election.
  • Vertical scaling: increase UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS for MariaDB when running hundreds of monitors.

For high availability, the recommended approach is active-passive with shared storage (e.g., a network filesystem for DATA_DIR with SQLite, or a shared MariaDB instance) and an external failover mechanism.

5. Operations

5.1 Startup Sequence

When server/server.js starts:

  1. Node.js version check — exits if below 18 or in 20.0.x-20.3.x range
  2. UptimeKumaServer.getInstance() — singleton initialization
  3. Database setup (server/setup-database.js) — selects SQLite or MariaDB based on UPTIME_KUMA_DB_TYPE
  4. Knex migrations — runs all pending migrations from db/knex_migrations/
  5. Express middleware setup — security headers, rate limiting, CORS, static files
  6. Socket.IO server creation with origin check policy
  7. Socket handler registration — all 10 handlers attach their event listeners
  8. HTTP(S) server starts listening on configured host:port
  9. needSetup check — if no user exists, the UI shows the setup wizard
  10. Background jobs start (clear-old-data, incremental-vacuum)
  11. All active monitors begin their heartbeat loops
  12. Cloudflare tunnel starts if token is configured

5.2 Graceful Shutdown

Shutdown is managed by http-graceful-shutdown with a 30-second timeout. On SIGINT or SIGTERM:

  1. HTTP server stops accepting new connections
  2. All active monitors stop their heartbeat loops
  3. Cloudflare tunnel process is killed
  4. Background jobs are stopped
  5. Database connection is closed
  6. Process exits

Note

If monitors do not stop within the 30-second window, the process force-exits. Long-running checks (Real Browser monitors with high timeouts, slow database monitors) may be interrupted mid-check. The next startup will resume from the last recorded heartbeat.

5.3 Background Jobs

Clear Old Data (server/jobs/clear-old-data.js)

Periodically deletes heartbeat records older than keepDataPeriodDays (configured in Settings). Runs on a timer after startup. Prevents unbounded database growth.

Incremental Vacuum (server/jobs/incremental-vacuum.js)

SQLite-only. Runs PRAGMA incremental_vacuum periodically to reclaim free pages without the full-table lock of VACUUM. Only active when UPTIME_KUMA_DB_TYPE is sqlite.

Tip

For large SQLite databases (multiple GB), the incremental vacuum is far less disruptive than a full VACUUM. If you need to reclaim significant space after a bulk heartbeat purge, you can trigger a full vacuum via the database socket handler's shrink function in the UI (Settings > Info > Shrink Database).

5.4 Backup and Restore

SQLite

The database file is at DATA_DIR/kuma.db (with WAL files kuma.db-wal and kuma.db-shm). To back up:

# Stop Uptime Kuma first for a consistent backup
cp data/kuma.db data/kuma.db.bak
cp data/kuma.db-wal data/kuma.db-wal.bak 2>/dev/null
cp data/kuma.db-shm data/kuma.db-shm.bak 2>/dev/null

For online backup, use the SQLite .backup command or sqlite3 data/kuma.db ".backup 'backup.db'".

The UI also provides an Export function that creates a JSON export of monitors, notifications, and status pages (accessible via Socket.IO exportBackup event).

MariaDB

Use standard mysqldump against the configured database:

mysqldump -h "$UPTIME_KUMA_DB_HOSTNAME" -P "$UPTIME_KUMA_DB_PORT" \
  "$UPTIME_KUMA_DB_NAME" > backup.sql

5.5 Monitoring Uptime Kuma Itself

Prometheus Metrics

The /metrics endpoint (requires HTTP Basic Auth) exposes:

  • Standard Node.js process metrics via prom-client (CPU, memory, event loop lag, GC)
  • HTTP request metrics via prometheus-api-metrics (request count, duration histograms by route)
  • Custom monitor metrics (if configured)

Prometheus scrape config:

scrape_configs:
  - job_name: 'uptime-kuma'
    basic_auth:
      username: '<uptime-kuma-username>'
      password: '<uptime-kuma-password>'
    static_configs:
      - targets: ['status.example.com:3001']

Healthcheck Endpoint

The Go-compiled healthcheck binary (extra/healthcheck.go) performs an HTTP(S) GET to the server. Docker's HEALTHCHECK directive uses this. For external health monitoring:

curl -f http://localhost:3001/api/entry-page || echo "DOWN"

5.6 Log Management

Uptime Kuma logs to stdout/stderr. In Docker, use standard Docker log drivers:

docker logs uptime-kuma --tail 100 -f

Controlling log output:

Variable Effect
UPTIME_KUMA_LOG_FORMAT Changes log output format
UPTIME_KUMA_HIDE_LOG Comma-separated tags to suppress
SQL_LOG Enables SQL query logging (very verbose)
TIMELOGGER Enables performance timing for operations
DEBUG Enables API cache debug output
UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID Logs full HTTP response body for a specific monitor (debug)

Note

There is no built-in log rotation. When running with Docker, configure the Docker logging driver (e.g., json-file with max-size and max-file). For bare-metal deployments, pipe stdout through logrotate or a similar tool.

5.7 Database Maintenance

SQLite WAL Mode

SQLite runs in WAL (Write-Ahead Logging) mode by default. This allows concurrent reads during writes but creates .wal and .shm companion files. Never delete these files while the server is running.

Connection Pool Tuning (MariaDB)

For deployments with hundreds of monitors, each performing checks at different intervals, the connection pool can become a bottleneck. Symptoms include KnexTimeoutError: Knex: Timeout acquiring a connection (see GitHub issues #7260 and #6486).

Increase the pool size:

UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS=20

Migration Recovery

If a migration fails mid-execution (particularly the aggregate table migration referenced in issue #7274), the knex_migrations_lock table may remain locked:

-- Check lock state
SELECT * FROM knex_migrations_lock;

-- Unlock if stuck (only when Uptime Kuma is stopped)
UPDATE knex_migrations_lock SET is_locked = 0;

For the specific convert-float-precision migration failure (issue #6920), check that the database has sufficient disk space and that no other process holds a lock on the database file.

6. Performance

6.1 Monitor Heartbeat Loop

Each active monitor runs an independent setInterval loop in the Node.js event loop. The check sequence per heartbeat:

  1. Resolve proxy (if configured)
  2. Execute the monitor-type-specific check (HTTP request, TCP connect, ping, DNS query, etc.)
  3. Evaluate conditions (if configured)
  4. Record heartbeat to database
  5. Calculate uptime statistics via UptimeCalculator
  6. Emit status update to all connected Socket.IO clients
  7. Trigger notifications if status changed
  8. Sleep until next interval

Performance Impact by Monitor Type

Monitor Type Relative Cost Notes
Ping Low Spawns system ping process
TCP Low Single TCP connect + optional TLS handshake
HTTP(S) Low-Medium Full HTTP request; response body limited by RESPONSE_BODY_LENGTH_MAX
DNS Low Single DNS query via dns.resolve
Push Negligible Passive — waits for incoming HTTP push
Docker Low Docker API call over socket/HTTP
MQTT Medium Establishes MQTT connection, subscribes, waits for message
Database (MySQL/PostgreSQL/etc.) Medium Opens connection, runs query, closes
Real Browser High Launches headless Chromium, navigates page, optional screenshot
GameDig Medium Game-specific protocol query
gRPC Medium gRPC health check or keyword match
SNMP Low Single SNMP GET request

6.2 UptimeCalculator

server/uptime-calculator.js maintains per-monitor statistics in three time granularities:

  • Minutely (stat_minutely): aggregated every minute
  • Hourly (stat_hourly): aggregated every hour
  • Daily (stat_daily): aggregated every day

These aggregations run in the heartbeat loop and write to the database. The calculator also maintains in-memory caches for real-time dashboard updates. For large monitor counts, the aggregation writes can become a database write bottleneck — this is one of the primary drivers for considering MariaDB over SQLite at scale.

6.3 API Response Caching

Badge endpoints (/api/badge/:id/*) use a 5-minute server-side cache (via the apicache module). This prevents badge consumers (GitHub READMEs, status dashboards) from generating excessive database load.

6.4 Tuning Recommendations

Scenario Recommendation
50+ monitors Increase interval for non-critical monitors to 60-300s
Real Browser monitors Use remote browsers (remote_browser table) to offload Chromium from the main process
Large heartbeat tables Set keepDataPeriodDays to limit retention (e.g., 90 or 180 days)
Slow dashboard loads Reduce the number of monitors displayed per status page group
MariaDB latency Place MariaDB on the same host or low-latency network link

7. Security

7.1 Authentication Model

Initial Setup

On first launch with no users in the database, the /setup page is presented. The first user created becomes the admin. After setup, the setup page is disabled (the needSetup Socket.IO event returns false).

Login Flow

  1. Client emits login with username and password
  2. Server verifies password via bcryptjs.compare()
  3. If 2FA is enabled, server responds with tokenRequired: true
  4. Client emits loginByToken or submits TOTP code via verifyToken
  5. Server issues a JWT token (via jsonwebtoken) returned to the client
  6. Client stores token and uses loginByToken for subsequent connections

Two-Factor Authentication (2FA)

TOTP-based 2FA using notp and thirty-two libraries:

  • prepare2FA — generates a TOTP secret and QR code URI
  • save2FA — verifies a TOTP token and persists the secret to the user record
  • disable2FA — removes the TOTP secret after password verification

Caution

There is no recovery code mechanism in the source. If a user loses their 2FA device and cannot produce a valid TOTP code, the only recovery path is direct database modification: clear the twofa_secret and twofa_status columns in the user table. This requires stopping the server and directly editing the SQLite/MariaDB database.

API Key Authentication

API keys are managed via the api-key-socket-handler. Keys are stored in the api_key table with:

  • A hashed key value
  • An optional expiry date
  • An active/inactive flag

API keys authenticate requests to the /metrics endpoint and can be used for push monitor endpoints. They are verified in server/auth.js.

7.2 WebSocket Security

Origin Check

The UPTIME_KUMA_WS_ORIGIN_CHECK variable controls Socket.IO origin validation:

  • cors-like (default): checks that the Origin header matches the server's own URL. Blocks cross-origin WebSocket connections.
  • bypass: disables origin checking entirely. Required in some reverse proxy setups where the origin header is rewritten.

Warning

Setting UPTIME_KUMA_WS_ORIGIN_CHECK=bypass disables CSRF protection for WebSocket connections. Only use this when the reverse proxy enforces origin validation at its layer, or when the deployment is on a trusted internal network.

Frame Protection

The X-Frame-Options: SAMEORIGIN header is set by default, preventing the UI from being embedded in cross-origin iframes (clickjacking protection). Set UPTIME_KUMA_DISABLE_FRAME_SAMEORIGIN to allow embedding.

7.3 Password Security

  • Passwords are hashed with bcryptjs before storage
  • Password changes require the current password (via changePassword Socket.IO event)
  • The /.well-known/change-password endpoint exists for browser password-manager integration

7.4 TLS Configuration

Server-Side TLS

Set UPTIME_KUMA_SSL_KEY and UPTIME_KUMA_SSL_CERT to enable HTTPS directly. The passphrase for encrypted keys is provided via UPTIME_KUMA_SSL_KEY_PASSPHRASE.

Monitor Client TLS

Individual monitors can configure client TLS certificates for mTLS scenarios:

  • tls_ca — Custom CA certificate
  • tls_cert — Client certificate
  • tls_key — Client private key

The ignore_tls flag per monitor disables TLS verification for that specific check.

Warning

Issue #7265 documents a case where a monitor reports UP when TCP connects successfully but TLS negotiation fails. The expected_tls_alert field was added to handle explicit TLS alert expectations, but the default behavior is to report UP on successful TCP connect regardless of TLS state when ignore_tls is true.

7.5 Proxy Support

Proxies are defined in the proxy table and assigned per-monitor via proxy_id. Supported proxy types include HTTP(S) and SOCKS proxies. This allows monitors to check targets through specific network paths or to anonymize the source IP.

The NOTIFICATION_PROXY environment variable sets a global proxy for all outbound notification requests (separate from monitor check proxies).

7.6 Rate Limiting

Express rate limiting middleware is applied to prevent brute-force attacks on the login endpoint and API abuse. The specific rate limits are configured in server/server.js middleware setup.

7.7 Security Headers

The Express app sets standard security headers:

  • X-Frame-Options: SAMEORIGIN (unless disabled)
  • X-Content-Type-Options: nosniff
  • X-XSS-Protection headers
  • Content Security Policy headers appropriate for the SPA

7.8 Notification Security

Notification provider configurations (API keys, webhook URLs, SMTP credentials) are stored as JSON in the notification table's config column. These are only accessible to authenticated users via Socket.IO events.

The notification_sent_history table provides deduplication, preventing notification storms when a monitor flaps between UP and DOWN states.

8. Developer Internals

8.1 Repository Structure

uptime-kuma/
├── server/                          Backend (Node.js + Express)
│   ├── server.js                    Entry point, Express + Socket.IO setup
│   ├── uptime-kuma-server.js        Singleton lifecycle manager
│   ├── database.js                  Database abstraction (SQLite/MariaDB)
│   ├── auth.js                      Authentication middleware
│   ├── notification.js              Notification dispatcher
│   ├── prometheus.js                Prometheus metrics export
│   ├── uptime-calculator.js         Statistics aggregation engine
│   ├── config.js                    SSL and config helpers
│   ├── setup-database.js            DB type selection and connection setup
│   ├── util-server.js               Server-side utilities
│   ├── model/                       ORM models (13 classes)
│   │   ├── monitor.js               Core monitor model + heartbeat loop
│   │   ├── heartbeat.js             Heartbeat data model
│   │   ├── status_page.js           Status page model
│   │   ├── maintenance.js           Maintenance window model
│   │   ├── tag.js                   Tag model
│   │   ├── user.js                  User model
│   │   ├── api_key.js               API key model
│   │   ├── docker_host.js           Docker host model
│   │   ├── domain_expiry.js         Domain expiry tracking
│   │   ├── group.js                 Monitor group model
│   │   ├── incident.js              Incident model
│   │   ├── proxy.js                 Proxy model
│   │   └── remote_browser.js        Remote browser model
│   ├── monitor-types/               Monitor type plugins (23 types)
│   │   ├── dns.js                   DNS resolution monitor
│   │   ├── gamedig.js               Game server monitor
│   │   ├── globalping.js            Globalping API monitor
│   │   ├── group.js                 Group (aggregate) monitor
│   │   ├── grpc.js                  gRPC health/keyword monitor
│   │   ├── manual.js                Manual status monitor
│   │   ├── mongodb.js               MongoDB monitor
│   │   ├── mqtt.js                  MQTT subscribe monitor
│   │   ├── mssql.js                 MSSQL monitor
│   │   ├── mysql.js                 MySQL monitor
│   │   ├── oracledb.js              Oracle DB monitor
│   │   ├── postgres.js              PostgreSQL monitor
│   │   ├── rabbitmq.js              RabbitMQ node health monitor
│   │   ├── real-browser-monitor-type.js  Chromium headless monitor
│   │   ├── redis.js                 Redis monitor
│   │   ├── sip-options.js           SIP OPTIONS monitor
│   │   ├── smtp.js                  SMTP monitor
│   │   ├── snmp.js                  SNMP GET monitor
│   │   ├── system-service.js        systemd service monitor
│   │   ├── tailscale-ping.js        Tailscale DERP ping monitor
│   │   ├── tcp.js                   TCP/TLS monitor
│   │   └── websocket-upgrade.js     WebSocket upgrade monitor
│   ├── monitor-conditions/          Condition evaluation system
│   │   ├── evaluator.js             Expression group evaluator
│   │   ├── expression.js            Single condition expression
│   │   └── operators/               16 operator implementations
│   ├── notification-providers/      93 notification provider plugins
│   ├── socket-handlers/             10 Socket.IO event handler modules
│   ├── jobs/                        Background job definitions
│   ├── routers/                     Express route handlers
│   ├── modules/                     Vendored/modified modules (apicache)
│   └── analytics/                   Analytics integration (GA, Matomo, Plausible, Umami)
├── src/                             Frontend (Vue 3 SPA)
│   ├── main.js                      Vue app entry point
│   ├── App.vue                      Root component
│   ├── components/                  Vue components
│   ├── pages/                       Page-level Vue components
│   ├── mixins/                      Vue mixins (socket, theme, mobile)
│   ├── router.js                    Vue Router configuration
│   ├── util.js                      Shared utilities (also used by backend)
│   └── languages/                   77 i18n locale files
├── db/
│   ├── knex_init_db.js              Schema definitions (23 tables)
│   └── knex_migrations/             48 migration files
├── docker/
│   ├── dockerfile                   Production Dockerfile
│   ├── docker-compose-dev.yml       Dev compose
│   ├── debian-base.dockerfile       Base image
│   └── builder-go.dockerfile        Go healthcheck builder
├── extra/
│   ├── healthcheck.go               Docker healthcheck binary
│   ├── healthcheck.js               Node.js healthcheck (legacy)
│   └── push-examples/               Push monitor integration examples
├── config/
│   └── vite.config.js               Vite build configuration
└── test/                            Test suite
    └── backend-test/                Backend tests + e2e (Playwright)

8.2 Model Layer (redbean-node ORM)

All 13 models extend the redbean-node Bean class. The Monitor model is by far the most complex, containing:

  • The heartbeat loop (start() method) — an async loop that calls the appropriate MonitorType.check() and records results
  • validate() — comprehensive input validation
  • Status transition logic (UP/DOWN/PENDING/MAINTENANCE)
  • Notification dispatch on state changes
  • Certificate expiry tracking for TLS monitors

8.3 Monitor Type Plugin System

Each monitor type extends the MonitorType base class and implements:

class MyMonitorType extends MonitorType {
    name = "my-type";          // Unique identifier
    supportsConditions = true; // Whether conditions system applies

    /**
     * @param {Monitor} monitor - The monitor instance
     * @param {Heartbeat} heartbeat - The heartbeat to populate
     * @param {object} tlsInfo - TLS certificate info (if applicable)
     * @returns {Promise<void>}
     */
    async check(monitor, heartbeat, tlsInfo) {
        // Perform the check
        // Set heartbeat.status (UP=1, DOWN=0)
        // Set heartbeat.msg (status message)
        // Set heartbeat.ping (response time in ms)
    }

    // Optional: declare condition variables for the conditions system
    get conditionVariables() {
        return [
            { id: "response_body", name: "Response Body", type: "string" },
            { id: "status_code", name: "Status Code", type: "number" },
        ];
    }
}

Built-in types (handled directly in Monitor.check() without a separate class): HTTP(S), Keyword, JSON Query, Ping, Docker Container, Push, TLS Certificate.

Plugin types (23 classes in server/monitor-types/):

Type Class Key Behavior
dns DnsMonitorType Resolves DNS records (A/AAAA/CNAME/MX/NS/PTR/SOA/SRV/TXT/CAA), compares against expected value
gamedig GameDigMonitorType Queries game servers using the gamedig library, reports player count
globalping GlobalpingMonitorType Runs measurements via the Globalping API from distributed probes
group GroupMonitorType Aggregates status of child monitors; UP only if all children are UP
grpc GrpcKeywordMonitorType gRPC health check or keyword match in response
manual ManualMonitorType No automatic checks; status set manually via API
mongodb MongodbMonitorType Connects to MongoDB, optionally runs a command/query
mqtt MqttMonitorType Connects to MQTT broker, subscribes to topic, checks for expected message
mssql MssqlMonitorType Connects to Microsoft SQL Server, runs query
mysql MysqlMonitorType Connects to MySQL/MariaDB, runs query
oracledb OracleDbMonitorType Connects to Oracle Database, runs query
postgres PostgresMonitorType Connects to PostgreSQL, runs query
rabbitmq RabbitMqMonitorType Checks RabbitMQ node health via management API
real-browser RealBrowserMonitorType Launches Chromium via Playwright, navigates to URL, optional screenshot
redis RedisMonitorType Connects to Redis, runs PING or custom command
sip-options SIPMonitorType Sends SIP OPTIONS request via sipsak binary
smtp SMTPMonitorType Connects to SMTP server, checks response
snmp SNMPMonitorType SNMP GET (v1/v2c/v3 with auth/priv protocols)
system-service SystemServiceMonitorType Checks systemd service status via systemctl
tailscale-ping TailscalePing Pings a Tailscale node via DERP relay
tcp TCPMonitorType TCP connect with optional TLS upgrade
websocket-upgrade WebSocketMonitorType Checks WebSocket upgrade handshake

8.4 Monitor Conditions System

The conditions system (server/monitor-conditions/) allows monitors to define complex evaluation rules beyond simple UP/DOWN:

Architecture:

  • ConditionExpressionGroup — AND/OR groups of conditions
  • ConditionExpression — single condition: variable operator value
  • 16 operators in server/monitor-conditions/operators/:
Operator Class Behavior
StringEquals / StringNotEquals Exact string comparison
Contains / NotContains Substring match
StartsWith / NotStartsWith Prefix match
EndsWith / NotEndsWith Suffix match
NumberEquals / NumberNotEquals Numeric equality
LessThan / GreaterThan Numeric comparison
LessThanOrEqual / GreaterThanOrEqual Numeric comparison

Each monitor type declares its conditionVariables — the set of runtime values available for condition evaluation. For HTTP monitors, this includes status_code, response_body, response_time. For DNS monitors, resolved_address. Each type exposes the variables relevant to its check results.

8.5 Notification Provider Architecture

All 93 notification providers extend NotificationProvider:

class MyProvider extends NotificationProvider {
    name = "my-provider";

    /**
     * @param {object} notification - Provider config (from notification table)
     * @param {string} msg - Notification message
     * @param {Monitor} monitorJSON - Monitor data
     * @param {Heartbeat} heartbeatJSON - Heartbeat data
     * @returns {Promise<string>} - Success message
     */
    async send(notification, msg, monitorJSON, heartbeatJSON) {
        // Send the notification
        // Return success message or throw on failure
    }
}

The Notification dispatcher (server/notification.js) manages:

  • Provider registration and lookup
  • Sending notifications to all channels linked to a monitor
  • Notification deduplication via notification_sent_history
  • Error handling — a failing notification provider does not block the monitor loop

Notification requests route through NOTIFICATION_PROXY if set.

Caution

Issue #4058 documents cases where a notification provider timeout can freeze the monitor's heartbeat loop. The notification dispatch runs in the same async context as the heartbeat. If a provider's HTTP request hangs beyond the configured timeout, the monitor's next check is delayed. The resend_interval field mitigates notification storms but does not address provider timeouts.

8.6 Socket.IO Event Reference

Socket.IO is the primary API. All events require authentication (JWT token via loginByToken) unless marked as public.

Authentication Events

Event Direction Parameters Description
login Client → Server username, password, token (2FA) Authenticate with credentials
loginByToken Client → Server token (JWT) Re-authenticate with stored token
logout Client → Server — Invalidate session
needSetup Client → Server — Check if initial setup is required (public)
setup Client → Server username, password Create initial admin account (only when no users exist)

Monitor Management

Event Direction Parameters Description
add Client → Server Monitor config object Create a new monitor
editMonitor Client → Server Monitor config object Update an existing monitor
deleteMonitor Client → Server monitorID Delete a monitor and its heartbeats
getMonitor Client → Server monitorID Get a single monitor's config
getMonitorList Server → Client — Pushed on connection: all monitors
pauseMonitor Client → Server monitorID Stop a monitor's heartbeat loop
resumeMonitor Client → Server monitorID Start a monitor's heartbeat loop

Heartbeat & Statistics

Event Direction Parameters Description
getMonitorBeats Client → Server monitorID, period Get heartbeat history
monitorImportantHeartbeatListCount Client → Server monitorID Count of important heartbeats
monitorImportantHeartbeatListPaged Client → Server monitorID, offset, count Paginated important heartbeats
clearEvents Client → Server monitorID Clear important heartbeats
clearHeartbeats Client → Server monitorID Clear all heartbeats
clearStatistics Client → Server — Clear all statistics
heartbeatList Server → Client monitorID, data, overwrite Pushed: heartbeat data updates
heartbeat Server → Client data Pushed: single new heartbeat
importantHeartbeatList Server → Client monitorID, data, overwrite Pushed: important heartbeat updates

Tags

Event Direction Parameters Description
getTags Client → Server — List all tags
addTag Client → Server tag object Create a tag
editTag Client → Server tag object Update a tag
deleteTag Client → Server tagID Delete a tag
addMonitorTag Client → Server tagID, monitorID, value Link a tag to a monitor
editMonitorTag Client → Server tagID, monitorID, value Update tag-monitor link
deleteMonitorTag Client → Server tagID, monitorID, value Remove tag-monitor link

Notifications

Event Direction Parameters Description
addNotification Client → Server Notification config Create notification channel
deleteNotification Client → Server notificationID Delete notification channel
testNotification Client → Server Notification config Send a test notification
checkApprise Client → Server — Check if Apprise is installed

Settings

Event Direction Parameters Description
getSettings Client → Server — Get all settings
setSettings Client → Server Settings object Update settings
changePassword Client → Server currentPassword, newPassword Change user password

Two-Factor Authentication

Event Direction Parameters Description
prepare2FA Client → Server — Generate 2FA secret and QR URI
save2FA Client → Server token (TOTP code) Verify and save 2FA
disable2FA Client → Server password Disable 2FA
verifyToken Client → Server token, password Verify TOTP during login
twoFAStatus Client → Server — Check 2FA status

Maintenance (via maintenance-socket-handler)

Event Direction Description
addMaintenance Client → Server Create maintenance window
editMaintenance Client → Server Update maintenance window
deleteMaintenance Client → Server Delete maintenance window
getMaintenance Client → Server Get maintenance details
getMaintenanceList Client → Server List all maintenance windows
pauseMaintenance Client → Server Pause a maintenance window
resumeMaintenance Client → Server Resume a maintenance window
getMonitorMaintenance Client → Server Get maintenance for a monitor

Status Page (via status-page-socket-handler)

Event Direction Description
addStatusPage Client → Server Create status page
deleteStatusPage Client → Server Delete status page
saveStatusPage Client → Server Update status page config
getStatusPage Client → Server Get status page details
postIncident Client → Server Create/update incident
unpinIncident Client → Server Remove pinned incident

Docker Host (via docker-socket-handler)

Event Direction Description
addDockerHost Client → Server Add Docker host connection
editDockerHost Client → Server Update Docker host
deleteDockerHost Client → Server Delete Docker host
testDockerHost Client → Server Test Docker host connectivity

Other Handlers

Handler Key Events
proxy-socket-handler addProxy, editProxy, deleteProxy
database-socket-handler getDatabaseSize, shrinkDatabase
cloudflared-socket-handler installCloudflared, startCloudflared, stopCloudflared, checkCloudflared
remote-browser-socket-handler addRemoteBrowser, editRemoteBrowser, deleteRemoteBrowser, testRemoteBrowser
api-key-socket-handler addAPIKey, deleteAPIKey, getAPIKeyList
chart-socket-handler getChartData

8.7 REST API Reference

REST endpoints are secondary to Socket.IO but serve critical public-facing functions.

Method Path Auth Description
GET / None Serves the Vue SPA
GET /setup-database-info None Returns database type info for setup wizard
GET /robots.txt None Dynamic robots.txt based on searchEngineIndex setting
GET /metrics Basic Auth Prometheus metrics scrape endpoint
GET /.well-known/change-password None Redirects to password change (browser integration)
ALL /api/push/:pushToken Push Token Push monitor heartbeat receiver (GET or POST)
GET /api/entry-page None Returns configured landing page
GET /api/badge/:id/status None SVG status badge (5min cache)
GET /api/badge/:id/uptime/:duration? None SVG uptime percentage badge
GET /api/badge/:id/ping/:duration? None SVG average ping badge
GET /api/badge/:id/avg-response/:duration? None SVG average response time badge
GET /api/badge/:id/cert-exp None SVG certificate expiry badge
GET /api/badge/:id/response None SVG latest response time badge
GET /status/:slug None Public status page HTML
GET /status/:slug/rss None Status page RSS feed
GET /status None Status page index
GET /status-page None Status page redirect
GET /api/status-page/:slug None Status page JSON data
GET /api/status-page/heartbeat/:slug None Status page heartbeat data
GET /api/status-page/:slug/manifest.json None PWA manifest for status page
GET /api/status-page/:slug/incident-history None Status page incident history
GET /api/status-page/:slug/badge None Status page aggregate badge

8.8 Frontend Architecture

The frontend is a Vue 3 SPA built with Vite 5.4:

  • Entry: src/main.js → src/App.vue
  • Routing: src/router.js (Vue Router)
  • State: Socket.IO-driven reactivity (no Vuex/Pinia — state lives in the socket connection and component data)
  • Styling: Bootstrap 5.1 with RTL support via PostCSS
  • i18n: vue-i18n with 77 language files in src/languages/
  • Build: vite build compiles to static files served by Express

Analytics Integration

Four analytics providers are supported via server/analytics/:

Provider Integration
Google Analytics Script injection
Matomo Script injection
Plausible Script injection
Umami Script injection

Configured via the UI settings, not environment variables.

8.9 Testing

Type Location Framework
Backend unit/integration test/backend-test/ Custom test runner
End-to-end test/ Playwright
Container tests test/ Testcontainers

Run backend tests:

npm run test-backend

Run e2e tests (requires Playwright browsers installed):

npx playwright test

9. Integration Points

9.1 Push Monitor API

Push monitors provide an inbound heartbeat mechanism for external services. Each push monitor has a unique push_token. External systems call:

# Simple heartbeat (UP)
curl "https://status.example.com/api/push/<push_token>?status=up&msg=OK&ping=50"

# Report DOWN
curl "https://status.example.com/api/push/<push_token>?status=down&msg=Service%20failed"

Parameters:

Parameter Default Description
status up up or down
msg OK Status message
ping (none) Response time in ms

Both GET and POST methods are accepted on the /api/push/:pushToken endpoint.

Push examples for various languages and tools are provided in extra/push-examples/.

9.2 Status Page Embedding

Status pages are publicly accessible at /status/:slug. Each status page supports:

  • Custom title, description, and logo
  • Monitor groups with display ordering
  • Pinned incidents with markdown content
  • Maintenance window display
  • RSS feed at /status/:slug/rss
  • PWA manifest at /api/status-page/:slug/manifest.json
  • Aggregate badge at /api/status-page/:slug/badge

9.3 Badge Integration

Badges are SVG images suitable for GitHub READMEs, dashboards, and documentation:

![Status](https://status.example.com/api/badge/1/status)
![Uptime 30d](https://status.example.com/api/badge/1/uptime/720)
![Ping](https://status.example.com/api/badge/1/ping/24)
![Response](https://status.example.com/api/badge/1/response)
![Cert Expiry](https://status.example.com/api/badge/1/cert-exp)

The :duration parameter is in hours. Badges are cached for 5 minutes server-side.

9.4 Prometheus Integration

The /metrics endpoint exports:

  • Node.js process metrics: CPU usage, memory (RSS, heap), event loop lag, active handles/requests, GC statistics
  • HTTP metrics: Request count by method/route/status, response time histograms, active connections
  • Custom metrics: Available for extension via server/prometheus.js

Authentication is required (HTTP Basic Auth with Uptime Kuma credentials).

9.5 Docker Integration

Docker host connections are stored in the docker_host table. Supported connection methods:

  • Unix socket: /var/run/docker.sock (default for same-host Docker)
  • TCP: tcp://docker-host:2375 (unencrypted)
  • TLS: tcp://docker-host:2376 with TLS certificates

Docker monitors check container status via the Docker API. The docker-socket-handler manages CRUD for host connections.

9.6 Cloudflare Tunnel Integration

The built-in Cloudflare Tunnel support (node-cloudflared-tunnel) provides:

  • Zero-config remote access without port forwarding
  • Managed via the cloudflared-socket-handler (install, start, stop, check status)
  • Automatic startup via UPTIME_KUMA_CLOUDFLARED_TOKEN environment variable
  • Tunnel process lifecycle managed by UptimeKumaServer singleton

9.7 Remote Browser Integration

For Real Browser monitors, Playwright can connect to remote browser instances:

  • Remote browsers are stored in the remote_browser table
  • Connection via WebSocket URL to a Playwright-compatible browser service
  • Managed via remote-browser-socket-handler (add, edit, delete, test)

This offloads the heavy Chromium process from the Uptime Kuma server to dedicated browser infrastructure.

9.8 Notification Provider Categories

The 93 notification providers cover these categories:

Category Examples
Chat/Messaging Slack, Discord, Telegram, Microsoft Teams, Mattermost, Rocket.Chat, Matrix, Google Chat, Line, Feishu, DingTalk, WeChat
Email SMTP, SendGrid, Mailgun
Incident Management PagerDuty, Opsgenie, VictorOps/Splunk On-Call, Squadcast, Incident.io, Grafana OnCall, ZenDuty
Push Notifications Pushover, Pushbullet, Ntfy, Gotify, Bark, SimplePush
Webhooks Generic Webhook, Custom POST, FlashDuty
SMS Twilio, Vonage, SMSEagle, PromoSMS, ClickSend, SMSManager
Status Pages Atlassian Statuspage, Instatus, Sorry
Monitoring Datadog, New Relic, Dynatrace, Better Stack, Sentry
Home Automation Home Assistant, IFTTT, Apprise

9.9 Troubleshooting — Known Issues

Issue Symptom Resolution
#7260 KnexTimeoutError: Timeout acquiring a connection Increase UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS. Reduce concurrent monitor count or increase check intervals.
#6486 KnexTimeoutError: pool full on MariaDB Same as above. Check for long-running queries blocking the pool.
#6920 Migration fails on convert-float-precision Ensure sufficient disk space. Check no other process holds a DB lock. May need manual migration state cleanup.
#7274 Aggregate table migration interrupted, stuck on restart Set SET_MIGRATE_AGGREGATE_TABLE_TO_TRUE=1 to force re-run, or manually unlock knex_migrations_lock.
#7279 Cannot run under a subdirectory path Not supported. Must deploy at the root of a (sub)domain. Use a reverse proxy with a dedicated hostname.
#7265 Monitor shows UP when TCP connects but TLS fails Set ignore_tls=false and configure expected_tls_alert if you need to validate TLS negotiation.
#4058 Notification provider timeout freezes monitor heartbeat No built-in fix. Consider reducing notification provider timeouts at the provider level, or using faster notification channels.
#3574 Ping fails with packet size below 16 bytes Set packet_size to at least 16 (default is 56). Some OS implementations reject very small packets.

Warning

The knex_migrations_lock table can become permanently locked if the process crashes during a migration. Always check SELECT * FROM knex_migrations_lock if Uptime Kuma fails to start after an unexpected shutdown. Unlock with UPDATE knex_migrations_lock SET is_locked = 0 only when no instance is running.

Tip

For debugging monitor check failures, set UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID to the ID of the failing monitor. This logs the full HTTP response body, which is otherwise truncated in heartbeat messages.