fix(web): trust XFF for real client IP and correct port to 23081
- Configure nginx `set_real_ip_from` for RFC1918 ranges and enable `real_ip_recursive` so allowlists evaluate the true client IP instead of Docker's NAT gateway, preventing public exposure of `/metrics` and `/nginx_status` - Update published port from 23181 to 23081 in docker-compose
This commit is contained in:
@@ -377,7 +377,7 @@ services:
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
# ── Web: nginx reverse proxy, public port 23181 ────────────────────────────
|
||||
# ── Web: nginx reverse proxy, public port 23081 ────────────────────────────
|
||||
# No Django env — nginx only knows how to route. Public listener is
|
||||
# templated into the conf file by Ansible if the port ever needs to change.
|
||||
web:
|
||||
@@ -390,7 +390,7 @@ services:
|
||||
mcp:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "23181:80"
|
||||
- "23081:80"
|
||||
volumes:
|
||||
- ./nginx/mnemosyne.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- static:/var/www/static:ro
|
||||
|
||||
@@ -32,6 +32,19 @@
|
||||
# resolution at startup and returns 502 after `docker compose restart app`.
|
||||
resolver 127.0.0.11 valid=10s;
|
||||
|
||||
# Recover the real client IP from X-Forwarded-For (set by HAProxy on Titania)
|
||||
# before evaluating the RFC1918 allowlists below. nginx runs as a sidecar with
|
||||
# a published port, so every proxied request arrives via Docker's NAT gateway
|
||||
# (an RFC1918 address) — without this, the allowlists match that gateway and
|
||||
# pass ALL external traffic, exposing /metrics and /nginx_status publicly.
|
||||
# HAProxy's own health checks (e.g. to /healthz) carry no XFF and keep their
|
||||
# real 10.10.x.x source, so they stay allowed.
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
# Preserve X-Forwarded-Proto from the upstream reverse proxy (HAProxy TLS
|
||||
# termination on Titania); fall back to $scheme only if there's no upstream
|
||||
# header. Inside the compose network $scheme is always `http` because HAProxy
|
||||
|
||||
Reference in New Issue
Block a user