Skip to content

Run nginx as unprevileged user#3167

Open
rcmadhankumar wants to merge 1 commit intomainfrom
unprevileged-nginx
Open

Run nginx as unprevileged user#3167
rcmadhankumar wants to merge 1 commit intomainfrom
unprevileged-nginx

Conversation

@rcmadhankumar
Copy link
Copy Markdown
Contributor

@rcmadhankumar rcmadhankumar commented Nov 17, 2025

Made necessary changes to the nginx image so that it can be simply run as non root by passing --user=nginx flag.

fixes: #2924

bci-pushman pushed a commit that referenced this pull request Nov 17, 2025
bci-pushman pushed a commit that referenced this pull request Nov 17, 2025
bci-pushman pushed a commit that referenced this pull request Nov 17, 2025
@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 17, 2025

Created a staging project on OBS for Tumbleweed: home:pushman:BCI:Staging:Tumbleweed:Tumbleweed-3167
Changes pushed to branch Tumbleweed-3167 as commit 912f50c694b55abeaf427b79ede3fb98a835996d
Build succeeded ✅

Build Results

Repository images in home:pushman:BCI:Staging:Tumbleweed:Tumbleweed-3167 for x86_64: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository images in home:pushman:BCI:Staging:Tumbleweed:Tumbleweed-3167 for aarch64: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository containerfile in home:pushman:BCI:Staging:Tumbleweed:Tumbleweed-3167 for x86_64: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:Tumbleweed:Tumbleweed-3167 for aarch64: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Build succeeded ✅

To run BCI-tests against this PR, use the following command:

OS_VERSION=tumbleweed TARGET=custom BASEURL=registry.opensuse.org/home/pushman/bci/staging/tumbleweed/tumbleweed-3167/ tox -- -n auto
The following images can be pulled from the staging project:
  • registry.opensuse.org/home/pushman/bci/staging/tumbleweed/tumbleweed-3167/containerfile/opensuse/nginx:latest

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 17, 2025

Created a staging project on OBS for 7: home:pushman:BCI:Staging:SLE-15-SP7:7-3167
Changes pushed to branch 7-3167 as commit 57d9eeee2aa805b5caff87a84e1b66c4d8959f12
Build succeeded ✅

Build Results

Repository images in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for x86_64: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository images in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for aarch64: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository images in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for s390x: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository images in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for ppc64le: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository containerfile in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for x86_64: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for aarch64: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for s390x: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:SLE-15-SP7:7-3167 for ppc64le: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Build succeeded ✅

To run BCI-tests against this PR, use the following command:

OS_VERSION=15.7 TARGET=custom BASEURL=registry.opensuse.org/home/pushman/bci/staging/sle-15-sp7/7-3167/ tox -- -n auto
The following images can be pulled from the staging project:
  • registry.opensuse.org/home/pushman/bci/staging/sle-15-sp7/7-3167/containerfile/suse/nginx:latest

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 17, 2025

Created a staging project on OBS for 16.0: home:pushman:BCI:Staging:16.0:16.0-3167
Changes pushed to branch 16.0-3167 as commit 1dc98705a10c378fdb276b0baeabd7109abe09aa
Build succeeded ✅

Build Results

Repository containerkiwi in home:pushman:BCI:Staging:16.0:16.0-3167 for x86_64: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository containerkiwi in home:pushman:BCI:Staging:16.0:16.0-3167 for aarch64: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository containerkiwi in home:pushman:BCI:Staging:16.0:16.0-3167 for s390x: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository containerkiwi in home:pushman:BCI:Staging:16.0:16.0-3167 for ppc64le: current state: published
Build results:

package name status build log
nginx-image ⛔ excluded live log

Repository containerfile in home:pushman:BCI:Staging:16.0:16.0-3167 for x86_64: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:16.0:16.0-3167 for aarch64: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:16.0:16.0-3167 for s390x: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Repository containerfile in home:pushman:BCI:Staging:16.0:16.0-3167 for ppc64le: current state: published
Build results:

package name status build log
nginx-image ✅ succeeded live log

Build succeeded ✅

To run BCI-tests against this PR, use the following command:

OS_VERSION=16.0 TARGET=custom BASEURL=registry.opensuse.org/home/pushman/bci/staging/16.0/16.0-3167/ tox -- -n auto
The following images can be pulled from the staging project:
  • registry.opensuse.org/home/pushman/bci/staging/16.0/16.0-3167/containerfile/suse/nginx:1.27

bci-pushman pushed a commit that referenced this pull request Nov 18, 2025
bci-pushman pushed a commit that referenced this pull request Nov 18, 2025
bci-pushman pushed a commit that referenced this pull request Nov 18, 2025
bci-pushman pushed a commit that referenced this pull request Nov 18, 2025
bci-pushman pushed a commit that referenced this pull request Nov 18, 2025
bci-pushman pushed a commit that referenced this pull request Nov 18, 2025
bci-pushman pushed a commit that referenced this pull request Nov 20, 2025
bci-pushman pushed a commit that referenced this pull request Nov 20, 2025
bci-pushman pushed a commit that referenced this pull request Nov 20, 2025
entrypoint_log "$0: Removed 'user' directive for unprivileged worker."

# Ensure PID path is set to /tmp/nginx.pid
sed -i 's,^#\?\s*pid\s\+.*;$,pid /tmp/nginx.pid;,' /etc/nginx/nginx.conf
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we setting it to /tmp rather than a safe location like /run/nginx or /run ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are starting the nginx container as unprevileged user.
/run directory and /var/run directory is owned by root.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But nothing prevents you from having /run/nginx/nginx.pid , you can create the folder with the nginx user, which it seems you already do with chown -R nginx:nginx /var/run/.

I would also move this to be a default location, not just in case it is a non-root user. Since it would not make any difference if it is owned by nginx anyway.

Copy link
Copy Markdown
Contributor Author

@rcmadhankumar rcmadhankumar Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pid path is set to /var/run/nginx/nginx.pid

@dirkmueller
Copy link
Copy Markdown
Member

@rcmadhankumar can you please also include the (adjusted) readme update from #3071 ?

bci-pushman pushed a commit that referenced this pull request Dec 16, 2025
@rcmadhankumar
Copy link
Copy Markdown
Contributor Author

@rcmadhankumar can you please also include the (adjusted) readme update from #3071 ?

Added relevant readme update.

bci-pushman pushed a commit that referenced this pull request Dec 16, 2025
bci-pushman pushed a commit that referenced this pull request Dec 16, 2025
bci-pushman pushed a commit that referenced this pull request Dec 16, 2025
bci-pushman pushed a commit that referenced this pull request Dec 16, 2025
bci-pushman pushed a commit that referenced this pull request Dec 16, 2025
Copy link
Copy Markdown
Member

@alexandrevicenzi alexandrevicenzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we seding the user provided file as well (volume mount)? It does not make sense to change is such cases, only if it is the default config we ship, otherwise, we could potentially break the user config.

entrypoint_log "$0: Removed 'user' directive for unprivileged worker."

# Ensure PID path is set to /tmp/nginx.pid
sed -i 's,^#\?\s*pid\s\+.*;$,pid /tmp/nginx.pid;,' /etc/nginx/nginx.conf
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But nothing prevents you from having /run/nginx/nginx.pid , you can create the folder with the nginx user, which it seems you already do with chown -R nginx:nginx /var/run/.

I would also move this to be a default location, not just in case it is a non-root user. Since it would not make any difference if it is owned by nginx anyway.

bci-pushman pushed a commit that referenced this pull request Jan 28, 2026
@dirkmueller dirkmueller self-requested a review February 2, 2026 13:23
chown -R nginx:nginx /etc/nginx; \
chown -R nginx:nginx /var/run/nginx; \
install -d -o nginx -g nginx /tmp/client_temp /tmp/proxy_temp /tmp/fastcgi_temp /tmp/uwsgi_temp /tmp/scgi_temp; \
chown -R nginx:nginx /tmp; \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, /tmp must be owned by root, it has the sticky bit set though. why are you changing this here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, Now changing only the permissions of the subdirectories inside /tmp created in the run time to run the image in root less mode.

entrypoint_log "$0: Removed 'user' directive for unprivileged worker."

sed -i 's/listen \(.*\)80;/listen \18080;/' /etc/nginx/conf.d/default.conf 2>/dev/null || \
sed -i 's/listen \(.*\)80;/listen \18080;/' /etc/nginx/nginx.conf 2>/dev/null || true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be mounted over though by a user to provide a different configuration file? we should at least check before sed'ing whether there is a change necessary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True that. Sedding config file now only if it uses port 80 in rootless mode. This prevents if user wants to use different port than 8080 in rootless mode.

## Running nginx as a non-root user
To run the image as a less privileged user using the `nginx` user, do the following:
```ShellSession
$ podman run -it --user nginx --rm -p 8080:8080 -v /path/to/html/:/srv/www/htdocs/:Z -v $PWD/nginx.conf:/etc/nginx/nginx.conf:Z {{ image.pretty_reference }}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why exactly do we still need nginx.conf to be mounted over from the host here? where is it coming from?

Copy link
Copy Markdown
Contributor Author

@rcmadhankumar rcmadhankumar Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't necessarily mount the config file. Updated the readme.

ln -sf /dev/stderr /var/log/nginx/error.log; \
chown -R nginx:nginx /var/cache/nginx; \
chown -R nginx:nginx /etc/nginx; \
chown -R nginx:nginx /var/run/nginx; \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we're expecting the uid to be the one of nginx? otherwise these changes wouldn't seem to make sense?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it was. Now modified the code so the rootless user ID can be anything.

# Ensure PID path is set to /var/run/nginx.pid for both privileged and unprivileged users
sed -i 's,^#\?\s*pid\s\+.*;$,pid /var/run/nginx/nginx.pid;,' /etc/nginx/nginx.conf
# modify temp paths for both privileged and unprivileged users
sed -i "/^http {/a \ proxy_temp_path /tmp/proxy_temp;\n client_body_temp_path /tmp/client_temp;\n fastcgi_temp_path /tmp/fastcgi_temp;\n uwsgi_temp_path /tmp/uwsgi_temp;\n scgi_temp_path /tmp/scgi_temp;\n" /etc/nginx/nginx.conf
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a backward incompatible change, isn't it? we cannot do it that way unconditionally.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Updated the code.

Copy link
Copy Markdown
Member

@dirkmueller dirkmueller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to preserve compatibility with previous version of the nginx container

bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
@rcmadhankumar
Copy link
Copy Markdown
Contributor Author

modified the code by keeping following expectations in mind:

  • Nginx image should be runnable as a rootless user on the host
    podman run -it --rm --user $(id -u) -p 8080:8080 localhost/ngnix:latest

  • Nginx image should be runnable as a nginx user
    podman run -it --rm --user nginx -p 8080:8080 localhost/ngnix:latest

  • Nginx image should be runnable as any random rootless user id
    podman run -it --rm --user 1002 -p 8080:8080 localhost/ngnix:latest

  • Nginx image should be runnable as any random rootless user id and group id
    podman run -it --rm --user 486:499 -p 8080:8080 localhost/ngnix:latest

  • Nginx image should be runnable as a rootless user without externally providing any configuration file

  • Nginx image should be runnable as a rootless user which doesn't affect rootful mode so it can be backward compatible

bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
bci-pushman pushed a commit that referenced this pull request Feb 17, 2026
fi
fi

CURRENT_UID=$(id -u)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is going to vanish as soon as update-files.sh is executed. docker-entrypoint.sh is taken from upstream. I completely missed that before.

This piece of code should be in /docker-entrypoint.d/ and could be called unprivileged-mode.sh.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified.

bci-pushman pushed a commit that referenced this pull request Feb 24, 2026
bci-pushman pushed a commit that referenced this pull request Feb 24, 2026
bci-pushman pushed a commit that referenced this pull request Feb 24, 2026
{DOCKERFILE_RUN} set -euo pipefail; mkdir -p /var/cache/nginx /var/run/nginx /tmp/client_temp /tmp/proxy_temp /tmp/fastcgi_temp /tmp/uwsgi_temp /tmp/scgi_temp;\
ln -sf /dev/stdout /var/log/nginx/access.log;\
ln -sf /dev/stderr /var/log/nginx/error.log;\
chmod -R 777 /var/cache/nginx /etc/nginx /var/run/nginx /var/log/nginx /tmp/client_temp /tmp/proxy_temp /tmp/fastcgi_temp /tmp/uwsgi_temp /tmp/scgi_temp;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a chmod -R 0777 is kinda ugly, can we chown it to the nginx user instead? we should then set that as a stableuid and update the README accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nginx image: unable to run as non root in kubernetes

3 participants