How it works
flypod has two planes. A deploy pipeline ingests a zip into an immutable version, and a serve plane routes a subdomain to that version's files.
flypod is two planes. The deploy pipeline turns an uploaded zip into an immutable version and points a site at it. The serve plane maps an incoming request's subdomain to that site and returns its files. Everything else (versioning, TTL, ownership) hangs off these two.
The deploy pipeline
A deploy is a single POST /sites with a zip body. flypod processes it in
order:
Ingest the zip. Files are unpacked under size and count caps, with a path-traversal guard so no entry can escape the site root.
Render Markdown (if needed). If the upload has no index.html but does
contain Markdown files, flypod renders them into a small styled site.
Ensure an index.html exists. Every site must resolve / to something, so
flypod guarantees an index page is present.
Abuse scan. Contents are checked against abuse rules before anything goes live.
Detect SPA. flypod inspects the site to decide whether it's a single-page app. This flag drives the serve-plane fallback (below).
Store an immutable version. The processed content is hashed and stored as a version that never changes.
Create or point the site. A new site is created (or an existing one's live pointer is moved) to serve that version.
The response carries the live URL, the credentials
(tokens), the
expiry, anything flypod repaired during ingest
(healed), and any warnings, each carrying a fix_recipe a caller can act
on. It also carries a render key, which on flypod.dev is always
{"status": "pending"} — the hosted service runs no headless browser, so there
is no screenshot and no console capture. See
the HTTP API for the full response shape.
The serve plane
Each site lives at https://<site_id>.flypod.dev. The subdomain selects the
site. That's the entire routing model. A request to / serves the site's
/index.html.
Responses are cacheable and revalidate cheaply:
ETag: "<live_version_id>:<path>"
cache-control: public, max-age=60, must-revalidateThe ETag is the live version id plus the path, so a request that matches gets a
304 Not Modified. Because the version id changes on every deploy, a new
version automatically invalidates old cache entries.
SPA fallback
If a request path has no file extension and no file matches, flypod falls
back to serving index.html, but only if the live version was detected as a
single-page app. This lets client-side routers handle /about without a
real about.html. Static sites get a normal 404 for the same request.
Status codes
| Status | When |
|---|---|
200 | File found and served |
304 | ETag matched (If-None-Match) |
404 | Unknown host, or a missing file on a non-SPA site |
410 Gone | The site expired |
451 | The site was disabled by an operator |
SEO and indexing
flypod injects invisible attribution into served HTML: meta tags and JSON-LD,
no visible badge. Anonymous sites are additionally served with
x-robots-tag: noindex, keeping ephemeral deploys out of search engines.
HTTP API
The flypod REST API at https://flypod.dev deploys sites from a zip, redeploys new versions, rolls back, and manages accounts with bearer-token auth.
Versioning
Every deploy is an immutable version identified by a hash of its content; a single live pointer selects which version a site serves, moved by update and rollback.