Two gaps found while walking through a real single-tenant deployment scenario, both fixed and verified against the actual running stack (not just unit tests): - wg-easy moves to network_mode: host so Traefik can actually route to WireGuard peer addresses (wg-quick's route only existed inside wg-easy's own isolated network namespace before). This forced host-level sysctls (ops/host-sysctls.sh — Docker/runc rejects namespaced sysctls under host networking) and a host firewall rule (ops/firewall.sh) to keep wg-easy's now-unisolated admin API off the public interface. - control-plane gets a real Traefik route (traefik/dynamic/control-plane.yml.example) instead of being reachable only at 127.0.0.1:8090 — box registration carries a WireGuard private key and needs TLS, not bare loopback HTTP. Along the way, running the actual pinned wg-easy image (ghcr.io/wg-easy/wg-easy:14) surfaced that it's a different, older, Express-based codebase than what wg-easy's current docs/master branch describe: auth is a plain Authorization header per request (no session cookie), routes live under /api/wireguard/client, and its default WG_ALLOWED_IPS is full-tunnel (0.0.0.0/0) rather than the split-tunnel this design assumed. wgeasy.py and docker-compose.yaml are corrected accordingly, verified end-to-end against the real container. Also fixed: Docker Compose silently truncates a bcrypt hash's `$` characters when read from .env — documented the required $$ escaping.
28 lines
1.2 KiB
Text
28 lines
1.2 KiB
Text
# Copy to traefik/dynamic/control-plane.yml with GATEWAY_CONTROL_PLANE_HOST
|
|
# substituted for a real hostname you control (e.g. gw.example.com, with its
|
|
# own A/AAAA record pointing at this VPS).
|
|
#
|
|
# Without this file, the control-plane API is only reachable at
|
|
# 127.0.0.1:8090 on the gateway host itself — fine for a local health
|
|
# check, useless for a real remote Furtka box, which needs this over HTTPS
|
|
# anyway: the registration response carries a WireGuard private key in
|
|
# plaintext JSON, so that call must never go out over bare HTTP.
|
|
#
|
|
# GATEWAY_MODE=single: keep the certResolver line below (HTTP-01 per host,
|
|
# same as every app route — see traefik.single.yml).
|
|
# GATEWAY_MODE=shared: delete the `tls:` block entirely — the shared
|
|
# wildcard defaultGeneratedCert (traefik/dynamic/default-cert.yml) already
|
|
# covers every hostname under GATEWAY_BASE_DOMAIN, this included.
|
|
http:
|
|
routers:
|
|
control-plane:
|
|
rule: "Host(`GATEWAY_CONTROL_PLANE_HOST`)"
|
|
entryPoints: [websecure]
|
|
service: control-plane
|
|
tls:
|
|
certResolver: le
|
|
services:
|
|
control-plane:
|
|
loadBalancer:
|
|
servers:
|
|
- url: "http://control-plane:8090"
|