Skip to content

Commit 5259229

Browse files
Caddyfile: fix invalid substr() placeholder + simplify rewrites
Original config had `{uri.path.substr(10}` and `{uri.path.substr(5}` in the apex redirect rules — both are invalid Caddy syntax (no substr() placeholder exists, AND a paren was missing). Caddy rejected the new config on every reload and kept the old apex-only config running, which is why api./console./docs. had no certs. Rewrites: - Apex redirects to subdomains now use path_regexp matchers with named captures, e.g. @Dash path_regexp dash ^/dashboard(/.*)?$ redir @Dash https://console.zeroauth.dev{re.dash.1} permanent Empty capture for a bare /dashboard request canonicalises to /dashboard/ on the receiving side — Caddy handles that. - console.zeroauth.dev + docs.zeroauth.dev path prefixing now uses `rewrite * /dashboard{uri}` / `rewrite * /docs{uri}`, a single standard Caddy v2 directive. Removed the prior 'rewrite /' + 'rewrite /*' pair that would have double-rewritten. - api.zeroauth.dev dropped the catch-all 404 fence. Upstream Express handles the routing; on this vhost everything proxies through. Header forwarding (X-Real-IP / X-Forwarded-* incl. X-Forwarded-Host) stays identical across all four vhosts.
1 parent de158e1 commit 5259229

1 file changed

Lines changed: 18 additions & 40 deletions

File tree

Caddyfile

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,14 @@
33
#
44
# Usage on the production host:
55
# docker compose --profile prod up -d --build
6-
#
7-
# This Caddyfile is consumed by the `caddy` service in docker-compose.yml,
8-
# which is on the same Compose network as `zeroauth-prod`, so we reach the
9-
# app via its service name.
6+
# docker exec zeroauth-caddy caddy reload --config /etc/caddy/Caddyfile
107
#
118
# DNS prerequisites (operator action, before deploy):
129
# A zeroauth.dev → 104.207.143.14
1310
# A www.zeroauth.dev → 104.207.143.14
1411
# A api.zeroauth.dev → 104.207.143.14
1512
# A console.zeroauth.dev → 104.207.143.14
1613
# A docs.zeroauth.dev → 104.207.143.14
17-
# (or CNAMEs aliasing the apex). All five hostnames terminate at this one
18-
# Caddy instance which routes by Host header to the right path-prefix on
19-
# the upstream Express app. Same backend container; different vhost,
20-
# different rewrite.
2114

2215
# ─── Shared snippets ────────────────────────────────────────────
2316
(security_headers) {
@@ -41,20 +34,21 @@
4134
}
4235
}
4336

44-
# ─── Apex: marketing site + signup ─────────────────────────────
37+
# ─── Apex: marketing site + signup + apex 308s for legacy paths
4538
zeroauth.dev, www.zeroauth.dev {
4639
encode zstd gzip
4740

48-
# The apex serves /public/index.html and the marketing /demo.html.
49-
# Anything under /v1, /api, /dashboard, /docs that hits the apex
50-
# gets a 308 to the new canonical subdomain so legacy URLs don't
51-
# silently break for bookmarks + CI scripts.
52-
redir /v1/* https://api.zeroauth.dev{uri} permanent
53-
redir /api/* https://api.zeroauth.dev{uri} permanent
54-
redir /dashboard /dashboard/ permanent
55-
redir /dashboard/* https://console.zeroauth.dev{uri.path.substr(10}{uri.query} permanent
56-
redir /docs /docs/ permanent
57-
redir /docs/* https://docs.zeroauth.dev{uri.path.substr(5}{uri.query} permanent
41+
# Legacy URLs from the pre-split era get a permanent redirect to
42+
# the right subdomain. Use path_regexp with capture groups to keep
43+
# the suffix (so /dashboard/login → console.zeroauth.dev/login).
44+
@dash path_regexp dash ^/dashboard(/.*)?$
45+
redir @dash https://console.zeroauth.dev{re.dash.1} permanent
46+
47+
@docs path_regexp doc ^/docs(/.*)?$
48+
redir @docs https://docs.zeroauth.dev{re.doc.1} permanent
49+
50+
redir /v1/* https://api.zeroauth.dev{uri} permanent
51+
redir /api/* https://api.zeroauth.dev{uri} permanent
5852

5953
reverse_proxy zeroauth-prod:3000 {
6054
header_up X-Real-IP {remote_host}
@@ -72,40 +66,26 @@ zeroauth.dev, www.zeroauth.dev {
7266
api.zeroauth.dev {
7367
encode zstd gzip
7468

75-
# Strip the public path to map onto the same Express app. The
76-
# upstream still recognises /v1/* and /api/*; on api.zeroauth.dev
77-
# we keep the URI as-is (no rewrite) — clients hit
78-
# https://api.zeroauth.dev/v1/verifications which proxies to
79-
# zeroauth-prod:3000/v1/verifications.
8069
reverse_proxy zeroauth-prod:3000 {
8170
header_up X-Real-IP {remote_host}
8271
header_up X-Forwarded-For {remote_host}
8372
header_up X-Forwarded-Proto https
8473
header_up X-Forwarded-Host {host}
8574
}
8675

87-
# Hard 404 on any request to a non-API path so api.zeroauth.dev
88-
# doesn't accidentally serve dashboard / docs HTML if the
89-
# upstream's catch-all routes change.
90-
@nonapi not path /v1/* /api/* /.well-known/* /health
91-
respond @nonapi "Not an API route" 404
92-
9376
import security_headers
9477
import json_log
9578
}
9679

9780
# ─── console.zeroauth.dev — developer console ───────────────────
81+
# The upstream Express app serves the dashboard SPA at /dashboard/*.
82+
# On this vhost users see a bare-domain UX, so we rewrite the request
83+
# path to add the /dashboard prefix before proxying upstream.
9884
console.zeroauth.dev {
9985
encode zstd gzip
10086

101-
# Strip /dashboard prefix expected by the Vite-built SPA. Express
102-
# serves the dashboard at /dashboard/*; on console.zeroauth.dev we
103-
# want users to land at "/", so rewrite incoming "/" → "/dashboard/".
104-
rewrite / /dashboard/
105-
rewrite /* /dashboard{uri}
87+
rewrite * /dashboard{uri}
10688

107-
# Cookies issued by /api/console/* are scoped to ".zeroauth.dev" so
108-
# the console + API share session state across the subdomain boundary.
10989
reverse_proxy zeroauth-prod:3000 {
11090
header_up X-Real-IP {remote_host}
11191
header_up X-Forwarded-For {remote_host}
@@ -122,9 +102,7 @@ console.zeroauth.dev {
122102
docs.zeroauth.dev {
123103
encode zstd gzip
124104

125-
# Same rewrite story — strip /docs/* from the upstream path.
126-
rewrite / /docs/
127-
rewrite /* /docs{uri}
105+
rewrite * /docs{uri}
128106

129107
reverse_proxy zeroauth-prod:3000 {
130108
header_up X-Real-IP {remote_host}

0 commit comments

Comments
 (0)