feat(hephaestus): front the stack with Caddy for automatic TLS

Add Hephaestus/caddy/Caddyfile - Caddy reverse-proxies both containers on
{$SITE_HOSTNAME} (from docker-compose .env): /auth/* -> auth-proxy:4000 with
the prefix stripped, / -> forgejo:3000 with a 2GB body cap for git push, LFS,
and release uploads. HTTPS via automatic Lets Encrypt (HTTP-01 on :80); SSH
git access stays on 2222 outside Caddy.

docker-compose.yml wires the new caddy service alongside the two existing
containers; auth-proxy/src/index.ts gets the minor upstream adjustment so
paths line up after Caddy strips the /auth prefix.
This commit is contained in:
Local Dev 2026-08-30 13:37:08 +02:00
parent 6f9040fdb4
commit 6afb196bec
3 changed files with 54 additions and 5 deletions

View file

@ -224,14 +224,14 @@ function loginHtml(opts: {
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Hephaestus — Sign in with wallet</title>
<link rel="stylesheet" href="/static/login.css">
<link rel="stylesheet" href="static/login.css">
</head>
<body>
<main id="app"
data-state="${escapeHtml(opts.state)}"
data-redirect-uri="${escapeHtml(opts.redirectUri)}"
data-oidc-nonce="${escapeHtml(opts.oidcNonce)}"></main>
<script type="module" src="/static/wallet.js"></script>
<script type="module" src="static/wallet.js"></script>
</body>
</html>`;
}

26
caddy/Caddyfile Normal file
View file

@ -0,0 +1,26 @@
# Caddy fronts the whole Hephaestus stack.
# - Automatic Let's Encrypt cert for code.silentmode.st (HTTP-01 challenge on :80)
# - Path-based routing:
# /auth/* → auth-proxy container (prefix stripped before forwarding)
# / → Forgejo container
# - HTTPS-only for browser traffic; SSH git access stays on port 2222 outside Caddy.
#
# {$SITE_HOSTNAME} is provided by docker-compose from .env (SITE_HOSTNAME).
{$SITE_HOSTNAME} {
encode gzip zstd
# Auth-proxy under /auth/*. handle_path STRIPS the /auth prefix before proxying,
# so /auth/challenge upstream is just /challenge on auth-proxy.
handle_path /auth/* {
reverse_proxy auth-proxy:4000
}
# Everything else → Forgejo. Big body size so git push + LFS + release uploads work.
handle {
reverse_proxy forgejo:3000
request_body {
max_size 2GB
}
}
}

View file

@ -1,4 +1,21 @@
services:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
environment:
SITE_HOSTNAME: ${SITE_HOSTNAME}
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
depends_on:
- forgejo
- auth-proxy
postgres:
image: postgres:16-alpine
restart: unless-stopped
@ -23,8 +40,9 @@ services:
CLIENT_SECRET: ${AUTH_PROXY_CLIENT_SECRET}
CHALLENGE_DOMAIN: ${AUTH_PROXY_CHALLENGE_DOMAIN}
FORGEJO_REDIRECT_URI: ${FORGEJO_ROOT_URL}user/oauth2/hephaestus-wallet/callback
ports:
- "4000:4000"
# Caddy proxies /auth/* → auth-proxy:4000 over the internal network. No public port.
expose:
- "4000"
volumes:
- auth-proxy-keys:/data
@ -65,8 +83,11 @@ services:
FORGEJO__oauth2_client__UPDATE_AVATAR: "false"
# Skip the web installer wizard — everything is already configured
FORGEJO__server__INSTALL_LOCK: "true"
# Caddy proxies / → forgejo:3000 over the internal network. No public HTTP port.
# 22 stays on 2222 for git-over-SSH (no TLS involved).
expose:
- "3000"
ports:
- "3000:3000"
- "2222:22"
volumes:
- forgejo-data:/data
@ -80,3 +101,5 @@ volumes:
postgres-data:
forgejo-data:
auth-proxy-keys:
caddy-data:
caddy-config: