feat(caddy): serve Caddy root CA at /ca.crt for guest trust
Air-gap mirror uses tls internal; guests must trust Caddy's local CA. Serve it at http://<domain>/ca.crt from a world-readable mount (the live pki dir is root-only 0600). build-stack --up mirror|full exports the CA after bring-up; landing page links it. Pre-creates the mount target to avoid a dir bind. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,3 +16,6 @@ www/
|
|||||||
landing/node_modules/
|
landing/node_modules/
|
||||||
landing/.astro/
|
landing/.astro/
|
||||||
landing/dist/
|
landing/dist/
|
||||||
|
|
||||||
|
# exported Caddy CA (per-deploy artifact)
|
||||||
|
caddy/caddy-root-ca.crt
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
# Static toggle — apex landing page + launcher downloads.
|
# Static toggle — apex landing page + launcher downloads.
|
||||||
# Mounted only when the stack runs with static files (build-stack.sh up static|full).
|
# Mounted only when the stack runs with static files (build-stack.sh up static|full).
|
||||||
http://{$BASE_DOMAIN} {
|
http://{$BASE_DOMAIN} {
|
||||||
|
# Caddy's local CA root, so guests can trust the air-gap HTTPS mirror.
|
||||||
|
# Mounted from ./caddy/caddy-root-ca.crt (exported by build-stack prep;
|
||||||
|
# the live pki dir is root-only 0600 and can't be served directly).
|
||||||
|
handle /ca.crt {
|
||||||
|
root * /srv/ca-pub
|
||||||
|
file_server
|
||||||
|
}
|
||||||
# Launcher downloads are a sibling mount (/srv/launcher), not nested under
|
# Launcher downloads are a sibling mount (/srv/launcher), not nested under
|
||||||
# the read-only /srv/www. handle_path strips the /launcher prefix.
|
# the read-only /srv/www. handle_path strips the /launcher prefix.
|
||||||
handle_path /launcher/* {
|
handle_path /launcher/* {
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ services:
|
|||||||
- ./caddy/conf.d/10-static.caddy:/etc/caddy/conf.d/10-static.caddy:ro
|
- ./caddy/conf.d/10-static.caddy:/etc/caddy/conf.d/10-static.caddy:ro
|
||||||
- ./www:/srv/www:ro
|
- ./www:/srv/www:ro
|
||||||
- ./mirror/launcher:/srv/launcher:ro
|
- ./mirror/launcher:/srv/launcher:ro
|
||||||
|
- ./caddy/caddy-root-ca.crt:/srv/ca-pub/ca.crt:ro
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export const site = {
|
|||||||
// packwiz modpack entrypoint.
|
// packwiz modpack entrypoint.
|
||||||
packwizUrl: `http://packwiz.${BASE_DOMAIN}/pack.toml`,
|
packwizUrl: `http://packwiz.${BASE_DOMAIN}/pack.toml`,
|
||||||
|
|
||||||
|
// Caddy local CA root — guests import this to trust the offline asset mirror.
|
||||||
|
caCertUrl: `http://${BASE_DOMAIN}/ca.crt`,
|
||||||
|
|
||||||
// Launcher downloads. Stable filenames are symlinks created by
|
// Launcher downloads. Stable filenames are symlinks created by
|
||||||
// tooling/fetch-launcher.sh — keep these in sync with that script.
|
// tooling/fetch-launcher.sh — keep these in sync with that script.
|
||||||
launcher: {
|
launcher: {
|
||||||
|
|||||||
@@ -50,6 +50,11 @@ const { launcher } = site;
|
|||||||
Need credentials? Register at <a href={site.authUrl}>{site.authUrl}</a>, then log in
|
Need credentials? Register at <a href={site.authUrl}>{site.authUrl}</a>, then log in
|
||||||
with that username and password.
|
with that username and password.
|
||||||
</p>
|
</p>
|
||||||
|
<p class="note">
|
||||||
|
Offline party? Download and trust the
|
||||||
|
<a href={site.caCertUrl}>local CA certificate</a> so the game-file
|
||||||
|
mirror works over HTTPS.
|
||||||
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -109,7 +109,32 @@ up() {
|
|||||||
log "PHASE up (mode=$mode)"
|
log "PHASE up (mode=$mode)"
|
||||||
have_script render-config.sh
|
have_script render-config.sh
|
||||||
tooling/render-config.sh # cheap; ensures configs match current .env
|
tooling/render-config.sh # cheap; ensures configs match current .env
|
||||||
|
|
||||||
|
# Static mode mounts ./caddy/caddy-root-ca.crt as a file at /srv/ca-pub/ca.crt.
|
||||||
|
# Pre-create it (empty) so Docker doesn't make a directory at that path; the
|
||||||
|
# real cert is exported below once Caddy's local CA exists.
|
||||||
|
case "$mode" in
|
||||||
|
static|full) [ -e caddy/caddy-root-ca.crt ] || : > caddy/caddy-root-ca.crt ;;
|
||||||
|
esac
|
||||||
|
|
||||||
"${COMPOSE[@]}" "${files[@]}" up -d
|
"${COMPOSE[@]}" "${files[@]}" up -d
|
||||||
|
|
||||||
|
# Mirror/full provision Caddy's local CA — export it so guests can trust the
|
||||||
|
# HTTPS asset mirror (served at http://${BASE_DOMAIN}/ca.crt in static/full).
|
||||||
|
case "$mode" in
|
||||||
|
mirror|full)
|
||||||
|
local i
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
docker exec caddy cat /data/caddy/pki/authorities/local/root.crt \
|
||||||
|
> caddy/caddy-root-ca.crt 2>/dev/null && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
[ -s caddy/caddy-root-ca.crt ] \
|
||||||
|
&& echo " exported Caddy CA → caddy/caddy-root-ca.crt (served at /ca.crt)" \
|
||||||
|
|| warn "Caddy CA not ready; export later: docker exec caddy cat /data/caddy/pki/authorities/local/root.crt > caddy/caddy-root-ca.crt"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
log "stack up (mode=$mode). apex: http://${BASE_DOMAIN} auth: http://auth.${BASE_DOMAIN}"
|
log "stack up (mode=$mode). apex: http://${BASE_DOMAIN} auth: http://auth.${BASE_DOMAIN}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user