fix(startup): keep nginx temp dirs owned by the nginx worker user - #952
Open
conorbronsdon wants to merge 1 commit into
Open
fix(startup): keep nginx temp dirs owned by the nginx worker user#952conorbronsdon wants to merge 1 commit into
conorbronsdon wants to merge 1 commit into
Conversation
The PUID/PGID chown added in 123ae00 included /var/lib/nginx and /var/lib/nginx/tmp. These images replace the packaged nginx.conf (dockerfile:174, dockerfile-arm:165) and ours carries no 'user' directive, so nginx uses its compile-time default and a master started as root drops its workers to the 'nginx' user (uid 100). With PUID=0 the temp tree therefore ends up root:root mode 0700 and those workers cannot create proxy temp files: [crit] open() "/var/lib/nginx/tmp/proxy/0/10/0000000100" failed (13: Permission denied) while reading upstream When that happens nginx serves what it already has instead of failing, so the client gets a short body with HTTP 200. Reported on /api/data/podcast_episodes, where the mobile app parses the truncated JSON, throws, and renders an empty list. Response size alone does not trigger it, which is why it looks intermittent: nginx only needs a temp file when it has to buffer ahead of the client, so the same endpoint can return intact for a client that drains as fast as the upstream delivers and truncate for a slower one. The one log line it does produce goes to /var/log/nginx/error.log, which nothing surfaces because horust captures only nginx's stdout/stderr (startup/services/nginx.toml). Only a root master can setuid. When privileges are actually dropped the workers inherit PUID and the original chown was right, so the owner is chosen rather than hard-coded: privileges dropped (PUID and PGID set, PUID non-zero) -> PUID:PGID otherwise (master stays root) -> nginx:nginx The condition mirrors the privilege-drop guard below it, including the PGID check: PUID set without PGID does NOT drop privileges, so the master stays root and its workers are still 'nginx'. Testing PUID alone would hand the dirs to PUID while nginx ran as 'nginx', reproducing the bug in a configuration that works on main today. The zero test matches any all-zero spelling for the same reason, since chown and su-exec both read "00" as uid 0. nginx's directories are removed from the PUID chown list so the two cannot disagree. Fixes madeofpendletonwool#940
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The PUID/PGID chown added in 123ae00 included /var/lib/nginx and
/var/lib/nginx/tmp. These images replace the packaged nginx.conf
(dockerfile:174, dockerfile-arm:165) and ours carries no 'user'
directive, so nginx uses its compile-time default and a master started as
root drops its workers to the 'nginx' user (uid 100). With PUID=0 the
temp tree therefore ends up root:root mode 0700 and those workers cannot
create proxy temp files:
When that happens nginx serves what it already has instead of failing, so
the client gets a short body with HTTP 200. Reported on
/api/data/podcast_episodes, where the mobile app parses the truncated
JSON, throws, and renders an empty list.
Response size alone does not trigger it, which is why it looks
intermittent: nginx only needs a temp file when it has to buffer ahead of
the client, so the same endpoint can return intact for a client that
drains as fast as the upstream delivers and truncate for a slower one.
The one log line it does produce goes to /var/log/nginx/error.log, which
nothing surfaces because horust captures only nginx's stdout/stderr
(startup/services/nginx.toml).
Only a root master can setuid. When privileges are actually dropped the
workers inherit PUID and the original chown was right, so the owner is
chosen rather than hard-coded:
privileges dropped (PUID and PGID set, PUID non-zero) -> PUID:PGID
otherwise (master stays root) -> nginx:nginx
The condition mirrors the privilege-drop guard below it, including the
PGID check: PUID set without PGID does NOT drop privileges, so the master
stays root and its workers are still 'nginx'. Testing PUID alone would
hand the dirs to PUID while nginx ran as 'nginx', reproducing the bug in
a configuration that works on main today. The zero test matches any
all-zero spelling for the same reason, since chown and su-exec both read
"00" as uid 0.
nginx's directories are removed from the PUID chown list so the two
cannot disagree.
Fixes #940
Verification
Rebuilt the relevant slice of the image (alpine + nginx, an nginx.conf with no
userdirective, a 20MB upstream body) and ran the branch logic directly, then forced nginx to spill to a proxy temp file with a rate-limited client.Negative control, ownership broken with a root master: 7,008,182 of 20,263,158 bytes, HTTP 200, with the
[crit] ... 13: Permission deniedline quoted above.Every PUID/PGID combination after the fix:
Also checked:
chown -Rdoes not traverse the package's symlinks (/var/lib/nginx/logs,modules,run) since busybox chown does not dereference them, so no system files are touched; the recursion is load-bearing across restarts with a named volume on/var/lib/nginx, correcting stale ownership in both directions; and nothing else in the repo references these paths.