From 8dbfdf599a429d281600bbd74812e4f39267acb1 Mon Sep 17 00:00:00 2001 From: jknapp Date: Thu, 11 Jun 2026 07:55:42 -0700 Subject: [PATCH] fix(shared-ols): useIpInProxyHeader 2->1 so real client IP reaches lsphp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mode 2 ("trusted IP only") extracts the real client IP from X-Forwarded-For ONLY when the connecting peer is in a TRUSTED access-control list — which this tier never configured (accessControl is `allow ALL`, no trusted designation). So OLS kept HAProxy's container IP (172.18.0.34) as REMOTE_ADDR for EVERY request across ALL tenants. WP security plugins (Wordfence etc.) then saw all traffic as one IP; blocking it locked every site — and the admin — out. HAProxy already sends X-Forwarded-For and is the ONLY peer that connects to this tier (client-net, no host-published ports), and it OVERWRITES XFF with %[src] (set-header), so spoofing is impossible. Mode 1 (always trust XFF) is correct and safe here — it matches the working standalone configs/litespeed config which has always used 1. Verified on whp01: lsphp now receives the forwarded client IP end-to-end (REMOTE_ADDR=, was 172.18.0.34). Live-hotpatched whp01+whp02 pending this image rebuild. Co-Authored-By: Claude Opus 4.8 (1M context) --- configs/shared-ols/httpd_config_base.tpl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/configs/shared-ols/httpd_config_base.tpl b/configs/shared-ols/httpd_config_base.tpl index 3cb41ec..0b7e09e 100644 --- a/configs/shared-ols/httpd_config_base.tpl +++ b/configs/shared-ols/httpd_config_base.tpl @@ -9,11 +9,17 @@ serverName shared-ols ## Real client IP behind HAProxy. HAProxy sets X-Forwarded-For (the real -## client) and X-Forwarded-Proto. Mode 2 = trust the proxy header. HAProxy is -## the only thing that ever connects to this tier (it's not publicly exposed), -## so trusting the header from the docker-network peer is safe — same trust -## model as the shared httpd's RemoteIPInternalProxy. -useIpInProxyHeader 2 +## client) and X-Forwarded-Proto. Mode 1 = always use X-Forwarded-For as the +## client IP. HAProxy is the ONLY thing that ever connects to this tier (it's on +## client-net with no host-published ports) and it OVERWRITES X-Forwarded-For +## with %[src] (set-header, not add-header), so a client can't spoof it — mode 1 +## is safe here and matches the working standalone litespeed config. +## NOTE: mode 2 ("trusted IP only") does NOT mean "trust the proxy header" — it +## extracts the real IP ONLY when the connecting peer is in a TRUSTED access +## list, which this tier never configured. With mode 2 + no trusted IP, OLS kept +## HAProxy's container IP as REMOTE_ADDR for every request, so WP security +## plugins saw all tenants as one IP and blocking it locked everyone out. +useIpInProxyHeader 1 ## LSCache enabled at MODULE scope for the whole tier (dedicated cache volume, ## ephemeral across rebuilds; OLS auto-keys a per-vhost subdir under storagePath).