All checks were successful
Cloud Apache Container / Build-and-Push (74) (push) Successful in 4m47s
Cloud Apache Container / Build-and-Push (80) (push) Successful in 1m18s
Cloud Apache Container / Build-and-Push (81) (push) Successful in 1m17s
Cloud Apache Container / Build-and-Push (82) (push) Successful in 2m17s
Cloud Apache Container / Build-and-Push (83) (push) Successful in 2m20s
Cloud Apache Container / Build-and-Push (84) (push) Successful in 1m16s
Cloud Apache Container / Build-and-Push (85) (push) Successful in 1m17s
Cloud Apache Container / Build-FPM-Images (74) (push) Successful in 2m6s
Cloud Apache Container / Build-FPM-Images (80) (push) Successful in 2m14s
Cloud Apache Container / Build-FPM-Images (81) (push) Successful in 2m16s
Cloud Apache Container / Build-FPM-Images (82) (push) Successful in 2m21s
Cloud Apache Container / Build-FPM-Images (83) (push) Successful in 1m18s
Cloud Apache Container / Build-FPM-Images (84) (push) Successful in 1m19s
Cloud Apache Container / Build-FPM-Images (85) (push) Successful in 2m13s
Cloud Apache Container / Build-LiteSpeed-Images (81) (push) Successful in 35s
Cloud Apache Container / Build-LiteSpeed-Images (82) (push) Successful in 45s
Cloud Apache Container / Build-LiteSpeed-Images (83) (push) Successful in 1m9s
Cloud Apache Container / Build-LiteSpeed-Images (84) (push) Successful in 30s
Cloud Apache Container / Build-LiteSpeed-Images (85) (push) Successful in 31s
Cloud Apache Container / Build-Shared-httpd (push) Successful in 26s
OLS had no equivalent of the Apache cac:phpNN mod_remoteip wiring (configs/remote_ip.conf + RemoteIPInternalProxy), so every migrated LiteSpeed site logged HAProxy's docker-bridge IP and handed that same internal IP to lsphp as $_SERVER['REMOTE_ADDR']. That silently broke traffic analytics, WP security plugins, brute-force detection, Coraza source-IP correlation, geo, and rate-limiting. Add server-level `useIpInProxyHeader 1` to the httpd_config append fragment. OLS then rewrites the remote IP from X-Forwarded-For for both logging and the LSAPI REMOTE_ADDR before PHP sees it. Value 1 mirrors the Apache trust model (container is only reachable via HAProxy, never bound publicly). Confirmed HAProxy customer backends are mode http with `option forwardfor` and set X-Forwarded-For to the resolved real client IP. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
112 lines
5.1 KiB
Smarty
112 lines
5.1 KiB
Smarty
## OpenLiteSpeed APPEND fragment — added to the stock httpd_config.conf
|
|
## that ships with litespeedtech/openlitespeed. Keeping the stock config
|
|
## intact preserves all the cgid/lscgid plumbing (CGIRLimit defaults,
|
|
## fileAccessControl defaults, etc.) — when we tried writing a fully
|
|
## custom httpd_config.conf, lscgid never created its IPC socket and
|
|
## every PHP request 503'd. The upstream OLS docker template uses this
|
|
## append pattern too (see setup_docker.sh in litespeedtech/ols-dockerfiles).
|
|
##
|
|
## Rendered at container start by scripts/create-vhost-litespeed.sh via
|
|
## envsubst. Templated vars: $user $domain $vhost_map_aliases $PHPVER
|
|
## $LSAPI_CHILDREN (computed by detect-memory-litespeed.sh)
|
|
|
|
## --- real client IP behind HAProxy ---
|
|
## OLS equivalent of the Apache cac:phpNN mod_remoteip wiring
|
|
## (configs/remote_ip.conf + RemoteIPInternalProxy in entrypoint.sh). Without
|
|
## this, OLS records HAProxy's docker-bridge IP as the peer: every site's
|
|
## access_log and lsphp $_SERVER['REMOTE_ADDR'] collapse to one internal IP,
|
|
## silently breaking traffic analytics, WP security plugins, brute-force
|
|
## detection, Coraza source-IP correlation, geo, and rate-limiting.
|
|
## 1 = trust X-Forwarded-For (the container is only reachable via HAProxy;
|
|
## it is never bound to a public address). Mirrors the Apache side, which
|
|
## trusts the whole docker subnet via RemoteIPInternalProxy $docker_network.
|
|
## When enabled, OLS rewrites the remote IP for BOTH logging and the LSAPI
|
|
## REMOTE_ADDR before PHP sees it — so the default access_log format already
|
|
## records the real visitor; no LogFormat change needed.
|
|
useIpInProxyHeader 1
|
|
|
|
## --- our listeners (replace stock Default :8088) ---
|
|
listener HTTP {
|
|
address *:80
|
|
secure 0
|
|
map siteVH *
|
|
## NB: HTTP→HTTPS redirect is in site-template.tpl's rewrite{} block,
|
|
## NOT here — OLS 1.8 listener-level rewrites are inert for vhTemplate
|
|
## members. Don't move it back to this listener.
|
|
}
|
|
|
|
listener HTTPS {
|
|
address *:443
|
|
secure 1
|
|
keyFile /usr/local/lsws/conf/cert/self.key
|
|
certFile /usr/local/lsws/conf/cert/self.crt
|
|
sslProtocol 24
|
|
enableSpdy 15
|
|
enableQuic 0
|
|
map siteVH *
|
|
}
|
|
|
|
## --- lsphp extProcessor (overrides the stock one which is hard-coded to
|
|
## PHP_LSAPI_CHILDREN=10 regardless of container memory).
|
|
##
|
|
## Sized dynamically by detect-memory-litespeed.sh based on the cgroup cap:
|
|
## 2 GiB container → LSAPI_CHILDREN ≈ 17 (was stuck at 10)
|
|
## 1 GiB container → LSAPI_CHILDREN ≈ 8
|
|
## 512 MiB → LSAPI_CHILDREN ≈ 3
|
|
##
|
|
## Idle-reduction knobs (the question that motivated this whole block):
|
|
## LSAPI_MAX_IDLE_CHILDREN=2 default was CHILDREN/2 (so 10/2=5)
|
|
## LSAPI_MAX_IDLE=60 default was 300 (5 min)
|
|
## Together: max 2 idle workers kept alive, anything idle >60s gets reaped.
|
|
## Trade-off: cold-start of an extra worker after idle reaping costs ~50-100ms
|
|
## on the first request to it. Worth it for shadowdao-sized low-traffic sites
|
|
## where the difference is "30 MB idle" vs "200 MB idle".
|
|
##
|
|
## memSoftLimit/memHardLimit: per-worker RLIMIT_AS catches a runaway PHP
|
|
## script before it hogs the whole pool's memory. Cgroup is still the host
|
|
## backstop (one-customer-per-container), but the per-worker cap protects
|
|
## the OTHER workers in the same pool from a bad-actor script. 1024M soft
|
|
## comfortably accommodates typical Divi/WooCommerce VSZ (~280-365 MB).
|
|
extProcessor lsphp {
|
|
type lsapi
|
|
address uds://tmp/lshttpd/lsphp.sock
|
|
maxConns ${LSAPI_CHILDREN}
|
|
env PHP_LSAPI_CHILDREN=${LSAPI_CHILDREN}
|
|
env LSAPI_MAX_IDLE_CHILDREN=2
|
|
env LSAPI_MAX_IDLE=60
|
|
env PHP_LSAPI_MAX_REQUESTS=500
|
|
env LSAPI_AVOID_FORK=200M
|
|
initTimeout 60
|
|
retryTimeout 0
|
|
persistConn 1
|
|
pcKeepAliveTimeout 30
|
|
respBuffer 0
|
|
autoStart 1
|
|
path /usr/local/lsws/lsphp${PHPVER}/bin/lsphp
|
|
backlog 100
|
|
instances 1
|
|
runOnStartUp 1
|
|
priority 0
|
|
memSoftLimit 1024M
|
|
memHardLimit 1500M
|
|
procSoftLimit 400
|
|
procHardLimit 500
|
|
}
|
|
|
|
## --- our vhost via vhTemplate (upstream's working pattern) ---
|
|
## The template file is /usr/local/lsws/conf/templates/site.conf — written
|
|
## by create-vhost-litespeed.sh at the same time as this fragment.
|
|
vhTemplate site {
|
|
templateFile conf/templates/site.conf
|
|
listeners HTTP, HTTPS
|
|
note cac-litespeed per-customer vhost
|
|
|
|
## vhDomain: customer's domain + serveralias list + `*` catchall so
|
|
## ip-only requests (e.g. HAProxy backend health check by container_name)
|
|
## still resolve. WHP/HAProxy filters hostnames upstream — no risk to
|
|
## allowing the catchall here.
|
|
member siteVH {
|
|
vhDomain ${domain}${vhost_map_aliases}, *
|
|
}
|
|
}
|