Rootless Docker and Daemon Socket Access
Membership of the docker group is equivalent to root on the host, and most people who have it do not know why. What the exposure actually is, what rootless mode changes, and what it costs you.
Security and Production Guide 39 of 46 Advanced
- OSUbuntu 26.04 LTS (resolute)
- Docker Engine29.7.2
- Buildxv0.36.1
- Architectureamd64
- TimeAbout 12 min
- Reviewed22 August 2026
Inspected on the versions above. The rootless installation was NOT performed on the capture host - it makes host-wide changes to a shared machine. Only read-only inspection was executed; the install commands below are shown as reference and are labelled as such.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| DOCKER01 | 192.168.0.21 | Ubuntu 26.04 LTS | Docker Host | 2 Core | 4 GB | 50 GB |
Before you start
- You understand images, containers and the daemon - guide 2 in this path.
- A host where you are permitted to make system-level changes, if you intend to install rootless.
-
The daemon runs as root, and that is the whole issue
Docker's daemon runs as root because creating namespaces, configuring networking and mounting filesystems all require it. The CLI talks to it over a Unix socket owned by
root:docker. Anyone who can write to that socket can ask the daemon to do root things - which is why the group is not a lesser privilege.bash ls -l /var/run/docker.socksrw-rw---- 1 root docker 0 Aug 21 04:04 /var/run/docker.sockExpected resultA socket owned by root with group docker.
Success conditionYou can see that the group is the access-control mechanism, and it grants access to a root-owned service.
-
Why docker group means root
This is not theoretical and it needs no exploit. Anyone who can talk to the daemon can ask it to mount the host's root filesystem into a container they control, as root. There is no permission boundary left after that. Treat granting docker group membership as granting root, because it is.
bash # DO NOT RUN on a machine you do not own - this is the escalation, shown so you recognise itdocker run -v /:/host -it alpine chroot /host sh# the container now has a root shell on the HOST filesystemgetent group docker# audit who is in this group; each of them effectively has rootExpected resultThe membership list. The escalation itself is deliberately not run here.
Success conditionYou can justify treating docker group membership as a root grant in a security review.
-
What rootless mode changes
Rootless runs the daemon itself as your unprivileged user, inside a user namespace where your uid is mapped to root INSIDE the namespace but remains unprivileged outside it. A container escape lands the attacker as your ordinary user, not as host root. The daemon socket moves into your runtime directory and belongs to you alone.
bash Example session docker info --format "{{json .SecurityOptions}}"["name=apparmor","name=seccomp,profile=builtin","name=cgroupns"]# a ROOTLESS daemon additionally reports name=rootless hereExpected resultThe security options of the daemon you are talking to. This host is rootful, so
rootlessis absent.Success conditionYou can tell rootful from rootless with one command. That absent entry is the check.
-
The tooling, and what installing it would do
The setup tool ships with Docker on Ubuntu. It installs a systemd user service, sets up uid and gid mappings, and starts a second daemon owned by you - a host-level change affecting every user of the machine. It was deliberately not run here for that reason; the help output below is real, the installation is not something this guide performed.
bash Example session dockerd-rootless-setuptool.sh --helpUsage: /usr/bin/dockerd-rootless-setuptool.sh [OPTIONS] COMMANDA setup tool for Rootless Docker (dockerd-rootless.sh).Documentation: https://docs.docker.com/go/rootless/Options: -f, --force Ignore rootful Docker (/var/run/docker.sock)Commands: check Check prerequisites# 'dockerd-rootless-setuptool.sh install' was NOT run - it changes a shared hostExpected resultThe tool's own help.
checkreports prerequisites without changing anything.Success conditionYou know the tool exists and what installing it entails. Run
checkfirst on a machine that is yours. -
What rootless costs
It is not free, and the limitations are the reason it is not the default. Binding ports below 1024 needs extra configuration. Some storage drivers and network features are unavailable. Performance through the userspace network stack is lower. Resource limits need cgroup v2 with delegation configured. For a developer workstation these rarely matter; for a production host they need checking against your requirements first.
bash Example session docker info --format "cgroup={{.CgroupVersion}} driver={{.Driver}}"cgroup=2 driver=overlayfsExpected resultcgroup v2, which rootless needs for limits to work at all.
Success conditionYou can list three things that would break before you migrate anything.
-
What to do if you cannot go rootless
Most of the benefit is available without switching daemons. Never mount the docker socket into a container - that hands the container the same root-equivalent access the group has. Run container processes as a non-root user. Drop capabilities. These are covered in the next guide and cost nothing.
bash # mounting the socket gives that container root on the host - avoid it-v /var/run/docker.sock:/var/run/docker.sockdocker run --rm --user 1000:1000 alpine:3.22 iduid=1000 gid=1000 groups=1000Expected resultA container running as an unprivileged uid.
Success conditionYou have a mitigation you can apply today. See guide 40 for the rest.
Troubleshooting
Cannot connect to the Docker daemon after installing rootless
Why: The CLI is still pointing at the rootful socket, or the user service is not running.
Fix:Point DOCKER_HOST at your own socket and confirm the user service is up. Rootless daemons stop when your session ends unless lingering is enabled.
bash systemctl --user status dockerexport DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sockRootless cannot bind port 80
Why: Unprivileged processes cannot bind ports below 1024 by default.
Fix:Publish a high port and put a reverse proxy in front, or grant the capability to the rootless proxy binary. Do not weaken the host-wide sysctl casually.
bash docker run -d -p 8080:80 nginx:alpineContainers stop when you log out
Why: The rootless daemon is a user service tied to your session.
Fix:Enable lingering for the account so its user services survive logout.
bash sudo loginctl enable-linger $USERResource limits are ignored under rootless
Why: cgroup v2 delegation is not configured for the user, so the daemon cannot set limits.
Fix:Confirm cgroup v2 and that the controllers are delegated to the user slice.
bash cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/cgroup.controllers