Lab HTTPS — Gateway Fabric + Let's Encrypt¶
Expose MeshFlows lab hostnames over HTTPS using nginx Gateway Fabric (Kubernetes Gateway API) and cert-manager with Let's Encrypt HTTP-01 challenges.
Internal reference: internal/lab-https-setup.md (operator notes).
Hostnames¶
| Subdomain | Service |
|---|---|
lab-gateway.meshflows.org |
Gateway API |
lab-dashboard.meshflows.org |
Dashboard |
lab-wiki.meshflows.org |
Wiki |
lab-identity.meshflows.org |
Identity (OAuth, login, API keys) |
Other environments follow the same pattern (dev-*, tst-*, …).
Architecture¶
Internet (*.meshflows.org)
│ :80 / :443
▼
Fritzbox → node:30080 (HTTP) / :30443 (HTTPS)
▼
edge-router (meshflows-edge) — Host/SNI routing
├─ HTTP :80 → 301 https://$host$request_uri (ACME /.well-known proxied to env :80)
├─ HTTPS :443 SNI lab-* → meshflows-nginx.meshflows-lab:443
├─ HTTPS :443 SNI dev-* → meshflows-nginx.meshflows-dev:443
└─ code / webmail → meshflows-nginx.meshflows-lab:443
▼
Per-env nginx Gateway Fabric (internal HTTPS NodePorts 31101 / 31201 / …)
└─ HTTPRoutes → dashboard, gateway, identity, wiki services
Unknown hostnames return HTTP 404 from nginx Gateway Fabric (or from edge-router when no Host map matches).
Public clients should use either http:// or https:// hostnames; plain HTTP is redirected to HTTPS at the edge. HTTPS→HTTP is not used (TLS is the canonical scheme).
Relevant manifests:
engine/deploy/overlays/linux-cluster/infra/— Gateway + HTTPRoute hostname patcheswiki/deploy/k8s/— Wiki Gateway + HTTPRoute.github/workflows/infra.yml— cluster infrastructure install
Step 1 — DNS¶
Create A records at your registrar pointing to your public IP:
lab-gateway.meshflows.org A <public IP>
lab-dashboard.meshflows.org A <public IP>
lab-wiki.meshflows.org A <public IP>
lab-identity.meshflows.org A <public IP>
Step 2 — Fritzbox Port Forwards¶
| Protocol | External | Internal (server) |
|---|---|---|
| TCP | 80 | 30080 |
| TCP | 443 | 30443 |
Port 80 is required for ACME HTTP-01. Public HTTP traffic is 301-redirected to HTTPS by edge-router (engine/scripts/reconcile-edge-router.sh); ACME challenge paths are proxied to the env gateway without redirect. Each env Gateway also has an http-to-https HTTPRoute as a fallback.
Step 3 — Roll Out Infrastructure¶
Forgejo Actions → Deploy Cluster Infrastructure (infra.yml):
components : all
acme_email : you@email.example
environment: lab
This installs (in order):
- Gateway API CRDs (v1.5.0)
- nginx Gateway Fabric (NodePort 30080/30443)
- GatewayClass
nginx - cert-manager (
enableGatewayAPI=true) - cert-manager solver Gateway
- Let's Encrypt ClusterIssuers (
letsencrypt-prod+letsencrypt-staging)
See Gateway API Migration for migration from ingress-nginx.
Step 4 — Deploy Application Manifests¶
Via CI (recommended):
deploy.yml → environment=lab, release_id=<from build>
Or manually:
kubectl apply -k engine/deploy/overlays/linux-cluster/
kubectl apply -k wiki/deploy/k8s/
cert-manager requests certificates via Gateway TLS listeners (HTTP-01).
TLS issuer defaults in deploy: all environments (incl. dev) → letsencrypt-prod.
Use tls_issuer=letsencrypt-staging only as an explicit override. Deploy preserves an
existing production meshflows-tls secret; cert-manager renews automatically before expiry.
If an environment still has a staging certificate (e.g. after switching defaults),
deploy removes it once and re-issues via letsencrypt-prod (see
engine/scripts/reconcile-tls-certificate.sh).
Verification¶
kubectl get gateway -A
kubectl get httproute -A
kubectl get certificate -n meshflows-lab
kubectl describe certificate meshflows-tls -n meshflows-lab
curl -H "Host: lab-gateway.meshflows.org" http://<server-LAN-IP>:30080/
# → 301 redirect to https://
curl -k https://lab-gateway.meshflows.org/
Known Pitfalls¶
| Issue | Fix |
|---|---|
| NodePorts not 30080/30443 | Re-run infra.yml |
| cert-manager misses listeners | Verify cert-manager.io/cluster-issuer on Gateway and enableGatewayAPI=true |
| HTTP-01 fails | Check Fritzbox port 80 → 30080; ISP blocking |
| DNS not propagated | Wait; cert-manager retries |
| Let's Encrypt rate limit | Prefer leaving existing meshflows-tls in place; cert-manager renews before expiry. Staging issuer only for deliberate tests (max ~5 prod certs/domain/week). |