diff --git a/inventories/production/group_vars/all/reverse_proxy.yml b/inventories/production/group_vars/all/reverse_proxy.yml index 83b8e62..755038f 100644 --- a/inventories/production/group_vars/all/reverse_proxy.yml +++ b/inventories/production/group_vars/all/reverse_proxy.yml @@ -3,4 +3,15 @@ reverse_proxy__acme_email: admin@wingu.me reverse_proxy__routes: - {host: test.askari.wingu.me, respond: "boma reverse proxy"} - # M4b appends: {host: netbird.askari.wingu.me, upstream: "netbird-dashboard:80"} + # NetBird control plane (M4b). gRPC (h2c) + WebSocket + path-based routing to two + # backend containers on the shared `boma` Docker network (ADR-024, ADR-016). + - host: netbird.askari.wingu.me + caddy: | + # gRPC needs HTTP/2 cleartext (h2c) to the backend + @grpc header Content-Type application/grpc* + reverse_proxy @grpc h2c://netbird-server:80 + # management REST, embedded IdP, relay + ws-proxy (WebSocket) — same backend + @backend path /relay* /ws-proxy/* /api/* /oauth2/* + reverse_proxy @backend netbird-server:80 + # dashboard SPA (everything else) + reverse_proxy /* netbird-dashboard:80 diff --git a/roles/reverse_proxy/molecule/default/converge.yml b/roles/reverse_proxy/molecule/default/converge.yml index c521771..40aa788 100644 --- a/roles/reverse_proxy/molecule/default/converge.yml +++ b/roles/reverse_proxy/molecule/default/converge.yml @@ -11,6 +11,10 @@ upstream: "app:80" - host: t.example.test respond: "ok" + - host: grpc.example.test + caddy: | + @grpc header Content-Type application/grpc* + reverse_proxy @grpc h2c://backend:80 roles: - role: reverse_proxy diff --git a/roles/reverse_proxy/molecule/default/verify.yml b/roles/reverse_proxy/molecule/default/verify.yml index 6fbb7d0..8316e93 100644 --- a/roles/reverse_proxy/molecule/default/verify.yml +++ b/roles/reverse_proxy/molecule/default/verify.yml @@ -15,5 +15,7 @@ - "'app.example.test' in (_caddyfile.content | b64decode)" - "'reverse_proxy app:80' in (_caddyfile.content | b64decode)" - "'respond \"ok\" 200' in (_caddyfile.content | b64decode)" + - "'grpc.example.test' in (_caddyfile.content | b64decode)" + - "'reverse_proxy @grpc h2c://backend:80' in (_caddyfile.content | b64decode)" fail_msg: "Caddyfile is missing expected content" success_msg: "Caddyfile rendered correctly" diff --git a/roles/reverse_proxy/templates/Caddyfile.j2 b/roles/reverse_proxy/templates/Caddyfile.j2 index d84da68..0c0a280 100644 --- a/roles/reverse_proxy/templates/Caddyfile.j2 +++ b/roles/reverse_proxy/templates/Caddyfile.j2 @@ -9,11 +9,13 @@ {% endif %} } {% for r in reverse_proxy__routes %} -{{ r.host }} { -{% if r.upstream is defined %} - reverse_proxy {{ r.upstream }} +{{ r['host'] }} { +{% if r['caddy'] is defined %} +{{ r['caddy'] | trim | indent(2, first=true) }} +{% elif r['upstream'] is defined %} + reverse_proxy {{ r['upstream'] }} {% else %} - respond "{{ r.respond | default('boma') }}" 200 + respond "{{ r['respond'] | default('boma') }}" 200 {% endif %} } {% endfor %}