Merge feature/vpn-openvpn-mtu into main
This commit is contained in:
3 files changed
+32
-13
No files matched your search
@@ -544,3 +544,19 @@ small fixed-size packets → **not MTU-sensitive** like OpenVPN's TLS handshake,
|
||||
Gluetun's control API — matters only when qBittorrent/natmap is built (Phase 6), not now. `vpn-egress`
|
||||
disabled meanwhile (crashloop would fire false alerts). Awaiting operator's architect decision before the
|
||||
container swap.
|
||||
|
||||
### Phase 3 VPN — ACTUAL root cause: Cilium VXLAN pod MTU (2026-08-22)
|
||||
Operator (correctly) rejected the port theory (client uses ephemeral src ports; dest port is irrelevant to
|
||||
return traffic) and had me check MTU at each layer. Findings via `ping -M do` sweeps:
|
||||
- **Pod** → internet: MTU 1450 OK, 1470 DROP (silent). Pod `eth0` shows 1500 but the effective route is 1450.
|
||||
- **Node** (k3s-dev-3) → internet: **1500 OK**. All node ifaces (ens3, cilium_*, lxc*) = 1500.
|
||||
- **Hypervisor** → internet: **1500 OK**. (Google Fiber SOHO router hands off full 1500 — not the culprit.)
|
||||
- Cilium config: **`routing-mode: tunnel`, `tunnel-protocol: vxlan`** → Cilium subtracts the 50-byte VXLAN
|
||||
overhead → **pod MTU 1450**. OpenVPN emits ~1500-byte handshake packets → exceed 1450 → dropped (broken
|
||||
PMTUD = no ICMP back). This is why HTTPS (MSS-clamped) + small UDP (DNS/NTP) work but OpenVPN doesn't.
|
||||
|
||||
**Fix (operator's choice: "shrink OpenVPN MTU in gluetun"):** set gluetun `OPENVPN_MTU=1350` (tun-mtu) and
|
||||
`OPENVPN_MSSFIX=1350` so encrypted packets (~1350+52 ≈ 1402) fit under the 1450 pod MTU. Keeps OpenVPN +
|
||||
Cilium VXLAN unchanged. Port kept at 8080 (confirmed PIA responds). Re-enabled `vpn-egress`. Values hardcoded
|
||||
as quoted strings (int-coercion gotcha). Alternatives not taken: Cilium native routing (pod MTU→1500) or
|
||||
WireGuard/thrnz (MTU-robust) — both still available if the MTU shrink proves insufficient.
|
||||
@@ -17,13 +17,11 @@ resources:
|
||||
- cert-manager # Let's Encrypt DNS-01 wildcard — needs SOPS `cloudflare-api-token`
|
||||
- externaldns # auto DNS records — needs SOPS `cloudflare-api-token`
|
||||
- gateway # Gateway API listeners (ingress; replaces Traefik)
|
||||
# ---- Phase 3 — Egress / VPN — DISABLED, ESCALATED for an architect decision. OpenVPN via Gluetun
|
||||
# cannot connect on this network: 1197 conflicts with the home OpenVPN server; 53 is DNS-
|
||||
# intercepted; 8080 reaches TLS but the handshake fails across servers (MTU on WiFi+triple-NAT).
|
||||
# NTP/123 works, so it's OpenVPN-specific, not a UDP block. Recommendation: pivot to WireGuard
|
||||
# via thrnz/docker-wireguard-pia (PIA WG = UDP 1337, small MTU-robust handshake, ADR-0013's
|
||||
# documented fallback, operator's original preference). See DECISIONS-LOG "Phase 3 VPN". ----
|
||||
# - vpn-egress # re-enable after the architect decision (thrnz/WireGuard build)
|
||||
# ---- Phase 3 — Egress / VPN (PIA OpenVPN-UDP, ADR-0013 amendment). Root cause of earlier failures:
|
||||
# Cilium VXLAN gives pods MTU 1450 (node/host/WAN all 1500), so OpenVPN's 1500-byte handshake
|
||||
# packets were dropped. Fix: OPENVPN_MTU/MSSFIX=1350 in gluetun-gateway.yaml so packets fit 1450.
|
||||
# See DECISIONS-LOG "Phase 3 VPN". ----
|
||||
- vpn-egress # shared Gluetun PIA/OpenVPN-UDP egress gateway + kill-switch (ADR-0013)
|
||||
# ---- Phase 4 — Observability (creds provisioned via SOPS: grafana-admin, alertmanager-smtp) ----
|
||||
- monitoring # kube-prometheus-stack + Loki + Alloy + Alertmanager
|
||||
# ---- Later phases: enabled when their phase opens ----
|
||||
|
||||
@@ -41,12 +41,17 @@ spec:
|
||||
- name: VPN_TYPE
|
||||
value: "openvpn" # OpenVPN-UDP — satisfies "protocol != TCP" (R-NET); ADR-0013 amended
|
||||
- name: OPENVPN_ENDPOINT_PORT
|
||||
value: "8080" # NOT 1197 (home NATs its own OpenVPN server there → replies never
|
||||
# return) and NOT 53 (this network transparently intercepts :53 DNS,
|
||||
# swallowing OpenVPN-over-53). 8080 verified: arbitrary UDP works here
|
||||
# (NTP/123 test). Hardcoded string (not ${var}): Flux/kustomize strips
|
||||
# quotes on "${VAR}" → int coercion k8s rejects (Longhorn-fix gotcha).
|
||||
# Valid PIA ports: 53, 1194, 1197, 1198, 8080, 9201. See DECISIONS-LOG.
|
||||
value: "8080" # 8080: PIA confirmed responding here; avoid 53 (this network
|
||||
# intercepts DNS/:53). Port is NOT the root cause — MTU is (below).
|
||||
# Hardcoded string (not ${var}): Flux/kustomize strips quotes on
|
||||
# "${VAR}" → int coercion k8s rejects (Longhorn-fix gotcha).
|
||||
# --- MTU: Cilium runs VXLAN (routing-mode tunnel), so pods get MTU 1450 (1500 − 50 encap) while
|
||||
# the node/host/WAN are all 1500. OpenVPN's default 1500-byte packets exceed 1450 and are
|
||||
# dropped (PMTUD broken). Shrink tun-mtu so packets fit: 1350 + ~52 overhead ≈ 1402 < 1450. ---
|
||||
- name: OPENVPN_MTU
|
||||
value: "1350" # tun-mtu; keeps encrypted UDP packets under the 1450 pod MTU
|
||||
- name: OPENVPN_MSSFIX
|
||||
value: "1350" # clamp TCP-in-tunnel to match, avoid in-tunnel fragmentation
|
||||
# PIA credentials from the SOPS secret (Gluetun's PIA OpenVPN creds env):
|
||||
- name: OPENVPN_USER
|
||||
valueFrom:
|
||||
|
||||
Reference in new issue
Block a user