Docker · Containers in practice

Why and how should containers run as non-root?

Mediumnon-rootuserssecurityUpdated Oct 2026
Quiz this track

Short answer

Running as non-root limits the damage if the process is compromised. Create a dedicated user, set USER in the Dockerfile, and fix file ownership so the app can still write where it needs to.

By default many base images run as root. Inside a container, root has fewer powers than host root in a hardened setup, but it can still write to the filesystem, change ownership and interact with mounted volumes in ways an unprivileged user cannot.

dockerfile
FROM node:20-alpine
RUN addgroup -S app && adduser -S -G app app
WORKDIR /app
COPY --chown=app:app . .
USER app
EXPOSE 3000
CMD ["node", "server.js"]
The chown makes copied files owned by the runtime user; USER switches before the process starts.

Practical issues

  • Binding ports below 1024 normally requires a capability or a higher port
  • Mounted volumes may be owned by root and need correct permissions
  • Some base images assume a writable home directory
  • Platforms such as OpenShift run with an arbitrary UID, so do not hardcode assumptions
  • A fixed UID makes volume permissions predictable

The best practice is to listen on an unprivileged port such as 8080 or 3000 and put a reverse proxy in front for port 80 and 443. That avoids granting NET_BIND_SERVICE to the application.

USER app in the Dockerfile is not enough if an entrypoint script switches back to root. Check the final process with docker exec id or inspect the container's user.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1How does an app bind to port 80 without running as root?
  2. 2Why do mounted volumes often cause permission errors for a non-root user?
  3. 3How do you support platforms that assign an arbitrary UID?
  4. 4How would you verify the container is not running as root?

Say it in the interview

I create a dedicated user in the image, chown the application files, and switch with USER before the process starts. That limits what a compromised process can do and satisfies most security policies. If the app needs port 80, I terminate it at a reverse proxy rather than granting extra capabilities, and I check that entrypoint scripts do not switch back to root.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Docker mock interview and get scored feedback on depth, clarity and confidence.