7fe0cc3753
Near-1:1 clone of the prod remote-access stack, isolated on a new external dev_edge network and fronted by the same shared Caddy instance (dual-homed on edge + dev_edge). Dev is manual-start (not on boot). - Hostnames: app-dev / api-dev .linumiq.net, tunnels under *.dev.linumiq.net, dev tunnel ingress on port 7001. - Dev Supabase (project supabase-dev, *-dev containers), web, frps, redis, stripe-stub, bandwidth-worker with fresh independent secrets (gitignored). - Shared Caddyfile: app-dev -> web-dev, api-dev -> dev kong (+webhook block), *.dev -> frps-dev vhost. Caddy compose dual-homed on dev_edge. - On-demand-TLS authorizer (prod check-subdomain, in gitignored volumes/) extended additively: app-dev/api-dev -> 200; *.dev delegated to the dev authorizer. Prod allow-list logic unchanged. - dev.sh manual up/down/ps helper; README documents topology + secrets. Secrets, frps.toml, volumes/, web worktree and data dirs are gitignored.
109 lines
3.3 KiB
Caddyfile
109 lines
3.3 KiB
Caddyfile
{
|
|
email office@linumiq.com
|
|
on_demand_tls {
|
|
# SECURITY (R2/F3): closed allow-list authorizer. The edge function returns
|
|
# 200 only for reserved hosts (apex/app/api) and subdomains registered in
|
|
# the tunnels table; 403 otherwise. This prevents unbounded on-demand
|
|
# certificate issuance for arbitrary hostnames.
|
|
ask http://supabase-edge-functions:9000/check-subdomain
|
|
}
|
|
}
|
|
|
|
# SECURITY (R4/F10/W5): baseline response-hardening headers applied to the
|
|
# LinumIQ-controlled surfaces (apex/app/api). HSTS forces HTTPS for a year and
|
|
# is safe for first-party hostnames we fully control.
|
|
(security_headers) {
|
|
header {
|
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
|
X-Content-Type-Options "nosniff"
|
|
X-Frame-Options "SAMEORIGIN"
|
|
Referrer-Policy "no-referrer"
|
|
Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
|
Cross-Origin-Opener-Policy "same-origin"
|
|
-Server
|
|
-X-Powered-By
|
|
}
|
|
}
|
|
|
|
# Apex -> dashboard redirect
|
|
linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
import security_headers
|
|
redir https://app.linumiq.net{uri} permanent
|
|
}
|
|
|
|
# Reserved hostname: Next.js dashboard (upstream not yet running in Wave A)
|
|
app.linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
import security_headers
|
|
reverse_proxy web:3000
|
|
}
|
|
|
|
# Reserved hostname: Supabase API (Kong)
|
|
api.linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
import security_headers
|
|
# SECURITY (R2): block machine-only webhook functions from the public edge.
|
|
# auth-webhook and stripe-webhook are invoked internally over the docker
|
|
# network (supabase-edge-functions:9000) and must never be callable from the
|
|
# internet. get-node stays public for the Home Assistant add-on.
|
|
@blocked_webhooks path /functions/v1/auth-webhook* /functions/v1/stripe-webhook*
|
|
respond @blocked_webhooks 403
|
|
reverse_proxy supabase-kong:8000
|
|
}
|
|
|
|
# Wildcard tunnel subdomains -> frps vhost HTTP. Per-name HTTP-01 issued on first hit.
|
|
# NOTE: only HSTS is injected here; Home Assistant sets its own security headers
|
|
# (X-Frame-Options, etc.) and we must not override its CSP / framing behaviour.
|
|
*.linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
header Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
reverse_proxy frps:7080
|
|
}
|
|
|
|
# ============================================================================
|
|
# DEV environment (served by this same shared Caddy instance).
|
|
# Dev upstreams live on the external "dev_edge" network; Caddy is dual-homed on
|
|
# both "edge" (prod) and "dev_edge" (dev). On-demand TLS for these hosts is
|
|
# authorized by the global ask endpoint, which recognises the dev hostnames.
|
|
# ============================================================================
|
|
|
|
# Dev dashboard (Next.js, dev build)
|
|
app-dev.linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
import security_headers
|
|
reverse_proxy web-dev:3000
|
|
}
|
|
|
|
# Dev Supabase API (dev Kong)
|
|
api-dev.linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
import security_headers
|
|
@blocked_webhooks path /functions/v1/auth-webhook* /functions/v1/stripe-webhook*
|
|
respond @blocked_webhooks 403
|
|
reverse_proxy supabase-dev-kong:8000
|
|
}
|
|
|
|
# Dev wildcard tunnel subdomains -> dev frps vhost HTTP. More specific than
|
|
# *.linumiq.net, so dev tunnels match here. Only HSTS injected (HA sets its own
|
|
# framing/CSP headers).
|
|
*.dev.linumiq.net {
|
|
tls {
|
|
on_demand
|
|
}
|
|
header Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
reverse_proxy frps-dev:7080
|
|
}
|