Overview
Vigil is a self-hosted uptime monitoring tool that runs on Cloudflare Workers. It uses Cloudflare Durable Objects for per-monitor scheduling and state, Cloudflare D1 for persistence, and Cloudflare Workers as the runtime for the frontend and backend. It is built for small+ scale in mind. Anyone can clone the repo and run it to monitor their own apps. It's designed to run behind Cloudflare Access for authentication, keeping auth concerns out of the application entirely.
Happy Path
For standard use of the tool, a user would start by adding a site to the monitor configuration. This includes the URL to monitor, how often to check it, and other options. Once a monitor is configured, they can view a dashboard specific to that monitor which shows current status, a visualization of performance over time, any recent incidents, and a table of the most recent checks against the monitor's URL. If a check fails, the site goes into a "degraded" state while Vigil attempts to connect. After a few attempts the site officially becomes "down". Similarly, once checks begin to succeed again, the site moves into a "recovering" state until finally becoming "up" again. Incidents are opened when the site is "down" and closed when they return to "up" status, with notifications (if configured) following the same pattern.
Background
I built this application initially as an experiment to see what I could do with Durable Objects in a production-focused setting. I also wanted to intentionally not make this into a SaaS with imaginary scale since I actually wanted to use it for my own purposes. These constraints and a general desire to contribute were why I chose to make it open source and easy to deploy in as few steps as possible. Thanks to Cloudflare's unified ecosystem and tooling, I was able to achieve this using their "Deploy to Cloudflare" button which basically clones the repo, configures all the resources, and deploys it to your Cloudflare account. You can find a step by step guide to this process in the project's README.md on GitHub.
Tech Stack
| Layer | Technologies |
|---|---|
| Runtime | Cloudflare Workers, Durable Objects, D1 (SQLite) |
| Backend | Hono, Drizzle ORM |
| Frontend | React, Vite, TailwindCSS, React Router, TanStack Query |
| Forms & Validation | React Hook Form, Zod |
| Charts | Recharts |
| Dev Tooling | TypeScript, Biome, Vitest, Wrangler |
Features
- HTTP endpoint monitoring with configurable methods, headers, expected status codes, and timeouts
- Smart status detection: UP, DEGRADED, DOWN, RECOVERING states with consecutive failure thresholds
- Automatic incident tracking: incidents open when services go down and close on recovery
- Notifications via webhooks with retry logic and exponential backoff—failed deliveries are logged but not retried indefinitely (notification system is extensible to other channels)
- Real-time dashboard with response time charts and check history
- Data retention controls: automatic cleanup of old check results
- Test before you commit: validate endpoints and notification channels before enabling
Architecture
How it works:
Each monitor gets its own Durable Object. This provides natural isolation: one misbehaving endpoint can't affect others. The DO manages its own check schedule using Alarms. Checks execute from Cloudflare's edge location hosting the DO instance; Vigil does not fan out checks to multiple regions per endpoint.
Checks run on a configurable interval (default: 60 seconds). The Durable Object wakes up, performs the HTTP check, records the result, and goes back to sleep.
State transitions are deterministic. A monitor doesn't flip to DOWN on a single failure. It requires consecutive failures (default: 3) to avoid false positives from transient network issues.
All data lives in D1. Check results, incidents, and notification logs all persist in a SQLite database at the edge.
A daily cron job cleans up old data. Check results older than the retention period (default: 15 days) are automatically pruned.
No internal API keys. All communication between Workers, Durable Objects, and D1 uses Cloudflare bindings. The only outbound HTTP calls are the health checks themselves.
Tradeoffs
The architecture of Vigil is intentional and thus limited.
Single-provider dependency. The whole stack is on Cloudflare which is great for performance but this is also a vulnerability. If Cloudflare goes down, so does your monitoring. This is suitable for smaller scale applications (if Cloudflare is down you probably have bigger issues) in exchange for the benefits of edge-based computing and a simplified deployment model.
Single-region checks. Monitors check from one edge location rather than many. A site could be down only in one region, but Vigil will not differentiate between that and all regions. This is acceptable given most of your applications are most likely in one region anyway at this scale - even if Vigil is used to monitor client sites, for example.
No built-in authentication. As mentioned, Vigil is not shipped with any sort of authentication or identity awareness. This is great for development and overall simplicity but it limits things like multi-tenancy or granular permissions and requires you to configure Cloudflare Access. Fortunately Access allows some pretty sophisticated identity patterns and given the ease of deployment, you could easily just deploy multiple instances of Vigil to achieve multi-tenancy if needed.
Future Considerations
These aren't necessarily promises or a roadmap: they are just ideas I had but decided to put on the back burner.
Additional notification channels. Webhooks are enabled which gives a lot of customization but also requires configuration to achieve. I'd love to add integrations with Slack, Discord, and an email service so you could use those by default or choose webhook if you need further customization with an external service.
Public status pages. I had the idea of creating some kind of read-only report, status page, or even a simple badge so you could expose the health of your site(s) to the public. Depending on how far I want to take it, this is probably the easiest to accomplish on this list.