Rootless Docker and why containers shouldn't run as root
Run the Docker daemon and your containers as a non-root user so a container escape lands unprivileged, plus the subuid, cgroups, and storage gotchas.
Default Docker runs the daemon as root. A container escape or daemon bug often yields uid 0 on the host — game over. Rootless Docker runs dockerd under your user account, maps container uids through subordinate id ranges (/etc/subuid, /etc/subgid), and uses slirp4netns or pasta for networking without touching host iptables as root. The tradeoff is friction: some flags, storage drivers, and cgroup versions behave differently than rootful Docker.
This note installs rootless Docker, verifies subuid mappings, runs a sample container, and documents the limitations you hit in CI and on older kernels. Pair with Docker hardening for seccomp, read-only rootfs, and capability drops; Linux essentials for user namespaces fundamentals.
Install script creates ~/.config/systemd/user/docker.service. Logout/login required so subuid maps apply. Test before migrating prod workloads.
Install rootless Docker
Use the official rootless install script — it configures XDG_RUNTIME_DIR, user systemd, and socket at $XDG_RUNTIME_DIR/docker.sock. Export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock in your shell profile so CLI talks to the user daemon, not /var/run/docker.sock.
Rootless mode uses fuse-overlayfs or btrfs when the kernel denies unprivileged overlay mounts. On RHEL and Ubuntu LTS, package names differ but the flow is the same: prerequisites, install script, user systemd enable. Document docker context usage if developers switch between rootful Colima and rootless Linux workstations.
curl -fsSL https://get.docker.com/rootless | sh# Add to ~/.bashrcexport DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/docker.sockexport PATH=/usr/bin:$HOME/bin:$PATHsystemctl --user enable --now docker
Subordinate uid/gid maps
Rootless mode maps container root (uid 0 inside) to a high unprivileged uid on the host — typically the first entry in /etc/subuid. Without 65536 subids per user, nested namespaces fail mysteriously. Corporate LDAP users need subuid entries provisioned at account creation.
Slirp4netns provides user-mode networking without root iptables rules — fine for dev, sometimes limiting for published ports at scale. Pasta (passt) improves performance on newer kernels. For production orchestration, Kubernetes with user namespaces (1.30+) pursues similar goals at pod level; rootless Docker is the laptop and CI builder story.
# user: start: countalice:100000:65536# container uid 0 → host uid 100000
docker info | grep rootlessrootless: truedocker run --rm alpine iduid=0(root) gid=0(root) # inside containerps aux | grep runc | head -1host process runs as alice, not rootWhere this goes next
Combine rootless mode with cap_drop: ALL, read-only rootfs, and non-root USER in Dockerfiles. On orchestrators, migrate the same principles to Kubernetes Pod Security. Docker hardening covers seccomp profiles and image minimalism; Linux hardening covers the host OS beneath the daemon.
CI builders benefit most from rootless — compromised build scripts lose root on the host. Production Kubernetes nodes still run containerd as root; rootless Docker is not a substitute for pod security policies there.
Go deeper in a courseDocker hardeningRootless mode, seccomp, capabilities, and minimal production images.View course