Infrastructure & Operations › Containers
Running as Non-Root
Not running container processes as root.
Also known as: non-root user, rootless container, USER instruction
By default a container process often runs as root (UID 0) — either because the base image doesn’t set a user, or because you never changed it. Inside the container that root has full control, which sounds harmless given isolation, but it isn’t.
Two reasons it matters:
- Containers share the host kernel. A kernel flaw, a bad mount or a misconfiguration can let a root process escape and reach the host (see container vs VM and Linux namespaces).
- Root owns files outside the container. A process writing to a bind-mounted directory creates root-owned files on the host, and a container root that can reach the Docker socket is effectively host root.
The fix is to declare a non-root user in the image:
FROM node:20-slim
RUN groupadd -r app && useradd -r -g app app
WORKDIR /app
COPY --chown=app:app . .
USER app
CMD ["node", "server.js"]
Now the process runs as app. Match this to file permissions and ownership: files the app must write to should be owned by app, or you’ll get “permission denied” the moment it starts.
The classic mistakes:
- Setting
USERwithout fixing ownership, so the app can’t write its own files. - Using
chown -Rover the whole filesystem, which copies every file into a new layer and bloats the image. UseCOPY --chowninstead. - Assuming non-root is enough. Also drop Linux capabilities you don’t need, run a read-only root filesystem where possible, and apply least privilege to what the container can reach.
Rootless Docker and rootless runtimes add a second layer of safety by running the daemon itself as an unprivileged user. For anything exposed to the internet, treat a non-root container as a baseline, not a bonus — the same instinct as server hardening.