docs: design the update manager + manifest generator #3
71
docs/caddy-updates.conf
Normal file
71
docs/caddy-updates.conf
Normal file
@@ -0,0 +1,71 @@
|
||||
# Caddy snippet for updates.jakubkadlec.dev.
|
||||
#
|
||||
# Drop this into the main Caddyfile on the VPS (or include it from there).
|
||||
# Caddy already handles TLS via Let's Encrypt for the parent zone; this block
|
||||
# only adds a subdomain that serves the update manifest, detached signature,
|
||||
# and content-addressed blob store.
|
||||
#
|
||||
# Directory layout on disk (owned by the release operator, not Caddy):
|
||||
#
|
||||
# /var/www/updates.jakubkadlec.dev/
|
||||
# ├── manifest.json
|
||||
# ├── manifest.json.sig
|
||||
# ├── manifests/
|
||||
# │ └── 2026.04.14-1.json (archived historical manifests)
|
||||
# ├── files/
|
||||
# │ └── <hash[0:2]>/<hash> content-addressed blobs
|
||||
# └── launcher/ Velopack feed (populated by Velopack's own publish tool)
|
||||
#
|
||||
# Create with:
|
||||
# sudo mkdir -p /var/www/updates.jakubkadlec.dev/{files,manifests,launcher}
|
||||
# sudo chown -R mt2.jakubkadlec.dev:mt2.jakubkadlec.dev /var/www/updates.jakubkadlec.dev
|
||||
#
|
||||
# Then add this to Caddy and `sudo systemctl reload caddy`.
|
||||
|
||||
updates.jakubkadlec.dev {
|
||||
root * /var/www/updates.jakubkadlec.dev
|
||||
|
||||
# Allow clients to resume interrupted downloads via HTTP Range.
|
||||
# Caddy's file_server sets Accept-Ranges: bytes by default, so there's
|
||||
# nothing extra to configure for this — listed explicitly as a reminder.
|
||||
file_server {
|
||||
precompressed gzip br
|
||||
}
|
||||
|
||||
# Content-addressed blobs are immutable (the hash IS the file name), so we
|
||||
# can tell clients to cache them forever. A manifest update never rewrites
|
||||
# an existing blob.
|
||||
@blobs path /files/*
|
||||
header @blobs Cache-Control "public, max-age=31536000, immutable"
|
||||
|
||||
# The manifest and its signature must never be cached beyond a minute —
|
||||
# clients need to see new releases quickly, and stale caches would delay
|
||||
# rollouts. Short TTL, not zero, to absorb thundering herds on release.
|
||||
@manifest path /manifest.json /manifest.json.sig
|
||||
header @manifest Cache-Control "public, max-age=60, must-revalidate"
|
||||
|
||||
# Historical manifests are as immutable as blobs — named by version.
|
||||
@archive path /manifests/*
|
||||
header @archive Cache-Control "public, max-age=31536000, immutable"
|
||||
|
||||
# The Velopack feed (launcher self-update) is a separate tree managed by
|
||||
# Velopack's publishing tool. Same cache rules as the main manifest: short
|
||||
# TTL on the feed metadata, blobs are immutable.
|
||||
@velopack-feed path /launcher/RELEASES*
|
||||
header @velopack-feed Cache-Control "public, max-age=60, must-revalidate"
|
||||
|
||||
@velopack-blobs path /launcher/*.nupkg
|
||||
header @velopack-blobs Cache-Control "public, max-age=31536000, immutable"
|
||||
|
||||
# CORS is not needed — the launcher is a native app, not a browser — so
|
||||
# no Access-Control-Allow-Origin header. If a web changelog page ever needs
|
||||
# to fetch the manifest from the browser, revisit this.
|
||||
|
||||
# Deny directory listings; the launcher knows exactly which paths it wants.
|
||||
file_server browse off 2>/dev/null || file_server
|
||||
|
||||
log {
|
||||
output file /var/log/caddy/updates.jakubkadlec.dev.access.log
|
||||
format json
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user