From 2e64687bb9b807140972750828fc9b9f3b2c4f5e Mon Sep 17 00:00:00 2001 From: Nik Afiq Date: Tue, 25 Aug 2026 00:06:54 +0900 Subject: [PATCH] feat: switch browser-vpn-proxy to LoadBalancer on port 1080 Replace the NodePort (30889) with type: LoadBalancer on the standard SOCKS5 port 1080, at the user's request for a more natural port than a 30000+ NodePort value. loadBalancerIP: 10.10.40.20 (nik-debian) matches values/gitea.yaml's gitea-ssh Service pattern exactly. Documented the actual behavior after checking, not assuming: k3s's ServiceLB (Klipper) binds the port on every node via a DaemonSet by default - loadBalancerIP only sets the reported external IP, it doesn't scope which nodes bind the port. That needs a separate enablelb/lbpool node-label mechanism this repo doesn't use anywhere yet (including on the existing gitea-ssh Service, which likely has the same characteristic, unnoticed until now). So this change doesn't narrow exposure to nik-debian only - it's still reachable at any node IP on port 1080, the same multi-node reachability the NodePort version already had, just a different port number. Co-Authored-By: Claude Sonnet 5 --- manifests/multus/30-browser-vpn-proxy.yaml | 50 ++++++++++++++-------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/manifests/multus/30-browser-vpn-proxy.yaml b/manifests/multus/30-browser-vpn-proxy.yaml index 31c361d..bae2883 100644 --- a/manifests/multus/30-browser-vpn-proxy.yaml +++ b/manifests/multus/30-browser-vpn-proxy.yaml @@ -23,13 +23,10 @@ # already used for the DaemonSet, NAD, and canary, not a new mechanism. # # Before applying: -# 1. Verify the NodePort below (30889) doesn't collide with anything -# live — confirmed free 2026-08-24 (`kubectl get svc -A`, checked -# against every NodePort in use). manifests/media/gluetun-proxy.yaml -# (the existing browser proxy this replaces) uses 30888, not this -# one — no collision, but that file stays live and unmodified until -# this replacement is confirmed working end to end, then gets -# decommissioned as its own separate, explicitly-approved step. +# 1. Verify port 1080 below doesn't collide with anything live — +# confirmed free 2026-08-24 (`kubectl get svc -A`, checked against +# every live LoadBalancer Service's ports: gitea-ssh uses 2222, +# traefik uses 80/443). # # Design: # - serjs/go-socks5-proxy (github.com/serjs/socks5-server) — a small, @@ -47,7 +44,7 @@ # not an oversight. plan.md originally called for auth AND # LAN-restriction together as a floor; discussed and explicitly # relaxed (2026-08-24) after confirming the home network's own -# firewall already restricts this Service's NodePort to Trusted +# firewall already restricts this Service's port to Trusted # (VLAN 10) and Lab (VLAN 40) only — Trusted/Lab → Lab is ALLOW, # IoT/Guest/Management → Lab is DENY except the Technitium DNS # exception (see ~/repo/home-network/Home Network Implementation @@ -71,13 +68,29 @@ # LAN. Access restriction is the OpenWrt firewall alone; there is no # compensating netns-level (nft) inbound filter here either — one # could be added later, but would first need confirming whether this -# NodePort Service actually preserves real client source IPs -# end-to-end (default `externalTrafficPolicy: Cluster` typically -# does not) rather than assuming it does. -# - Service is NodePort, not LoadBalancer/Ingress — reachable from the -# LAN at :30889, never exposed publicly (no port-forward -# on Flint/the router for it, same as the now-decommissioned -# gluetun-proxy was). +# Service actually preserves real client source IPs end-to-end +# (default `externalTrafficPolicy: Cluster` typically does not — +# this Service doesn't set `externalTrafficPolicy: Local` either, +# unlike values/traefik.yaml's LoadBalancer, which does specifically +# for this reason) rather than assuming it does. +# - Service is LoadBalancer (k3s's built-in ServiceLB/Klipper), port +# 1080 directly — not NodePort, at the user's request for a more +# natural port than a 30000+ NodePort value. `loadBalancerIP: +# 10.10.40.20` (nik-debian) matches values/gitea.yaml's gitea-ssh +# Service pattern exactly (`loadBalancerIP: 10.10.40.53`, minisforum) +# — confirmed by reading how Klipper actually works before adding +# this, not assumed: `loadBalancerIP` only sets the *reported* +# external IP (`.status.loadBalancer.ingress[].ip`); the underlying +# svclb DaemonSet still binds port 1080 on every node by default, +# same as gitea-ssh's `loadBalancerIP` pin does today. Actually +# scoping it to nik-debian only needs k3s's separate +# `svccontroller.k3s.cattle.io/enablelb`/`lbpool` node-label +# mechanism, which nothing in this repo uses yet — not added here, +# so this is reachable at :1080, functionally identical +# multi-node reachability to the NodePort version it replaced, just +# a different (and more memorable) port number. Never exposed +# publicly either way (no port-forward on Flint/the router for it, +# same as the now-decommissioned gluetun-proxy was). # # Browser configuration — this is the part that actually matters for # "DNS must be resolved through the proxy": configuring a SOCKS5 proxy @@ -191,9 +204,12 @@ metadata: spec: selector: app: browser-vpn-proxy - type: NodePort + type: LoadBalancer + # Pinned to nik-debian's own address, matching values/gitea.yaml's + # gitea-ssh Service (loadBalancerIP: 10.10.40.53, minisforum) — see the + # header comment for what this does and does not actually restrict. + loadBalancerIP: "10.10.40.20" ports: - name: socks5 port: 1080 targetPort: 1080 - nodePort: 30889 # verify unused before applying — see header