fix(docker): expand 0.0.0.0/0 trusted-proxy CIDR for mod_remoteip - #1531
Conversation
RemoteIPInternalProxy 0.0.0.0/0 (the natural way to spell 'trust every proxy' on a platform like Railway where the edge proxy IP isn't fixed) fails Apache's config parser with 'The specified network mask is invalid', because mod_remoteip's apr_ipsubnet_create() rejects a /0 mask outright. Apache then refuses to start and the container crash-loops forever. Split 0.0.0.0/0 (and the IPv6 equivalent ::/0) into the two /1 halves that cover the identical IP range but that mod_remoteip does accept: 0.0.0.0/1 + 128.0.0.0/1, or ::/1 + 8000::/1. Same trust-everyone semantics, valid syntax. Reproduced the exact AH00526 error with apache2ctl configtest, confirmed the /1+/1 split passes configtest for both address families, then rebuilt the full prod image and booted it end to end against a real MariaDB container with SBPP_TRUSTED_PROXIES=0.0.0.0/0: schema installed, migrations ran, Apache started, container reported healthy, health.php returned 200.
docker/php/prod-entrypoint.sh had CRLF line endings on disk (a Windows git checkout artifact from core.autocrlf=true). A CRLF shebang line breaks the interpreter lookup at exec time (#!/bin/sh followed by a stray \\r makes the kernel look for a nonexistent /bin/sh\\r), which surfaces as a confusing 'exec: no such file or directory' instead of a parse error. This does not affect the published GHCR image, since CI builds on Linux where the checkout is already LF, but it silently breaks local Docker/Podman builds for any contributor on Windows. Force LF on docker/**/*.sh so Docker COPY always reads a working script regardless of the host OS or git config.
maxijabase
left a comment
There was a problem hiding this comment.
Self-review completed against the full PR diff and surrounding production-Docker configuration.
The implementation is functionally sound:
0.0.0.0/1plus128.0.0.0/1exactly covers IPv4/0.::/1plus8000::/1exactly covers IPv6/0.- Other space-separated proxy entries retain the existing pass-through behavior.
docker/**/*.sh text eol=lfis the correct Git attribute for Linux-executed Docker scripts.- No whitespace errors were found in the diff.
One item should be addressed before merge. docs/src/content/docs/getting-started/quickstart-docker.mdx still says, “The entrypoint passes the value through verbatim” in its RemoteIPInternalProxy troubleshooting row. That statement becomes false for the two /0 aliases. This PR also changes an operator-visible production Docker behavior, so the repository rules require the matching Docker quickstart documentation to change in the same PR. The docs should explain that 0.0.0.0/0 and ::/0 are expanded into Apache-compatible /1 pairs. It should also warn that trusting all proxies is safe only when direct access to the container is blocked.
I found no code-level correctness defect in the expansion itself. The existing successful E2E check and the documented full production-image boot test support the implementation. GitHub does not allow an author to approve their own PR, so this is submitted as a commented self-review.
When you're locally reviewing your own changes and it decides to randomly post the findings in the PR... |
Context
Found while deploying the published
ghcr.io/sbpp/sourcebans-ppimage to Railway, right after the MPM fix in #1530. With that fix applied andSBPP_TRUSTED_PROXIES=0.0.0.0/0set (the value Railway needs, since its edge proxy IP is not fixed), Apache still refused to start:Same crash loop as before, different cause.
Summary
SBPP_TRUSTED_PROXIES=0.0.0.0/0is the documented way to say "trust every proxy", needed on platforms like Railway where the edge proxy's IP is not fixed or published. The entrypoint writes this straight into aRemoteIPInternalProxy 0.0.0.0/0line formod_remoteip.mod_remoteiprejects a/0netmask outright at parse time (apr_ipsubnet_createfails on it), so Apache never starts.The fix splits
0.0.0.0/0into the two/1halves that cover the exact same IP range but thatmod_remoteipaccepts:0.0.0.0/1and128.0.0.0/1. Same applies to the IPv6 equivalent,::/0, split into::/1and8000::/1. Same trust-everyone behavior, valid syntax.Also included: a
.gitattributesfix. While testing this locally on Windows with Docker Desktop,docker/php/prod-entrypoint.shhad CRLF line endings on disk from a normal Windows git checkout (core.autocrlf=true). A CRLF shebang line breaks the script at exec time with a confusing "no such file or directory" instead of a parse error. This does not affect the real GHCR image, since CI builds on Linux where the checkout is already LF, but it silently breaks local image builds for any contributor on Windows. Forcing LF ondocker/**/*.shcloses that gap for good.Testing
Tested locally with Docker Desktop (not Podman).
AH00526error with a bareapache2ctl configtestagainst aRemoteIPInternalProxy 0.0.0.0/0line.0.0.0.0/1+128.0.0.0/1split passesconfigtest, same for the IPv6::/1+8000::/1split.SBPP_TRUSTED_PROXIES=0.0.0.0/0: schema installed, updater migrations ran to the latest version, Apache started with no errors, container reported healthy,health.phpreturned 200, login page returned 200.