Cloudsteading
UptimeFlare author-operated public demo · uptime history and response-time chart, captured 1 October 2026
UptimeFlare author-operated public demo · uptime history and response-time chart, captured 1 October 2026

UptimeFlare

Run minute-by-minute uptime checks and your own status page on Cloudflare.

UptimeFlare is a self-hosted Better Stack/Pingdom alternative built on Cloudflare (D1, Durable Objects, Pages, Workers). Free tier eligible within limits. Inspect the source and license in the linked repository.

Source & license

Upstream license: Apache-2.0

License TL;DR

You can use, change and sell it, including in closed-source products. When sharing copies, include the license, keep required notices and mark changed files. It includes a contributor patent grant with conditions, but no trademark permission or warranty.

Explain Apache 2.0 in plain English →

Summary of the main license. Separate packages and assets can have different terms.

Inspect repository ↗Read this project’s actual license ↗

Repository owner

@lyc8503

See the upstream repository for the original creator and contributors.

Maintain this project? Maintainer verification →

Cloudflare hosting

Free tier eligible within limits

A small uptime-monitoring setup can fit Cloudflare Free allowances using Workers, Pages, D1 and SQLite Durable Objects. Eligibility depends on measured CPU, monitor count, status-page traffic and account quotas; it is not a verified zero-cost deployment.

Hosting requirements
  • Keep combined Workers and Pages Function requests within the account Free allowance of 100,000 per day and each Worker invocation within 10 ms CPU. Measure history compaction and checks; the upstream claim of 50 monitors is not a tested free-tier capacity here.
  • Keep D1 below 5 million rows read/day, 100,000 rows written/day and the account storage allowance. The scheduled Worker writes compacted state on status changes or the configured cooldown; page requests also read it.
  • Use the Terraform-created SQLite RemoteChecker class for optional worker:// regional checks and stay within Durable Object request, duration and storage allowances. Other proxy modes and Globalping are separate services with their own terms.
  • Use an eligible GitHub Actions plan and provision your own Cloudflare account, token, database and configuration. Private-repository Actions minutes, custom domains and third-party notification delivery can add costs.
  • Basic direct checks and the public status page need no paid notification provider. Apprise, hosted notification gateways and external proxies are optional and excluded from this free-tier assessment.
Check current pricing ↗
Sources checked 01/10/2026

Repository snapshot: a5670e5. Hosting eligibility reflects the deployment documentation and listed assumptions.

  • uptimerobot ↗

    Support for HTTP/HTTPS/TCP port monitoring

  • better-stack ↗

    Support for HTTP/HTTPS/TCP port monitoring

  • pingdom ↗

    Support for HTTP/HTTPS/TCP port monitoring

  • workers ↗

    resource "cloudflare_workers_script" "uptimeflare_worker"

  • pages ↗

    resource "cloudflare_pages_project" "uptimeflare"

  • d1 ↗

    name = "uptimeflare_d1"

  • durable-objects ↗

    new_sqlite_classes = ["RemoteChecker"]

  • free-tier-eligible ↗

    | **Free** | 100,000 per day | No charge for duration | 10 milliseconds of CPU time per invocation |

  • free-tier-eligible ↗

    | Rows read | 5 million / day | First 25 billion / month included + $0.001 / million rows |

  • free-tier-eligible ↗

    | Rows written | 100,000 / day | First 50 million / month included + $1.00 / million rows |

  • free-tier-eligible ↗

    Workers Free plan can only create and access SQLite-backed Durable Objects.

  • free-tier-eligible ↗

    migrations = var.enable_do_migration ? { new_tag = "v1" new_sqlite_classes = ["RemoteChecker"] } : null bindings = [{ name = "REMOTE_CHECKER_DO" class_name = "RemoteChecker" type = "durable_object_namespace" }, { name = "UPTIMEFLARE_D1" type = "d1" id = cloudflare_d1_database.uptimeflare_d1.id }] }

  • Apache-2.0 ↗

    Apache License Version 2.0, January 2004

  • architecture ↗

    resource "cloudflare_workers_cron_trigger" "uptimeflare_worker_cron" { account_id = var.CLOUDFLARE_ACCOUNT_ID script_name = cloudflare_workers_script.uptimeflare_worker.script_name schedules = [{ cron = "* * * * *" # every 1 minute, you can reduce the write counts by increase the worker settings of `kvWriteCooldownMinutes` }] } resource "cloudflare_pages_project" "uptimeflare" { account_id = var.CLOUDFLARE_ACCOUNT_ID name = "uptimeflare" production_branch = "main" deployment_configs = { # SMH Cloudflare provider will throw an error without preview config preview = { fail_open = false } production = { d1_databases = { UPTIMEFLARE_D1 = { id = cloudflare_d1_database.uptimeflare_d1.id } } compatibility_date = "2025-04-02" compatibility_flags = ["nodejs_compat"] fail_open = false } } # SMH it will error without this build_config build_config = { root_dir = "/" } }

  • architecture ↗

    resource "cloudflare_workers_script" "uptimeflare_worker" { account_id = var.CLOUDFLARE_ACCOUNT_ID script_name = "uptimeflare_worker" main_module = "worker/dist/index.js" content_file = "worker/dist/index.js" content_sha256 = filesha256("worker/dist/index.js") compatibility_date = "2025-04-02" compatibility_flags = ["nodejs_compat"] observability = { enabled = true logs = { enabled = true invocation_logs = true } } migrations = var.enable_do_migration ? { new_tag = "v1" new_sqlite_classes = ["RemoteChecker"] } : null bindings = [{ name = "REMOTE_CHECKER_DO" class_name = "RemoteChecker" type = "durable_object_namespace" }, { name = "UPTIMEFLARE_D1" type = "d1" id = cloudflare_d1_database.uptimeflare_d1.id }] }

  • architecture ↗

    export const runtime = 'edge'

  • architecture ↗

    await getFromStore(process.env as any, 'state')

  • architecture ↗

    Interactive ping (response time) chart for all types of monitors

Documented public demo screenshot · lyc8503/UptimeFlare repository contributors ↗. Depicts the upstream project. We have not deployed and tested a fresh installation here.

What it can replace

Compare the workflow you need. These mappings describe overlap; full feature parity requires a separate comparison.

UptimeRobot logoUptimeRobot ↗

HTTP/HTTPS/TCP availability checks and a self-hosted status page. Excludes real-user monitoring, logs, traces, synthetic browser journeys, on-call scheduling and complete feature parity.

See supporting source ↗
Better Stack logoBetter Stack ↗

HTTP/HTTPS/TCP availability checks and a self-hosted status page. Excludes real-user monitoring, logs, traces, synthetic browser journeys, on-call scheduling and complete feature parity.

See supporting source ↗
Pingdom logoPingdom ↗

HTTP/HTTPS/TCP availability checks and a self-hosted status page. Excludes real-user monitoring, logs, traces, synthetic browser journeys, on-call scheduling and complete feature parity.

See supporting source ↗
UptimeFlare status page with service uptime and latency charts · upstream application screenshot
external SaaS target
varies
external SaaS target
varies
external SaaS target
varies

How it works

The shape of UptimeFlare on Cloudflare, and how it stacks up against the rented tools it replaces.

Architecture

Diagram based on the linked repository documentation. See the sources and hosting assumptions above.

View upstream source ↗
Public interface
Status page visitors2
GET
Public status page
Charts, incidents and maintenance notices
GET
/api/data
JSON status read from D1
Scheduled checks1
CRON
Every minute · * * * * *
Configured by Terraform
↓
App
uptimeflare · Pages
entry
Next.js via next-on-pages · edge API
Read compacted monitor state from D1Render status, incident and maintenance views
uptimeflare_worker
entry
Cloudflare Workers · scheduled handler
Check configured HTTP/HTTPS/TCP endpointsWrite state on status changes or cooldownOptional worker:// checks through RemoteChecker
↓

Configuration and workflow sources

Reviewed commit a5670e51cbc1. This configuration evidence comes from reading source files. Execution checks, when available, appear in the project's runtime review.

Deployment configuration · 2 files
wrangler.toml ↗

Cloudflare Workers · compatibility 2025-04-02

uptimeflare · default

  • UPTIMEFLARE_D1 → D1
worker/wrangler.toml ↗

Cloudflare Workers · compatibility 2025-04-02

uptimeflare_worker · default

Entrypoint: src/index.ts

  • UPTIMEFLARE_D1 → D1

Named environments are separate deployments. Bindings are shown only where declared. Configured routes are URL patterns, not verified application endpoints.

Runtime source · handlers, binding usage and workflow steps

Observed TypeScript/JavaScript declarations from Worker entrypoints and resolved relative imports. Calls and workflow steps may run conditionally; their listed order is not a proven end-to-end request flow. Router declarations may be mounted under a prefix or may not be registered. This shows code wiring, not a successful deployment or runtime test. Dynamic wiring, aliases and generated code may not resolve.

worker/src/index.ts ↗
  • L15 · scheduled handler exported · calls getWorkerLocation, console.log, getFromStore, Math.round, Date.now, pLimit, checkQueue.push, limit, doMonitor, Promise.all, state.incidentLen, state.appendIncident, state.getIncident, state.setIncident, formatAndNotify, lastIncident.error.slice, lastIncident.start.push, lastIncident.error.push, state.appendLatency, state.getFirstLatency, state.unshiftLatency, state.shiftIncident, state.unshiftIncident, setToStore, state.getCompactedStateStr
worker/src/monitor.ts ↗
  • L5 · isIpAddress calls (conditional paths may differ): hostname.includes, hostname.split, parts.every, test, Number
  • L19 · getDomainOnlyIpVersionOption calls (conditional paths may differ): isIpAddress, Number, gpUrl.searchParams.get
  • L27 · httpResponseBasicCheck calls (conditional paths may differ): monitor.expectedCodes.includes, JSON.stringify, bodyReader, responseBody.includes, console.log, responseBody.slice
  • L73 · getStatusWithGlobalPing calls (conditional paths may differ): getDomainOnlyIpVersionOption, gpUrl.searchParams.get, includes, monitor.method.toUpperCase, Object.fromEntries, map, Object.entries, String, Number, targetUrl.protocol.replace, Date.now, console.log, JSON.stringify, fetchTimeout, measurement.json, json, setTimeout, Math.round, httpResponseBasicCheck, startsWith
  • L267 · getStatus calls (conditional paths may differ): Date.now, then, connect, Number, withTimeout, socket.close, console.log, e.message.includes, headers.has, headers.set, fetchTimeout, httpResponseBasicCheck, response.text.bind
  • L357 · doMonitor calls (conditional paths may differ): console.log, monitor.checkProxy.startsWith, monitor.checkProxy.replace, env.REMOTE_CHECKER_DO.idFromName, env.REMOTE_CHECKER_DO.get, doStub.getLocationAndStatus, doStub.kill, getStatusWithGlobalPing, json, fetch, JSON.stringify, getStatus

Environment references: env.REMOTE_CHECKER_DO

worker/src/store.ts ↗
  • L9 · getFromStore calls (conditional paths may differ): env.UPTIMEFLARE_D1.prepare, first, stmt.bind
  • L15 · setToStore calls (conditional paths may differ): env.UPTIMEFLARE_D1.prepare, run, stmt.bind

Environment references: env.UPTIMEFLARE_D1

pages/api/data.ts ↗
  • L14 · handler calls (conditional paths may differ): getFromStore, JSON.stringify, compactedState.getIncident, compactedState.incidentLen, compactedState.getLastLatency
next.config.js ↗

    Environment references: process.env.NODE_ENV

    worker/src/util.ts ↗
    • L4 · getWorkerLocation calls (conditional paths may differ): fetch, res.text, exec
    • L24 · withTimeout calls (conditional paths may differ): setTimeout, reject, Promise.race
    • L32 · formatStatusChangeNotification calls (conditional paths may differ): Math.round, dateFormatter.format
    • L70 · templateWebhookPlayload calls (conditional paths may differ): Object.prototype.hasOwnProperty.call, templateWebhookPlayload
    • L82 · webhookNotify calls (conditional paths may differ): Array.isArray, webhookNotify, console.log, JSON.stringify, JSON.parse, templateWebhookPlayload, Object.entries, urlTmp.searchParams.append, v.toString, urlTmp.toString, headers.get, headers.set, toString, Object.fromEntries, headers.entries, fetchTimeout, resp.text
    Build and deployment pipeline · 3 GitHub Actions workflows

    Repository CI declarations, separate from runtime request processing. Job dependencies and conditions are shown as written; long commands are shortened with an ellipsis; a workflow file does not prove a recent successful run.

    Deploy to Cloudflare · .github/workflows/deploy.yml ↗

    Triggers: push, workflow_dispatch

    build-and-deploy · no job dependencies declared

    1. actions/checkout@v3actions/checkout@v3
    2. Setup Terraformhashicorp/setup-terraform@v2.0.3
    3. Use Node.js 22.xactions/setup-node@v3
    4. Fetch Account IDif [[ -n "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" ]]; then ACCOUNT_ID="${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" echo "Using provided CLOUDFLARE_ACCOUNT_ID from secrets." else ACCOUNT_ID=$(curl -X GET "https://api.cloudflare.com/client/v4/accounts" -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" -H "Content-Type:application/json" | jq ".result[0].id" -r) if [[ "$ACCOUNT_ID" == "null" ]]; then echo "Failed to get an account id, please make sure you have set up CLOUDFLARE_API_TOKEN correctly!" exit …
    5. Install packagesnpm install cd worker npm install
    6. Build workercd worker npx wrangler deploy src/index.ts --outdir dist --dry-run
    7. Build pagenpx @cloudflare/next-on-pages
    8. Create D1 database and tablespython3 deploy/init_d1.py # This sets D1_ID in GITHUB_ENV
    9. Migrate state from KV (if needed)python3 deploy/migrate_kv.py
    10. Deploy using Terraformterraform init DO_RESP=$(curl "https://api.cloudflare.com/client/v4/accounts/$TF_VAR_CLOUDFLARE_ACCOUNT_ID/workers/durable_objects/namespaces?per_page=1000" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN") if echo "$DO_RESP" | jq -e '.result[] | select(.script == "uptimeflare_worker" and .class == "RemoteChecker")' > /dev/null; then echo "Existing Durable Object namespace found for uptimeflare_worker RemoteChecker. No migration needed." else echo "No existing Durable Object namespace found f…
    11. Upload pagesnpx wrangler pages deploy .vercel/output/static --project-name uptimeflare
    issue-translator · .github/workflows/issue_translate.yml ↗

    Triggers: issue_comment, issues

    build · no job dependencies declared

    1. usthe/issues-translate-action@v2.7usthe/issues-translate-action@v2.7
    Upstream Sync · .github/workflows/sync.yaml ↗

    Triggers: workflow_dispatch

    Sync latest commits from upstream repo · no job dependencies declared

    1. Checkout target repoactions/checkout@v3
    2. Current configcat uptime.config.ts cp uptime.config.ts /tmp/origin.config.ts
    3. Sync upstream changesgit config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" # Fetch latest code git clone https://github.com/lyc8503/UptimeFlare /tmp/latest rm -rf /tmp/latest/.git # Clean current repo and update git rm -rf '*' cp -r /tmp/latest/. . cp /tmp/origin.config.ts uptime.config.ts git add . git commit -m "Sync latest code from upstream" git push
    4. Trigger deploymentbenc-uk/workflow-dispatch@v1Condition: ${{ inputs.override-token == '' }}
    package.json ↗
    • build: next build
    worker/package.json ↗
    • deploy: wrangler deploy

    Full upstream document by @lyc8503 · README.md · snapshot a5670e5

    English 简体中文

    ✔UptimeFlare

    A more advanced, serverless, and free uptime monitoring & status page solution, powered by Cloudflare Workers, complete with a user-friendly interface.

    📢 [SECURITY ADVISORY 2026/03/04] A vulnerability (CVE-2026-29779) that could expose monitor configuration and credentials in uptime.config.ts to clients was fixed. Versions between 2025-09-21 (from commit 41257c6) and 2026-03-04 are affected. Affected users are strongly advised to upgrade to the latest version.

    🎉 [UPDATE 2026/01/03] I have just migrated UptimeFlare from KV to D1 Database. I also updated the Terraform Cloudflare provider to v5 and improved the deployment process. The data structure has been optimized to resolve long-standing performance issues.

    New users can deploy directly, while existing users can have a simple auto migration process (upgrade docs below)! Feel free to open an issue if you run into any trouble deploying.

    ⭐Features

    • Open-source, easy to deploy (in under 10 minutes, no local tools required), and free
    • Monitoring capabilities
      • Up to 50 checks at 1-minute intervals
      • Geo-specific checks from over 310 cities worldwide
      • Support for HTTP/HTTPS/TCP port monitoring
      • Up to 90-day uptime history and uptime percentage tracking
      • Customizable request methods, headers, and body for HTTP(s)
      • Custom status code & keyword checks for HTTP(s)
      • Downtime notification supporting 100+ notification channels
      • Customizable Webhook
      • Multi-language support (English/Chinese)
    • Status page
      • Interactive ping (response time) chart for all types of monitors
      • Scheduled maintenances alerts & Incident history page
      • Responsive UI that adapts to your system theme
      • Customizable status page
      • Use your own domain with CNAME
      • Optional password authentication (private status page)
      • JSON API for fetching realtime status data

    👀Demo

    My status page (Online demo): https://uptimeflare.pages.dev/

    Some screenshots:

    Desktop, Light theme

    ⚡Quickstart / 📄Documentation

    Please refer to Wiki

    🚀Upgrade existing deployments

    Get the latest features right away with simple upgrade process

    ⚙️Docs for developer

    To contribute new features or customize your deployment furthermore, see here.

    New features (TODOs)

    • Specify region for monitors
    • TCP opened promise
    • Use apprise to support various notification channels
    • Telegram example
    • Bark example
    • Email notification via Cloudflare Email Workers
    • Improve docs by providing simple examples
    • Notification grace period
    • SSL certificate checks
    • Self-host Dockerfile
    • Incident history
    • Improve checkLocationWorkerRoute and fix possible proxy failed
    • Groups
    • Remove old incidents
    • Known issue: fetch doesn't support non-standard port (resolved after CF update)
    • Compatibility date update
    • Scheduled Maintenance
    • Add docs for dev
    • Migration to Terraform Cloudflare provider version 5.x
    • Cloudflare D1 database
    • Scheduled maintenances (via IIFE)
    • Simpler config example
    • Upcoming maintenances
    • Universal Webhook upgrade
    • i18n...? (maybe)
    • ICMP via proxy?
    • Add default UA
    • Customizable footer
    • New header logo
    • Improve CPU time usage
    • Local deployment (docs WIP)

    Frequently asked about UptimeFlare

    What is UptimeFlare?+

    UptimeFlare is a self-hosted Better Stack/Pingdom alternative built on the Cloudflare developer platform. Run minute-by-minute uptime checks and your own status page on Cloudflare.

    What does UptimeFlare replace?+

    UptimeFlare is listed as an alternative to Better Stack, Pingdom, UptimeRobot. Compare the features and tradeoffs before migrating.

    What Cloudflare primitives does UptimeFlare use?+

    UptimeFlare is built on D1, Durable Objects, Pages, Workers.

    How much does UptimeFlare cost to run?+

    A small uptime-monitoring setup can fit Cloudflare Free allowances using Workers, Pages, D1 and SQLite Durable Objects. Eligibility depends on measured CPU, monitor count, status-page traffic and account quotas; it is not a verified zero-cost deployment. Keep combined Workers and Pages Function requests within the account Free allowance of 100,000 per day and each Worker invocation within 10 ms CPU. Measure history compaction and checks; the upstream claim of 50 monitors is not a tested free-tier capacity here. Keep D1 below 5 million rows read/day, 100,000 rows written/day and the account storage allowance. The scheduled Worker writes compacted state on status changes or the configured cooldown; page requests also read it. Use the Terraform-created SQLite RemoteChecker class for optional worker:// regional checks and stay within Durable Object request, duration and storage allowances. Other proxy modes and Globalping are separate services with their own terms. Use an eligible GitHub Actions plan and provision your own Cloudflare account, token, database and configuration. Private-repository Actions minutes, custom domains and third-party notification delivery can add costs. Basic direct checks and the public status page need no paid notification provider. Apprise, hosted notification gateways and external proxies are optional and excluded from this free-tier assessment. Check current Cloudflare pricing before deploying.

    Is UptimeFlare open source?+

    The upstream repository declares the Apache-2.0 license. Read its terms at https://raw.githubusercontent.com/lyc8503/UptimeFlare/a5670e51cbc167bf3610fce4d3389dd00141d729/LICENSE. Source code and contributor credit are available at https://github.com/lyc8503/UptimeFlare.

    Community rating

    No ratings yet. Tried this project? Share your experience.

    One rating per verified account. You can change or remove yours. Accounts are email verified; use of the software is self-reported.

    Discuss your experience ↓
    Sign in to rate

    Discussion · 0

    sign in to comment →
    No comments yet — be the first.