louislam/uptime-kuma
A fancy self-hosted monitoring tool
Mixed signals — read the receipts
- ✓Last commit 1d ago
- ✓5 active contributors
- ✓Distributed ownership (top contributor 38%)
- ✓MIT licensed
- ✓CI configured
- ⚠Small team — 5 top contributors
- ⚠No test directory detected
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Embed this verdict
[](https://repopilot.app/r/louislam/uptime-kuma)Paste into your README — the badge live-updates from the latest cached analysis.
Onboarding doc
Onboarding: louislam/uptime-kuma
Generated by RepoPilot · 2026-05-04 · Source
Verdict
WAIT — Mixed signals — read the receipts
- Last commit 1d ago
- 5 active contributors
- Distributed ownership (top contributor 38%)
- MIT licensed
- CI configured
- ⚠ Small team — 5 top contributors
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
TL;DR
Uptime Kuma is a self-hosted monitoring tool built with Node.js (Express + Socket.IO backend) and Vue 3 frontend that monitors HTTP(s), TCP, DNS, Docker containers, and 10+ other protocol types at configurable intervals as low as 20 seconds. It stores heartbeat/uptime data in SQLite via Knex.js and delivers alerts through 90+ notification integrations (Telegram, Slack, PagerDuty, etc.). It solves the problem of needing a Pingdom/UptimeRobot alternative that runs entirely on your own infrastructure. Monolith with clear client/server split: the Node.js backend lives in server/ (Socket.IO event handlers, monitor logic, notification providers), the Vue 3 SPA frontend lives in src/ (components, views, lang/ for i18n), and db/knex_migrations/ handles schema versioning. Vite (config/vite.config.js) builds the frontend, and Playwright (config/playwright.config.js) runs E2E tests.
Who it's for
Self-hosters, DevOps engineers, and sysadmins who want a beautiful, dependency-light uptime monitoring dashboard they can run on a $5 VPS or home server without paying SaaS fees or sending their endpoint data to a third party.
Maturity & risk
Extremely mature: 60k+ GitHub stars, active CI via GitHub Actions (.github/workflows/ has 20+ workflow files including CodeQL, auto-tests, and release pipelines for beta/final/nightly), and the Knex migrations under db/knex_migrations/ show ongoing schema evolution. Verdict: production-ready and actively maintained.
Single primary maintainer (louislam) is a real bus-factor risk — the FUNDING.yml and sponsor links suggest reliance on community funding to sustain development. The mix of JavaScript and Vue with minimal TypeScript (TypeScript is only 24k lines vs 1.4M JS lines) means limited type safety. The SQLite-only persistence model creates scalability limits for high-frequency monitoring at scale.
Active areas of work
Active work is visible in the release workflows (.github/workflows/release-beta.yml, release-nightly.yml) suggesting ongoing versioning cadence. The db/knex_migrations/ directory shows recent schema additions including heartbeat retries (2023-09-29), MQTT query support (2023-10-08), and push token length changes (2023-10-11), indicating active feature development in late 2023.
Get running
git clone https://github.com/louislam/uptime-kuma.git cd uptime-kuma npm install npm run dev
Backend runs on :3001, Vite dev server proxies frontend — open http://localhost:3000
Daily commands: npm run dev # starts both Vite frontend dev server and Node backend concurrently npm run build # production Vite build node server/server.js # run backend standalone (production) docker compose up -d # full Docker deployment via compose.yaml
Map of the codebase
db/knex_init_db.js— Initializes the SQLite database schema and runs all Knex migrations, making it the single source of truth for data model evolution.config/vite.config.js— Controls the Vite build pipeline for the Vue 3 frontend, defining how assets are bundled, aliased, and served in dev/production.config/playwright.config.js— Defines the end-to-end test suite configuration, specifying browsers, base URLs, and test file patterns critical for CI validation.compose.yaml— The canonical Docker Compose definition for running Uptime Kuma, showing all service dependencies, port bindings, and volume mounts.db/knex_migrations/2025-12-22-0121-optimize-important-indexes.js— Adds critical database indexes that directly impact heartbeat query performance at scale — a must-read for understanding DB performance tuning.AGENTS.md— Describes the agentic/automation conventions used in this repo, essential for contributors using AI-assisted development workflows.CONTRIBUTING.md— Defines contribution standards, branch naming, PR requirements, and coding conventions that every contributor must follow.
How to make changes
Add a new monitor type
- Create a new Knex migration file to add any monitor-specific columns to the monitor table (follow existing naming convention YYYY-MM-DD-HHMM-description.js). (
db/knex_migrations/2026-01-16-0000-add-screenshot-delay.js) - Reference the new migration in the DB init sequence so it runs on startup. (
db/knex_init_db.js) - Add a migration for any response/config fields your monitor type needs. (
db/knex_migrations/2025-10-15-0001-add-monitor-response-config.js)
Add a new database migration
- Create a new file in db/knex_migrations/ following the date-based naming convention (YYYY-MM-DD-HHMM-description.js) with up() and down() exports. (
db/knex_migrations/2026-02-07-0000-disable-domain-expiry-unsupported-tlds.js) - Register the migration in the Knex init so it is included in the migration run order. (
db/knex_init_db.js)
Add a new notification channel
- Add any schema changes needed for storing notification-specific config (e.g. tokens, URLs) via a new Knex migration. (
db/knex_migrations/2025-01-01-0000-add-smtp.js) - Update ESLint and code style configs if adding new utility files to ensure consistency. (
.eslintrc.js)
Add a new CI/CD workflow
- Create a new YAML file under .github/workflows/ following the pattern of existing workflows (jobs, triggers, secrets usage). (
.github/workflows/auto-test.yml) - Reference any new workflow in the validation pipeline if it should gate PRs. (
.github/workflows/validate.yml) - Update the exclude list if the new workflow touches files that should not trigger other checks. (
.github/config/exclude.txt)
Why these technologies
- SQLite via Knex.js — Zero-config embedded database perfect for self-hosted single-server deployments; Knex provides migration management and query building without requiring a separate DB process.
- Vue 3 + Vite — Vue 3's Composition API and Vite's fast HMR enable rapid UI development; the reactive model fits well with real-time WebSocket-driven monitoring data.
- Socket.io (WebSockets) — Enables real-time push of heartbeat events and monitor status changes to all connected browser clients without polling, critical for a live monitoring dashboard.
- Docker + Docker Compose — Self-hosted tool requiring simple, reproducible deployment; Docker eliminates environment drift and makes installation a single command for most users.
- Knex Migrations — Provides versioned, repeatable, rollback-capable schema evolution without an ORM, keeping DB changes explicit and auditable in the migration files.
- Playwright — Cross-browser E2E testing of the full monitoring dashboard UI, catching regressions in real browser environments as part of the CI pipeline.
Trade-offs already made
-
SQLite instead of PostgreSQL/MySQL
- Why: Drastically simplifies self-hosted installation — no separate database server to configure or maintain.
- Consequence: Cannot scale horizontally; concurrent write performance degrades under very high heartbeat volumes; no built-in replication.
-
Monolithic Node.js server (backend + WebSocket + static serving)
- Why: Reduces operational complexity for self-hosting; single process to start, monitor, and update.
- Consequence: A crash or memory leak in one subsystem (e.g. a bad monitor check) can affect the entire application including the UI.
-
File-based Knex migrations with manual ordering by date prefix
- Why: Simple, transparent, and Git-friendly; no migration registry service needed.
- Consequence: Date collisions between contributors can cause ordering conflicts; migrations must be carefully coordinated in PRs.
-
WebSocket-first data delivery instead of REST polling
- Why: Provides instant status updates on the dashboard without the latency or overhead of frequent HTTP polling.
- Consequence: Stateful connections require more careful session management; reconnection handling adds frontend complexity.
Non-goals (don't propose these)
- Multi-tenant SaaS hosting with user isolation
- Horizontal scaling across multiple nodes with shared state
- Built-in SSL termination (expected to be handled by a reverse proxy like Nginx/Caddy)
- Enterprise LDAP/SAML authentication (OAuth is supported but full enterprise IdP integration is out of scope)
- Time-series database for long-term metric retention at scale
Traps & gotchas
- The SQLite database file is stored in /app/data inside the container — if you forget to mount a volume (as shown in compose.yaml), all monitor config and history is lost on container restart. 2) NFS mounts for the data directory are explicitly unsupported and will cause corruption. 3) The dev server requires both the Vite frontend process AND the Node backend to be running simultaneously — check that npm run dev starts both via the concurrently package. 4) Node.js version compatibility matters; check .npmrc and the Dockerfile base image for the expected version before running locally.
Architecture
Concepts to learn
- Socket.IO real-time push — The entire Uptime Kuma UI updates live without polling — heartbeat results are pushed from server to browser over Socket.IO WebSocket connections, which is the core architectural pattern you must understand to add new monitor types.
- Knex.js migrations — All SQLite schema changes must be made as versioned migration files in db/knex_migrations/ — understanding the Knex migration lifecycle prevents data loss when deploying schema changes.
- Heartbeat monitoring pattern — Uptime Kuma uses a 'heartbeat' model (db/knex_migrations/2023-08-18-0301-heartbeat.js) where each check result is stored as a discrete event rather than aggregated, enabling the ping history charts and uptime percentage calculations.
- Push monitoring (dead man's switch) — The 'Push' monitor type (seen in the push token migration 2023-10-11) inverts the polling model — your service calls Uptime Kuma's endpoint, so Kuma alerts if it stops hearing from the service, which is essential for monitoring cron jobs.
- Vue 3 Composition API — The frontend is Vue 3 and new UI components in src/components/ should use the Composition API (<script setup>) rather than Options API to match the existing codebase patterns.
- Certificate transparency / TLS cert monitoring — Uptime Kuma exposes SSL certificate expiry info to users, which requires understanding how Node.js TLS socket inspection works to extend or debug HTTPS monitor behavior.
Related repos
louislam/dockge— Another tool by the same author (louislam) for managing Docker Compose stacks, commonly deployed alongside Uptime Kuma.healthchecks/healthchecks— Direct alternative: Django-based self-hosted cron job and uptime monitor solving the same problem in the Python ecosystem.getsentry/sentry— Ecosystem companion for error monitoring — users who self-host Uptime Kuma for uptime often pair it with self-hosted Sentry for error tracking.nicklockwood/SwiftFormat— Unrelated — included in error; replace with: upptime/upptime — GitHub Actions-based uptime monitor, a popular serverless alternative to Uptime Kuma.upptime/upptime— Serverless GitHub Actions-based uptime monitoring alternative that stores data in the repo itself rather than a self-hosted server.
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for the new manual monitor type (db/knex_migrations/2025-06-11-0000-add-manual-monitor.js)
The manual monitor type was recently added (June 2025 migration) but there are no corresponding Playwright or unit tests visible in the file structure. This is a high-value gap because manual monitors have unique behavior (no automatic polling, status set by user/API) that differs from all other monitor types, making it easy for regressions to slip through. The existing Playwright config at config/playwright.config.js provides a foundation to add E2E tests.
- [ ] Review db/knex_migrations/2025-06-11-0000-add-manual-monitor.js to understand the schema changes and what fields were introduced
- [ ] Locate the monitor type handler (likely in server/monitor-types/ or similar) for the manual monitor and identify all code paths
- [ ] Add a Playwright E2E test in the tests/ directory (using config/playwright.config.js) that creates a manual monitor, verifies its initial status, and confirms it does not trigger automatic heartbeats
- [ ] Add a unit test asserting that manually pushing a status update via the API correctly records a heartbeat and updates uptime stats (referencing db/knex_migrations/2023-08-16-0000-create-uptime.js schema)
- [ ] Ensure the new tests run in .github/workflows/auto-test.yml by confirming test file discovery patterns cover the new files
Add a dedicated GitHub Actions workflow for database migration integrity checks
The repo has 25+ Knex migration files spanning 2023–2025, including complex schema changes (conditions, SNMP, RabbitMQ, IP family, custom URL, maintenance last-start). There is no visible workflow in .github/workflows/ that runs migrations from scratch and validates the final schema. A migration integrity workflow would catch issues like the existing fix migrations (2024-10-31-0000-fix-snmp-monitor.js, 2025-03-25-0127-fix-5721.js) before they reach users.
- [ ] Create .github/workflows/migration-check.yml triggered on pull_request when files under db/knex_migrations/** are changed
- [ ] In the workflow, set up Node.js, install dependencies, and run db/knex_init_db.js against a fresh SQLite database to apply all migrations in order
- [ ] Add a step that runs migrations again on the same DB to verify idempotency and that 'already migrated' state is handled cleanly
- [ ] Add a step that rolls back the latest migration (knex migrate:rollback) and re-applies it, ensuring down() functions exist and work for recent migrations
- [ ] Document the workflow purpose in CONTRIBUTING.md under a 'Database Migrations' section so future contributors know to run this locally before submitting migration PRs
Split and add unit tests for the uptime statistics calculation logic introduced across multiple migrations
Several migrations (2023-08-16-0000-create-uptime.js, 2023-12-22-0000-hourly-uptime.js, 2024-01-22-0000-stats-extras.js, 2023-12-21-0000-stat-ping-min-max.js) indicate a growing and evolving uptime/statistics system. If the calculation logic lives in a single large server-side file, it is a refactoring and testing target. Adding focused unit tests for uptime percentage calculation, ping min/max aggregation, and hourly rollup logic would prevent silent stat corruption bugs.
- [ ] Identify the server-side file(s) responsible for uptime calculation and heartbeat aggregation (likely server/uptime-calculator.js or similar) by cross-referencing the migration column names
- [ ] Extract any pure calculation functions (uptime percentage, ping aggregation, hourly rollup) into a standalone module (e.g., server/utils/stats.js) if they are currently embedded in a larger class
- [ ] Write
Good first issues
- Add unit tests for individual notification providers in server/notification-providers/ — most have no test coverage visible in the repo. 2) Several db/knex_migrations files lack comments explaining the 'why' behind schema changes; adding inline documentation would help future contributors. 3) The src/lang/ directory likely has incomplete translations for newer keys in en.json across non-English locale files — a diff-based audit and completion of any language you speak fluently is a direct contribution.
Top contributors
- @louislam — 13 commits
- @github-actions[bot] — 9 commits
- @aindriu80 — 4 commits
- @Aluisio — 4 commits
- @MrEddX — 4 commits
Recent commits
f43087a— chore: update to 2.3.2 (#7347) (github-actions[bot])07b3818— fix: Revert back to single SQLite connection by default (#7346) (louislam)a4030ba— chore: update to 2.3.1 (#7345) (github-actions[bot])9b92fe1— chore: Update dependencies (#7340) (github-actions[bot])8b27ca6— fix(push): use multi-arch Node base in push image Dockerfile (#7344) (herwinz)913105f— fix: Addbusy_timeoutto sqlite to avoid errorSQLITE_BUSY: database is locked(#7307) (wagnerand)9e84e3c— chore: update to 2.3.0 (#7336) (github-actions[bot])f15015f— chore: Translations Update from Weblate (#7292) (louislam)3d19b6d— chore: Update dependencies (#7317) (github-actions[bot])13de229— Translated using Weblate (Chinese (Simplified)) (AnnAngela)
Security observations
- High · SQL Injection Risk via Knex Migrations with Raw Queries —
db/knex_migrations/. The presence of numerous Knex migration files (e.g., altering columns, fixing data types, converting float precision) suggests the codebase uses raw SQL in migrations. If any user-controlled input is interpolated into raw Knex queries (knex.raw()) without parameterization, SQL injection is possible. The migration files referencing fixes (e.g., '2025-03-25-0127-fix-5721.js', '2025-10-15-0000-stat-table-fix.js') suggest reactive patching rather than systematic sanitization. Fix: Audit all knex.raw() calls to ensure parameterized queries are used exclusively. Never interpolate user-supplied data directly into raw SQL strings. Use Knex's built-in query builder methods where possible. - High · Potential XSS via Unescaped Monitor Data Rendering —
config/vite.config.js, frontend Vue components (implied by project structure). Uptime Kuma renders monitor names, URLs, status page content, and notification messages in the frontend. The file structure references status pages, heartbeat data, and RSS title fields ('2026-01-05-0000-add-rss-title.js'). If any of these user-supplied values are rendered without proper escaping (e.g., via v-html in Vue.js or dangerouslySetInnerHTML in React), stored XSS is possible. Status pages are publicly accessible, increasing the attack surface significantly. Fix: Audit all Vue template bindings for use of v-html with user-controlled data. Implement a Content Security Policy (CSP) header. Sanitize all user-supplied strings server-side before storage and client-side before rendering using a library like DOMPurify. - High · SSRF Risk in Monitor URL Handling —
Server-side monitor execution logic (implied by monitor types in migrations). Uptime Kuma is a monitoring tool that accepts arbitrary URLs from authenticated users and performs HTTP/TCP/DNS/MQTT/WebSocket requests to those URLs. This is a classic SSRF scenario: a malicious authenticated user can direct the server to make requests to internal network resources (e.g., cloud metadata endpoints like 169.254.169.254, internal services, localhost). The SECURITY.md explicitly excludes SSRF from their bug bounty scope, indicating known risk acceptance rather than mitigation. Fix: Implement an allowlist/denylist for monitored URLs blocking RFC1918 ranges, loopback addresses, and cloud metadata endpoints. Use a network-level egress firewall to restrict outbound connections from the monitoring service. Consider running monitors in isolated network namespaces. - High · Insecure Default Configuration - No Authentication Enforcement on First Run —
compose.yaml, Docker deployment. Uptime Kuma is designed to be set up without initial authentication during first-run configuration. During the setup window before an admin account is created, the application may be accessible to anyone who can reach the network port. In Docker deployments, if port 3001 is exposed publicly, any unauthenticated user can claim the instance during this window. Fix: Implement a time-limited or network-restricted setup mode. Enforce binding to localhost by default (127.0.0.1:3001) in Docker compose configuration and require explicit opt-in for public exposure. Add setup-completion detection with automatic lockdown. - Medium · MQTT Credential Exposure in Monitor Configuration —
db/knex_migrations/2023-10-08-0000-mqtt-query.js, MQTT monitor configuration. The codebase includes MQTT monitor support ('2023-10-08-0000-mqtt-query.js', '2025-07-17-0000-mqtt-websocket-path.js'). MQTT broker credentials (username/password) stored as monitor configuration in the SQLite database could be exposed if the database file is accessed directly or if the API returns full monitor configurations including credentials to the frontend without masking. Fix: Encrypt sensitive credentials (passwords, tokens, API keys) stored in the database using application-level encryption. Mask credential fields in API responses. Ensure the SQLite database file has restrictive filesystem permissions (600) and is excluded from backups transmitted insecurely. - Medium · OAuth Audience Field Injection Risk —
undefined. The migration '2024-06-24-0000-add-audience-to-oauth.js' adds an audience field to OAuth Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.