NovFora Dev

[HELP] Getting Python docker images to run as non-root — what approach?

Stella Cook

Stella Cook

2 months ago

Trying to build a container that doesn't run as root for security reasons, but my app needs to bind port 80 and write to /app/logs. The standard USER python works fine for the app itself but breaks those two requirements. I've looked at: (1) using setcap on the binary — feels brittle; (2) creating a separate process that binds the port and proxies via reverse proxy — adds complexity; (3) running the docker container as root but dropping privileges inside via sudo/setuid wrappers. Are there any modern best practices I'm missing?

Rowan Morales

Rowan Morales

2 months ago

This is genuinely one of those topics where people either know it well or have never thought about it, and there's a lot of nuance that gets glossed over in quick Stack Overflow answers. I want to lay out what I consider to be the canonical approach while flagging a few edge cases that trip up everyone who hasn't done this at scale before.

The fundamental issue is that by default Python images — whether you are using python:3.12-slim or even the Debian-based ones — run as root because the Dockerfile simply doesn't specify otherwise, and the container engine defaults to UID 0 when it builds the layer stack. For a production service exposed to the internet, running as root is not just bad practice; it is an architectural vulnerability. If your Python application has an arbitrary code execution bug (which all of us know exists somewhere in our dependencies), that remote attacker now lands inside the container with full privileges over whatever resources Docker exposes — file system writes, network access via docker.sock if you've mounted it, or worse.

So here is what I recommend as a standard pattern for Python images: first, create a system user and group explicitly using groupadd -r appuser and adduser -u 10001 -G appuser --no-create-home --disabled-login appuser. Using the -r flag ensures you're creating a system account rather than a regular user with home directories, which keeps your image smaller. I prefer using a high UID like 10001 to avoid collisions with any existing users on host systems if you are running these containers through an orchestrator that might share namespaces. Then build the app and all its dependencies into one directory owned by this new user: RUN chown -R appuser:appuser /opt/app. The /opt prefix is a convention I've adopted over `/usr/src/

Ethan Davis

Ethan Davis

2 months ago

sorry this is such a dumb question but i keep getting permission denied on my python app and every tutorial says "use a non-root user" so that part good — but how do you actually set one up in your dockerfile? like what's the syntax for creating a new system user versus just using an existing one. also if i create a user does it automatically have access to /app or do i need extra commands and am i doing something wrong with permissions somewhere because every time i

Stella Cook

Stella Cook

2 months ago

Three standard approaches, ranked by maintainability:

1. Use official distroless/alpine bases. Instead of building your own non-root user in a heavy image, start with python:3.x-slim or python:3.x-alpine. The slim images already have sane permission boundaries and are tiny (~40MB vs 900MB).

2. Build as root, run as non-root. This is the canonical Docker pattern — your BUILD stage can use root to install system deps (apt-get, pip install --user), then you COPY just the application into a final image with a dedicated user:

FROM python:3.12-slim AS builder
RUN pip install --no-cache-dir -r requirements.txt --target=/app/site-packages

FROM python:3.12-slim
COPY --from=builder /app/site-packages /usr
Oliver Green

Oliver Green

2 months ago

Use python:python3 in your FROM and add a user with WORKDIR set to something like

Join the conversation to leave a reply.

Sign in to reply

Related topics