ServeProxy

ServeProxy CDN documentation

Point your domain at the CDN, give it your origin, and static files are cached at the edge. Purge them with one API call. Bandwidth is metered per location.

ServeProxy CDN is a multi-node caching proxy. Static assets are cached at the edge and served from the closest available node.

A cache miss fetches the file from your origin, stores the response and serves it. Later requests are served from cache without touching your origin.

Each CDN location maps one or more hostnames to a single origin. You manage locations from the dashboard.

Getting started

  1. Create a location. Sign in to the dashboard and add a location with your origin URL, for example https://origin.example.com.
  2. Note your CDN hostname. The dashboard assigns a hostname under .cdn.serveproxy.com. You can also attach a custom domain.
  3. Save your API key. Each location has its own key, used for purges and stats.
  4. Point your DNS at the CDN. See DNS setup.
  5. Test it. Request a static file through the CDN hostname and check the response headers.

DNS setup

A custom domain must resolve by CNAME to a hostname under .cdn.serveproxy.com. The CDN checks this on its next config sync. Until the check passes, the domain is skipped and won't serve traffic.

assets.example.com.  CNAME  your-location.cdn.serveproxy.com.

Once the CNAME resolves correctly, a TLS certificate is issued and the domain goes live within a minute or two.

If you use Cloudflare for DNS, set this record to DNS only (grey cloud). Proxying through Cloudflare on top of the CDN breaks verification.

Cache behaviour

What gets cached

Only GET requests for static file extensions are cached. Everything else is passed straight through to your origin.

Cached extensions include images (jpg png webp avif svg gif ico), fonts (woff woff2 ttf eot otf), scripts and styles (css js mjs map wasm), media (mp4 webm mp3 ogg wav flac) and documents (pdf json xml txt csv zip).

How long

If your origin sends Cache-Control: max-age=N, the CDN uses it. Responses marked no-store or private are not cached. Without a header, these defaults apply:

Content typeDefault TTL
Images (jpg, png, webp, avif, svg, gif, ico)7 days
CSS, JS, fonts30 days
JSON, XML1 hour
Everything else cacheable1 hour

Stale-while-revalidate

When an entry has expired but is still inside its stale window, the CDN serves the cached copy immediately and refreshes it from your origin in the background. If your origin sends stale-while-revalidate=N, that value is used; otherwise the window equals the TTL.

Conditional requests

Background refreshes send If-None-Match and If-Modified-Since when the cached entry has an ETag or Last-Modified. A 304 Not Modified reply saves bandwidth and simply extends the TTL.

Response headers

HeaderMeaning
X-CacheHIT if served from cache, MISS if fetched from your origin
X-Cache-AgeHow long the cached entry has been stored, in seconds
X-Served-ByThe CDN node that served the request
curl -I https://your-location.cdn.serveproxy.com/logo.png

Purge API

Clears cached entries on every node.

A request to one node is passed on to all the others, so you only need to call it once.

GET https://your-location.cdn.serveproxy.com/_cdn/purge
ParameterDescription
keyRequired. Your location's API key.
urlPurge a single URL. Pass the path including any query string.
allSet to true to clear the whole cache for this location.

Either url or all=true must be set.

Purge one file

curl "https://your-location.cdn.serveproxy.com/_cdn/purge?key=YOUR_KEY&url=/images/logo.png"

Purge everything

curl "https://your-location.cdn.serveproxy.com/_cdn/purge?key=YOUR_KEY&all=true"

Response

JSON with the totals from all nodes combined:

{
  "ok": true,
  "hostname": "edge-01",
  "host": "your-location.cdn.serveproxy.com",
  "backend": "https://origin.example.com",
  "action": "url",
  "url": "/images/logo.png",
  "total_entries": 4,
  "total_freed": "1.2 MB",
  "duration_ms": 87,
  "timestamp": "2026-05-27T10:15:00Z"
}

The API key travels in the query string. Don't paste purge URLs into chat logs, issue trackers or anywhere that gets archived. If a key leaks, regenerate it from the dashboard.

Stats API

Returns cache statistics for your location, summed across all nodes. Useful for monitoring.

curl "https://your-location.cdn.serveproxy.com/_cdn/stats?key=YOUR_KEY"
{
  "ok": true,
  "hostname": "edge-01",
  "host": "your-location.cdn.serveproxy.com",
  "backend": "https://origin.example.com",
  "cached_urls": 6240,
  "total_size": "2.4 GB",
  "timestamp": "2026-05-27T10:15:00Z"
}

Each node caches these numbers for 30 seconds, so values may lag briefly after a purge.

Rate limits

Each client IP may make 500 requests per second, with bursts up to 1,000. Clients over the limit receive 429 Too Many Requests with a Retry-After header.

The limit applies to every endpoint, including /_cdn/purge and /_cdn/stats. It is counted per node, so the effective ceiling across the network is higher.

Troubleshooting

A custom domain returns 502

The CDN only serves domains that resolve by CNAME to .cdn.serveproxy.com. Check the record with dig CNAME yourdomain.com. Verification retries on every config sync, every 30 seconds.

X-Cache always shows MISS

The file may not have a cached extension, your origin may send Cache-Control: no-store, or each request may land on a different node. Caches fill per node as traffic arrives.

Old content is still served after a purge

Check total_entries in the purge response. If it's 0, the entry was already gone or the URL didn't match. The url parameter must match exactly, including the query string.

Origin changes don't show up

Static assets are cached for up to 30 days by default. Send a shorter Cache-Control: max-age from your origin, version your asset URLs, or call the purge API after each deploy.

The first request on a new node is slow

The first request for a URL on each node is always a miss and goes to your origin. After that the node serves it from cache, and stale-while-revalidate keeps responses fast when entries expire.

Support

Questions, bug reports and feature requests: [email protected]