By default, processes inside a Docker container often run as root — while contained, this is a meaningful security weakness if a container is ever compromised. This guide covers running containers as a non-root user.
Why This Matters
If an attacker exploits a vulnerability in a containerized application running as root, they have root privileges within that container — while container isolation limits (but doesn't eliminate) the broader impact, running as non-root adds a meaningful additional layer of defense.
Setting a Non-Root User in Your Dockerfile
FROM node:20-alpine
RUN addgroup -g 1001 appgroup && \
adduser -D -u 1001 -G appgroup appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["node", "server.js"]
USER appuser switches the effective user for all subsequent instructions and the final running container.
Using a Base Image's Built-In Non-Root User
Many official images already provide a non-root user you can use directly rather than creating your own:
FROM node:20-alpine
USER node
WORKDIR /home/node/app
COPY --chown=node:node . .
CMD ["node", "server.js"]
Handling File Permission Issues
A common issue when switching to non-root: files copied before the USER instruction may be owned by root, inaccessible to the non-root user — use --chown on COPY instructions, or an explicit chown step, to ensure correct ownership.
Handling Ports Below 1024
Binding to privileged ports (below 1024, like port 80) traditionally requires root — either have your application listen on an unprivileged port (like 3000) and let a reverse proxy or Docker's port mapping handle the translation to port 80 externally, or use specific capability grants if binding a low port from within the container is genuinely required.
Running an Existing Third-Party Image as Non-Root
docker run --user 1000:1000 myimage
Override the user at runtime even if the image's Dockerfile doesn't specify one — verify the image's application actually works correctly without root (some applications assume root and may fail without it, requiring investigation of what specifically needs root and whether it's avoidable).
Setting User in Docker Compose
services:
app:
image: myapp
user: "1000:1000"
Verifying the Container Is Actually Running as Non-Root
docker exec myapp whoami
docker exec myapp id
Combining with Other Security Measures
Non-root execution complements, rather than replaces, other container security practices (see Docker Security Best Practices for Production Servers) — part of a broader defense-in-depth approach.
Common Errors
Permission denied errors after switching to non-root — almost always a file ownership issue; verify COPY --chown is correctly applied, or add an explicit RUN chown step before switching to the non-root user.
Continue Reading
- Docker Security Best Practices for Production Servers
- How to Build Custom Docker Images with Dockerfile
- How to Implement the Principle of Least Privilege on a Linux VPS
Browse more articles in Docker & Containers.