Docker as a System Engineer: Run Containers Safely, Not as “Just a User”

basanta sapkota
Nothing wakes you up faster than a container that quietly writes root-owned files into your project tree, breaks your CI cleanup, and leaves you reaching for sudo at 2 a.m. That’s the point where Docker stops being a developer convenience and starts becoming a systems problem. If you’re thinking about Docker as a system engineer not user, the real question isn’t “How do I run a container?” It’s “Who owns the daemon, who owns the files, and what happens when something goes wrong?”

As system engineers, we need to think in layers. There’s the user running Docker commands on the host. There’s the Docker daemon. And there’s the user inside the container. Those are related, but they are not the same thing. Mixing them up is how people end up with avoidable security risks.

Key Takeaways

  • By default, Docker runs container commands as root unless you set USER in the Dockerfile or override it at runtime.
  • Adding someone to the docker group removes the need for sudo, but Docker’s own docs warn that this grants root-level privileges.
  • Rootless Docker is different from “running a container as non-root.” In rootless mode, both the daemon and containers run without host root privileges.
  • Docker rootless mode requires newuidmap and newgidmap, plus at least 65,536 subordinate UIDs/GIDs in /etc/subuid and /etc/subgid.
  • Using --user $(id -u):$(id -g) is handy for bind mounts because files created in mounted directories will match the host user’s ownership.
  • A host username usually does not exist inside the container. That’s why whoami can fail or show odd output like “I have no name!”
  • --user at runtime overrides the USER instruction in a Dockerfile.
  • For production, least privilege matters: use non-root containers, avoid unnecessary capabilities, and consider rootless mode after testing its limitations.

What “Docker as a system engineer not user” really means

When I hear this phrase, I read it as: stop treating Docker like a desktop app and start treating it like infrastructure.

A normal user mindset is often:

  • install Docker
  • add myself to the docker group
  • run containers
  • fix permission issues later

A system engineer mindset is different:

  • decide whether the daemon should run rootful or rootless
  • control who can talk to the daemon
  • define container users explicitly
  • manage UID/GID behavior for volumes and bind mounts
  • reduce privileges and attack surface up front

Docker’s official Linux post-install docs make one thing very clear: the Docker daemon binds to a Unix socket owned by root, and users usually need sudo to access it. You can add users to the docker group, but Docker warns that the docker group grants root-level privileges. That’s not a small footnote. That’s a design-level security decision.

Docker rootless mode vs non-root containers

This is the part that confuses a lot of people, and honestly, for good reason.

Non-root container user

This means the process inside the container does not run as UID 0. You usually do this with a Dockerfile like:

FROM ubuntu:24.04

RUN useradd -ms /bin/bash appuser
USER appuser
WORKDIR /home/appuser

CMD ["bash"]

Docker’s official blog explains that if no USER is specified, Docker runs commands as root by default. That’s the baseline behavior.

Rootless Docker

This is bigger. In rootless mode, the Docker daemon itself runs as a non-root user. According to the official Docker docs, rootless mode runs both the daemon and containers inside a user namespace to reduce risks from daemon or runtime vulnerabilities.

So, short version:

  • non-root container = safer process inside the container
  • rootless Docker = safer daemon model on the host
  • they are not the same thing

A good explanation from the Docker community forum puts it bluntly: in rootless mode, the process can still feel like root inside the container, but it is not real root on the host.

Why system engineers should care about Docker users

There are three practical reasons.

1. Security and blast radius

If the daemon runs as root, anyone with access to the Docker socket effectively has serious power over the host. That’s why casually handing out docker group membership is risky.

And if your container runs as root too, you’ve widened the blast radius again. Docker’s own guidance recommends using a non-root user unless root is actually needed.

2. File ownership on bind mounts

This is the pain almost everyone hits first.

The Redbubble write-up explains it well: when Docker writes files into a mounted host directory as root, regular users later can’t delete or modify them cleanly. That’s why many teams run containers with:

docker run --rm \
  -v "$PWD":/app \
  -w /app \
  --user "$(id -u):$(id -g)" \
  my-image make build

That simple flag often saves a lot of cleanup drama.

3. Username mismatch between host and container

A host user is not automatically known inside the container. Stack Overflow and community discussions both point this out: containers are isolated OS environments, so a host account like deploy or alice won’t magically exist in /etc/passwd inside the image.

That’s why this happens:

docker run -it --rm --user 999:998 my-image bash
whoami

And you get errors like:

whoami: cannot find name for user ID 999

Or the infamous:

I have no name!

It looks weird, but the numeric UID/GID still works for file permissions.

How to run Docker more like a system engineer

Use Docker rootless mode when it fits

Docker’s official rootless docs say you need:

  • newuidmap and newgidmap
  • entries in /etc/subuid and /etc/subgid
  • at least 65,536 subordinate UIDs/GIDs for the user

Example checks:

id -u
whoami
grep ^$(whoami): /etc/subuid
grep ^$(whoami): /etc/subgid

Typical setup:

dockerd-rootless-setuptool.sh install
systemctl --user start docker
export DOCKER_HOST=unix:///run/user/1000/docker.sock
docker info

And docker info should show security options including rootless.

A quick caution, though. The Docker forum discussion makes a sensible point: rootless mode has limitations, and it’s worth testing before you put it into production. If you’re new to it, don’t switch a public-facing host blindly.

Set USER explicitly in your Dockerfile

Don’t rely on defaults. Make the runtime user obvious.

FROM python:3.12-slim

RUN useradd -m -u 10001 appuser
WORKDIR /app
COPY . /app
RUN chown -R appuser:appuser /app

USER 10001
CMD ["python", "app.py"]

Using a numeric UID can be more predictable across distributions than relying on a username alone.

Override with --user when bind mounts matter

For local builds, test runs, and automation, it’s often cleaner to match the host user:

docker run --rm -it \
  -v "$PWD":/workspace \
  -w /workspace \
  --user "$(id -u):$(id -g)" \
  ubuntu:24.04 bash

That keeps generated files owned by your host account.

One catch: the container may not know that UID as a named user, and $HOME may not behave the way some tools expect. The Redbubble article calls this out specifically. Some tools assume a home directory exists; some don’t handle nameless users gracefully.

Don’t confuse “no sudo” with “safer”

This one trips people up all the time.

Running Docker commands without sudo by joining the docker group feels cleaner. It is cleaner from an ergonomics standpoint. But it is not meaningfully less privileged. Docker docs explicitly warn that the docker group grants root-level privileges.

If your goal is convenience, use the group.
If your goal is host hardening, look at rootless mode.

Practical production advice

If I were setting up Docker on a VPS for web apps, databases, or chat services, I’d lean on a few rules:

  1. Run apps in containers as non-root whenever possible
  2. Avoid --privileged unless there is no alternative
  3. Be careful with bind mounts into sensitive host paths
  4. Use rootless mode if your workload supports it
  5. Test volume permissions early, not after deployment
  6. Drop unnecessary Linux capabilities where possible
  7. Consider read-only filesystems for stateless services

That advice lines up pretty well with the Docker forum guidance too: rootless mode protects the host better, but it doesn’t automatically solve every security problem inside the app stack.

Docker as a system engineer not user: a simple mental model

Here’s the cleanest way I know to think about it:

  • Host user: who runs docker commands
  • Docker daemon: rootful or rootless
  • Container user: root or non-root inside the container
  • Mounted files: governed by numeric UID/GID, not friendly usernames

If you keep those four separate in your head, most Docker permission problems suddenly make sense.

Further reading

For Docker security basics, the official Docker rootless mode documentation is the best starting point. And if you’re interested in broader AI infrastructure and ops topics, you could also check our post on Bifrost LLM gateway performance and deployment.

Another related read on this site: Why Gemini models are failing among developers. Different topic, sure, but it fits the same engineering mindset: don’t stop at the surface behavior. Look at the system.

Conclusion

Thinking about Docker as a system engineer not user changes the questions you ask. You stop asking only how to run a container, and start asking what privileges exist at every layer. That shift matters.

If you remember just three things, make them these: Docker defaults to root, the docker group is effectively privileged, and rootless mode is different from running a non-root process in a container. Get those right, and the rest gets much easier.

If you’re cleaning up a Docker host or designing a new deployment, try one service with an explicit USER, test --user $(id -u):$(id -g) on bind mounts, and evaluate rootless mode in a staging environment. If you’ve hit ugly permission bugs or rootless limitations in the real world, leave a comment. Those stories are where the useful lessons live.

Sources

  1. Docker Docs, Rootless mode
    https://docs.docker.com/engine/security/rootless/

  2. Docker Blog, Understanding the Docker USER Instruction
    https://www.docker.com/blog/understanding-the-docker-user-instruction/

  3. Docker Docs, Linux post-installation steps for Docker Engine
    https://docs.docker.com/engine/install/linux-postinstall/

  4. Docker Community Forums, Running Docker containers as non-root user
    https://forums.docker.com/t/running-docker-containers-as-non-root-user/151333

  5. Stack Overflow, how to correctly use system user in docker container
    https://stackoverflow.com/questions/50658883/how-to-correctly-use-system-user-in-docker-container

  6. Medium / Redbubble, Running a Docker container as a non-root user
    https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15

  7. Reddit discussion, why do containers not usually run as the user?
    https://www.reddit.com/r/docker/comments/g50al2/why_do_containers_not_usually_run_as_the_user_are/

  8. TechTarget, Docker's rootless mode a welcome security update
    https://www.techtarget.com/searchitoperations/tip/Dockers-rootless-mode-a-welcome-security-update

  9. Snyk, Securing PHP containers
    https://snyk.io/blog/securing-php-containers/

  10. Trend Micro, Why A Privileged Container in Docker Is a Bad Idea
    https://www.trendmicro.com/de_de/research/19/l/why-running-a-privileged-container-in-docker-is-a-bad-idea.html

Post a Comment