PeerWeave Devlog · 21 September 2026

Keeping PeerWeave awake

Render’s Free web services go to sleep after fifteen minutes with no inbound HTTP. The next visitor then sits on a boot screen. A quiet ping from an always-on machine is the workaround. Paying for Starter is the lasting fix.

The first visitor should not pay the cold start

Identified GETs, no body, no credentials — a systemd user timer that knocks on the origin every ten minutes so Next.js is already there.

PeerWeave’s public site is a Next.js app on Render. This personal site is not. lucastilford.com is a static tree: HTML, CSS, and JavaScript at the repo root, published for free, with an empty build command. Static files do not idle. A web service on Render Free does.

After fifteen minutes with no inbound HTTP, Render drops the Free instance. The next person to open peerweave.com does not get the app. They get “Welcome to Render / APPLICATION LOADING” for half a minute to a minute and a half while the origin boots. That is a tax on curiosity. I would rather the site already be standing.

So the hub PC — the same always-on Linux box that can also run Manticore Network Intelligence on networks I own — now knocks. The keep-warm job is not in manticore-net. It lives in the PeerWeave repo at deploy/keep-warm/.

A daemon, in the old sense

I wrote once about daemons as unseen agents that convert information into order. This is a small one. Every ten minutes (plus a little jitter so it is not a metronome) it GETs three URLs with an identified User-Agent:

  • https://www.peerweave.com/ — the visitor landing page
  • https://www.peerweave.com/app — the web client
  • https://peer-weave.onrender.com/ — the Render origin, so a future Cloudflare cache hit cannot skip the machine that actually sleeps

No POST. No cookies. No credentials. If Render’s interstitial comes back anyway, the script retries with backoff until real Next.js HTML arrives, with a ninety-second ceiling per attempt. The loop floor is five minutes, so it cannot hammer the site even if someone edits the interval down.

hub PC (systemd --user timer, Linger=yes)
        │
        │  GET every ~10 min
        ▼
www.peerweave.com/          ─┐
www.peerweave.com/app        ├─ Cloudflare (maybe)
peer-weave.onrender.com/    ─┘
        │
        ▼
Render origin (the process that idles)

Why the timer lives on this machine

GitHub Actions can ping the same three URLs. The workflow is .github/workflows/keep-warm.yml, scheduled every ten minutes. GitHub’s cron can lag past fifteen minutes. When it lags, the origin is already asleep and the Action is just another cold-start visitor. The hub-PC timer is the real keep-alive. The Action is a backup, and it only runs after that workflow is on main.

The installer copies the script to ~/.local/bin/peerweave-keep-warm and enables a systemd user timer. loginctl enable-linger is set so the timer keeps firing after logout. Persistent=true means a missed tick after a reboot still runs. It is not a packet capture. It is not a health dashboard. It is a polite knock.

A live probe after install: all three URLs returned 200 in well under a second. That is the whole point — visitors should see that, not the boot screen.

The caveat that actually matters

PeerWeave’s render.yaml already asks for Starter, which does not idle. If people still see the boot page, the live service is on Free. Keep-warm is the workaround. Starter is the durable fix.

A Free instance kept awake uses most of the 750 monthly instance hours. That is the honest cost of this trick: you have not escaped the meter; you have chosen to spend the hours on availability instead of on sleep. When the product should be up for strangers, pay for a plan that does not nap.

This page is hosted the other way: static files on the same Render product that does not spin down, at the price of zero dollars. The operator notes — commands, knobs, what to stop — live next to this log.

Operator notes PeerWeave hub Manticore-net (different tool) peerweave.com