From 53d74768ad26518edee303da13ae573fb846a14e Mon Sep 17 00:00:00 2001 From: Ruben Hensen Date: Mon, 26 Oct 2026 23:11:38 +0100 Subject: [PATCH 1/2] gateway: take the visitor's address from a PROXY header node001 passes TLS through without opening it, so every request from the tunneled hosts arrives from 46.224.26.65. Wordfence locked that address out after 20 failed logins on 2026-10-26, and with it everyone who logs in to scoutingmbg.nl. With a PROXY header from node001, Envoy puts the visitor's address in X-Forwarded-For instead. The header is optional: s2 and ntfy2 point straight at home, and node001's proxy on port 80 sends none either. --- gateway/proxy-protocol.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 gateway/proxy-protocol.yaml diff --git a/gateway/proxy-protocol.yaml b/gateway/proxy-protocol.yaml new file mode 100644 index 0000000..123f7e7 --- /dev/null +++ b/gateway/proxy-protocol.yaml @@ -0,0 +1,23 @@ +# node001 passes TLS for the tunneled hosts through without opening it, so +# without this every request arrives from 46.224.26.65. Wordfence locks that +# address out after 20 failed logins (2026-10-26), and with it everyone who +# logs in to scoutingmbg.nl. node001 puts a PROXY header with the visitor's +# address in front of each connection; Envoy takes the address from there +# and adds it to X-Forwarded-For. +# +# Optional, because s2 and ntfy2 point straight at home and their clients +# send no header, and neither does node001's proxy on port 80. The price: +# whoever connects to the home address directly can send a header of their +# own and claim any address. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: ClientTrafficPolicy +metadata: + name: proxy-protocol + namespace: envoy-gateway-system +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: homelab + proxyProtocol: + optional: true From 30540ea57987cdf8c8262336bcf7b2c250c1041a Mon Sep 17 00:00:00 2001 From: Ruben Hensen Date: Mon, 26 Oct 2026 23:11:38 +0100 Subject: [PATCH 2/2] node001: send the visitor's address to the home cluster The stream server on 443 now starts each connection with a PROXY header. nginx sends it to every upstream or none, so Stalwart (8443) and the local nginx for Gatus and ntfy (8444) get theirs through a hop on 8445/8446 that takes it off again; nothing changes for them. Deploy after the Gateway accepts the header, or the tunneled hosts stop answering until it does. --- nix-infra-machine/nodes/node001.nix | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/nix-infra-machine/nodes/node001.nix b/nix-infra-machine/nodes/node001.nix index ba80b9d..dd29371 100644 --- a/nix-infra-machine/nodes/node001.nix +++ b/nix-infra-machine/nodes/node001.nix @@ -173,12 +173,18 @@ in # - mail.rubenhensen.nl (and anything else) → local stalwart on 8443 # - tunneled hosts → home cluster ingress on 443 # - s1 / ntfy1.rubenhensen.nl → local nginx on 8444 (Gatus, ntfy) + # + # Each connection starts with a PROXY header that carries the visitor's + # address, so the home cluster sees who is asking instead of this box + # (gateway/proxy-protocol.yaml in k8scd). nginx sends the header to + # every upstream or none, so the local ones go through a hop on + # 8445/8446 that takes it off again. streamConfig = '' map $ssl_preread_server_name $tunnel_upstream { ${sniMapEntries} - s1.rubenhensen.nl 127.0.0.1:8444; - ntfy1.rubenhensen.nl 127.0.0.1:8444; - default 127.0.0.1:8443; + s1.rubenhensen.nl 127.0.0.1:8446; + ntfy1.rubenhensen.nl 127.0.0.1:8446; + default 127.0.0.1:8445; } server { @@ -186,6 +192,17 @@ ${sniMapEntries} listen [::]:443; proxy_pass $tunnel_upstream; ssl_preread on; + proxy_protocol on; + } + + server { + listen 127.0.0.1:8445 proxy_protocol; + proxy_pass 127.0.0.1:8443; + } + + server { + listen 127.0.0.1:8446 proxy_protocol; + proxy_pass 127.0.0.1:8444; } '';