Skip to content

Repository files navigation

Vigil

Self-hosted uptime monitoring — a lightweight Uptime Kuma / UptimeRobot alternative built on Bun, React 19, Tailwind v4 + shadcn/ui, and SQLite. One container, one volume, no external services.

Showcase

Dashboard — live overview with per-monitor uptime bars, grouped sidebar, and down alerts:

Dashboard

Monitor detail — recent checks, 24h/7d/30d response-time chart, uptime and TLS expiry at a glance:

Monitor detail

Public status page — grouped components, 90-day uptime history, pinned incidents with severity styling:

Status page

Features

  • Monitor types: HTTP(s), HTTP keyword (present/absent), Ping (ICMP), TCP port, DNS (A/AAAA/CNAME/MX/TXT/NS, custom resolver), and Push (heartbeat/cron) monitors
  • Checks: intervals from 20s, per-monitor timeout, retries with PENDING grace state, accepted status-code ranges, follow-redirects toggle, ignore-TLS toggle, custom headers/body/method
  • TLS certificate expiry tracking for HTTPS monitors
  • Grouping for monitors, with a live grouped sidebar
  • Status pages (multiple): pick monitors into named sections, publish/unpublish, optional password protection, optional custom domain, incidents (info/warning/danger/success, pin + resolve), 90-day daily uptime bars, "Powered by" toggle
  • Notifications: Webhook, Slack, Discord, Telegram, ntfy, Email (SMTP) — attach per monitor, mark channels as defaults, one-click test
  • Maintenance windows: scheduled silence — checks record MAINTENANCE, alerts are suppressed, status pages show it distinctly
  • MCP server: built-in Model Context Protocol endpoint so AI assistants (Claude, Cursor, …) can query status, inspect monitors, and create/pause/resume them
  • Dashboard: live overview, response-time charts (24h/7d/30d), important-event log, uptime bars
  • Dark/light theme, responsive UI

Quick start (Docker)

docker compose up -d

Open http://localhost:3001 and create your admin account on first run. Data (SQLite + WAL) lives in the vigil-data volume mounted at /app/data.

Environment

Variable Default Purpose
PORT 3001 HTTP port
DATA_DIR /app/data (Docker) / ./data (dev) SQLite location
SESSION_SECRET auto-generated, persisted Cookie/token signing secret
TZ UTC Container timezone

Push (heartbeat) monitors

Create a Push monitor and Vigil gives you a secret URL. Have your cron job / worker ping it within the configured interval:

curl -fsS "https://vigil.example.com/api/push/<token>?status=up&ping=42&msg=OK"

If no ping arrives within interval + grace, the monitor goes DOWN and alerts fire. Send status=down to fail it explicitly.

Status pages

Each page is served at /status/<slug>. Options:

  • Password: viewers must enter it once per browser (12h cookie).
  • Custom domain: set the domain on the page, then point DNS (or your reverse proxy) at the Vigil server. Requests landing on that host render the status page at the domain root — the admin app stays available on your primary host.
  • Incidents: post updates with severity styling; pin important ones; resolve when done.

MCP server

Vigil ships a built-in MCP server so AI assistants can query and manage your monitors. Generate an API key under Settings → MCP Server, then point any streamable-HTTP MCP client at /mcp:

{
  "mcpServers": {
    "vigil": {
      "type": "http",
      "url": "https://vigil.example.com/mcp",
      "headers": { "Authorization": "Bearer vgl_..." }
    }
  }
}

Tools

Area Tools
Status get_status_summary, list_monitors, get_monitor, list_events
Monitors create_monitor, pause_monitor, resume_monitor
Notifications describe_notification_types, list_notification_channels, create_notification_channel, update_notification_channel, delete_notification_channel, test_notification_channel, set_monitor_notifications

Channel configuration is self-describing: describe_notification_types returns the JSON Schema for each provider (webhook, Slack, Discord, Telegram, ntfy, SMTP), so an assistant can build a valid config without guessing field names. Credentials are write-only — secret fields come back as *** when a channel is read, and update_notification_channel merges the keys you pass, so you can change one field without resending a secret you cannot see.

The endpoint is stateless JSON-RPC over POST (no SSE session); rotate or disable the key at any time from Settings.

Development

bun install
bun run dev        # Bun fullstack dev server with HMR on :3001
bun run typecheck  # tsc --noEmit
bun test           # engine unit tests

The frontend is bundled by Bun itself (HTML imports + bun-plugin-tailwind — no Vite); in production (bun run start or Docker) assets are bundled once at startup, cached, and minified.

Architecture

src/
  shared/types.ts    # domain + API contract shared by server and web
  server/            # Bun.serve() routes, bun:sqlite, scheduler, checkers, notifiers
  web/               # React SPA (react-router, TanStack Query, shadcn/ui)
  • Heartbeats are appended to SQLite (WAL) with transition detection; daily aggregates power 30/90-day uptime and survive raw-beat retention (configurable, default 180 days).
  • Sessions are cookie-based (argon2id password hashing via Bun.password).
  • Ping checks shell out to the system ping (bundled in the Docker image).

About

Self host uptime monitor. 100% slop certificated

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages