Features

What the edge actually ships

Built from plan.txt: OpenResty edges, Go control plane, KeyCDN-compatible management API. First launch is CSS, JS, fonts, images, and other static files on a fast URL.

Delivery

Zones

Push and pull

Push/static files under /data/static/<zone>/ with sendfile. Pull zones append the request path to an origin (scheme+host). Zone names are lowercase alphanumeric, 1–20 chars — same constraint as KeyCDN.

Cache

Two SSD roots

Image cache 50g and other 20g so image waves cannot evict CSS and fonts. Default key $zone_id|$uri. Lock, revalidate, background update, and stale-on-error. Responses over 100 MB stream with X-Cache: BYPASS.

Purge

Zone or URL

Control fans out POST /internal/purge to every active edge. Snapshot carries a monotonic purge_generation as the correctness backstop. Browser caches are not purged.

Security and TLS

TLS

Shared, LE, custom

Shared wildcard on the zone domain, Let’s Encrypt for one alias per zone (lego on control), or a custom PEM. Optional HTTP→HTTPS 301. HTTP/2 on; HTTP/3 later.

Access

Referrers and tokens

Referrer allow/deny, empty-referrer toggle, secure token (optional bind-to-IP), CORS *, force download, block bad bots (451). Applied in Lua from the snapshot.

Headers

Edge identity

Server: cdn-server. X-Cache HIT|MISS|EXPIRED|STALE|BYPASS|UPDATING. X-Edge-Location. Accept-Ranges: bytes. Vary only when compressed.

Operations and API

Scale-out

DNS round-robin

No anycast. Each edge has a public IP. Dashboard prints A/AAAA records. Add a server from the operator UI; Ansible installs Docker and copies shared data — cache stays empty until filled on demand.

API

KeyCDN REST

HTTP Basic (API key as username, empty password). Zones, aliases, referrers, purge, reports, and credits with the KeyCDN envelope, parameters, and error codes. Rate limit 60/min.

Panel

Customer + operator

Zones, media library, FTP users, reports, tickets, packages and credits. Operator console manages nodes, users, packages, redeem codes, and transactions.

Image processing

Optional imgproxy (Go + libvips) when a zone has image processing enabled and the request carries transform query parameters. nginx caches the transformed bytes so libvips runs once per variant.

Out of first-launch scope

Streaming, HLS, CMS plugins, anycast, and HTTP/3 are catalogued for later. Stack does not include Redis, Elasticsearch, Kafka, MinIO, Varnish, Node, PHP, or Python app servers on the hot path.