Running DevContainers as a Non-Root User
A devcontainer running as root is both a security risk and a source of root-owned files on your host mount. This page runs it as a non-root user via remoteUser, aligning the UID so workspace files stay yours — least privilege and correct ownership in one move.
Prerequisites
You need a base image with a non-root user (or to create one).
- A base image providing a non-root user (the official images do).
remoteUserset to that user.- UID alignment via
updateRemoteUserUIDwhere host UIDs differ.
Step-by-Step Implementation
- Use a base image with a non-root user, and select it.
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu@sha256:PINNED",
"remoteUser": "vscode"
}
- Align the UID with the host so bind-mount files stay yours.
{ "updateRemoteUserUID": true }
- Create a non-root user if your base lacks one.
RUN useradd -m -s /bin/bash dev
USER dev
- Verify the container runs non-root.
devcontainer exec --workspace-folder . -- id -u # non-zero
Common Pitfalls
Root-run issues are an omitted remoteUser or a UID mismatch.
| Symptom | Root Cause | Remediation |
|---|---|---|
| Container runs as root | remoteUser omitted | Set a non-root remoteUser |
| Root-owned files on the host | UID not aligned | Enable updateRemoteUserUID |
| Permission denied writing workspace | Container UID != host UID | Align UIDs / fix ownership |
| Base has no non-root user | Minimal image | Create one in the Dockerfile |
Conclusion
Run non-root by default: select a non-root remoteUser and align its UID with the host, so a compromise is contained and workspace files stay owned by you. It is a one-line change with an outsized payoff for both security and ergonomics.
FAQ
Why run non-root if it's just my dev machine? Because a devcontainer runs code from a repository, and a compromise (a malicious dependency, a bad script) is far more contained as an unprivileged user. Non-root also prevents root-owned files appearing on your host mount, which break Git and local tooling.
What does updateRemoteUserUID do?
It aligns the container user's UID/GID with your host user's, so files the container writes to the bind-mounted workspace are owned by you rather than a mismatched UID. It is the companion to remoteUser for correct ownership.
My base image has no non-root user — now what?
Create one in the Dockerfile (useradd + USER) and set remoteUser to it. The official devcontainer base images already provide a non-root vscode user, so prefer those to avoid the extra step.
Related
- Up to DevContainer Security & Secrets Management — the overview of hardening.
- Injecting Secrets into a DevContainer Safely — keeping secrets out of the image.
- devcontainer.json Property Reference — the remoteUser and UID keys.