- Render free Web Service runs a real, long-running Python process with a persistent disk while the instance is up — required here because the monitor holds a continuous WebSocket connection and the SQLite DB needs to persist between requests. Vercel (serverless, ephemeral filesystem, no long-running processes) can't do either of those things for this app.
- GitHub Pages serves the static dashboard for free, permanently, from the same repo.
- The honest tradeoff: Render's free tier sleeps after 15 minutes with no HTTP traffic, which would kill the monitor's WebSocket connection too. The fix is a free external uptime pinger (step 5) — a real workaround, not a guarantee. This is a documented limitation, not hidden. See limitations.md.
-
Go to render.com and sign up / log in (free, GitHub OAuth is the fastest option).
-
Click New + → Blueprint.
-
Connect your GitHub account if prompted, then select the
India-BGP-Hijack-Monitorrepo. -
Render will detect
render.yamlin the repo root automatically and propose one service:india-bgp-hijack-monitor(free plan, Python runtime). Review it and click Apply.- If you'd rather set it up by hand instead of via Blueprint: New +
→ Web Service → connect the repo → Runtime:
Python 3→ Build Command:pip install -r requirements.txt→ Start Command:python -m uvicorn backend.api:app --host 0.0.0.0 --port $PORT→ Instance Type: Free. Then add the two environment variables from step 5 manually under the service's Environment tab.
- If you'd rather set it up by hand instead of via Blueprint: New +
→ Web Service → connect the repo → Runtime:
-
render.yamlalready sets all required environment variables, but if you set the service up by hand, add them under Environment:RUN_MONITOR_INLINE=1(starts the live monitor in a background thread inside the API process — seebackend/api.py)RUN_RPKI_REFRESH_INLINE=1(re-samples live RPKI coverage in a background thread on boot, on top of the instant seed from the committed summary — see "RPKI coverage self-heals" below)PYTHONUNBUFFERED=1(so log output shows up in Render's log viewer immediately instead of being buffered — without this you'll see nothing in the logs for minutes at a time)
If you already created the service before this env var existed: Blueprint config only applies automatically on initial creation — updating
render.yamllater does not retroactively change an already-running service's environment variables. AddRUN_RPKI_REFRESH_INLINE=1manually under the service's Environment tab in the Render dashboard, then Manual Deploy → Deploy latest commit (or just push any commit) to pick it up. -
Click Create Web Service (or confirm the Blueprint). First deploy takes a few minutes — watch the Logs tab. On first boot the API process builds the baseline itself (empty DB triggers
build_baseline()automatically, seebackend/api.py), so the first deploy is slower than subsequent ones. -
Once live, note your service URL — Render gives you something like
https://india-bgp-hijack-monitor.onrender.com. -
Verify it directly: open
https://YOUR-URL.onrender.com/api/statusin a browser. You should see real JSON withbaseline_prefix_countaround 20,000+. If it's0, check the Logs tab for a RIPEstat error.
- In
frontend/index.html, find this line near the top of the<script>block:const DEPLOYED_API_URL = 'https://REPLACE-WITH-YOUR-RENDER-URL.onrender.com';
- Replace the placeholder with your actual Render URL from Part 1, step 7 (no trailing slash).
- Commit and push:
git add frontend/index.html git commit -m "Point deployed frontend at the live Render API" git push
- On GitHub, open the
India-BGP-Hijack-Monitorrepo → Settings → Pages (left sidebar, under "Code and automation"). - Under Build and deployment → Source, choose Deploy from a branch.
- Under Branch, choose
mainand folder/ (root), then Save. - Wait a minute or two, then your dashboard is live at:
(GitHub Pages serves the whole repo as static files when the source is set to root —
https://<your-github-username>.github.io/India-BGP-Hijack-Monitor/frontend/frontend/in the URL is becauseindex.htmllives in that subfolder, not the repo root. GitHub automatically servesindex.htmlfor a directory path, so the trailing/frontend/with no filename works.) - Open that URL and confirm the dashboard loads and shows real data (it's
now calling your Render backend cross-origin, which works because the
API already has
allow_origins=["*"]set).
Render's free tier sleeps after 15 minutes of no HTTP traffic. Since the monitor's WebSocket connection lives inside that same process, sleeping kills live monitoring until the next request wakes it back up.
- Sign up for a free account at UptimeRobot or cron-job.org (both have permanently free tiers for this use case).
- Create a new monitor/cron job:
- URL:
https://YOUR-RENDER-URL.onrender.com/api/status - Interval: every 10-14 minutes (must be under Render's 15-minute sleep threshold)
- URL:
- This keeps the instance awake continuously, which is what makes the dashboard's "Live" badge meaningful on the deployed version, not just locally.
This is a known, common workaround for free-tier sleep behavior — not a guarantee of 100% uptime. If you want guaranteed uptime, that requires a paid tier, which is explicitly out of scope for this project.
Render auto-redeploys on every push to main by default (configurable
under the service's Settings → Build & Deploy). Just git push as
usual.
Caveat: Render's free tier does not include a persistent disk add-on, so a redeploy or restart gets a fresh filesystem. Two things self-heal automatically, no manual step required:
- Baseline rebuilds itself on boot if the table is empty.
- RPKI coverage is seeded instantly from the committed
docs/rpki-coverage-summary.json(real percentages within seconds of boot, not "not yet sampled"), then refreshed with fully live data in the background ifRUN_RPKI_REFRESH_INLINE=1is set.
Event history does not self-heal — there's no committed snapshot of past detections to seed from (events are live findings, not baseline/config data), so accumulated events genuinely reset on redeploy. This is a deliberate limitation, not an oversight: seeding fake "historical" events from a static file would be actively misleading for a security-monitoring tool. Documented in limitations.md.