Self-hosted edge cache on a dedicated Incus container, sits between
clients and the MinIO EC:2 cluster. Replaces the need for an external
CDN at v1.0 traffic levels — handles thousands of concurrent listeners
on the R720, leaks zero logs to a third party.
This is the phase-1 alternative documented in the v1.0.9 CDN synthesis :
phase-1 = self-hosted Nginx, phase-2 = 2 cache nodes + GeoDNS, phase-3
= Bunny.net via the existing CDN_* config (still inert with
CDN_ENABLED=false).
- infra/ansible/roles/nginx_proxy_cache/ : install nginx + curl, render
nginx.conf with shared zone (128 MiB keys + 20 GiB disk,
inactive=7d), render veza-cache site that proxies to the minio_nodes
upstream pool with keepalive=32. HLS segments cached 7d via 1 MiB
slice ; .m3u8 cached 60s ; everything else 1h.
- Cache key excludes Authorization / Cookie (presigned URLs only in
v1.0). slice_range included for segments so byte-range requests
with arbitrary offsets all hit the same cached chunks.
- proxy_cache_use_stale error timeout updating http_500..504 +
background_update + lock — survives MinIO partial outages without
cold-storming the origin.
- X-Cache-Status surfaced on every response so smoke tests + operators
can verify HIT/MISS without parsing access logs.
- stub_status bound to 127.0.0.1:81/__nginx_status for the future
prometheus nginx_exporter sidecar.
- infra/ansible/playbooks/nginx_proxy_cache.yml : provisions the
Incus container + applies common baseline + role.
- inventory/lab.yml : new nginx_cache group.
- infra/ansible/tests/test_nginx_cache.sh : MISS→HIT roundtrip via
X-Cache-Status, on-disk entry verification.
Acceptance : smoke test reports MISS then HIT for the same URL ; cache
directory carries on-disk entries.
No backend code change — the cache is transparent. To route through it,
flip AWS_S3_ENDPOINT=http://nginx-cache.lxd:80 in the API env.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>