How to Run Rootless Docker (Containers That Can't Become Root on the Host)

Rootless Docker: the daemon runs as you, so a container escape lands in your account, not root. What changes, what breaks, what it's worth.

Several tutorials noted it: docker.sock is root on the host, and the docker group is effectively sudo. Normally that's accepted. Rootless mode changes the deal — the Docker daemon itself runs as your user, inside user namespaces, so even a container that breaks out of its sandbox finds itself as john, not root. It costs some convenience (low ports, a few features) and is worth it on machines that run untrusted or internet-facing containers.

Quick reference

TaskWhat
Installdockerd-rootless-setuptool.sh install (from docker-ce-rootless-extras)
Socketunix:///run/user/1000/docker.sock — set DOCKER_HOST
Start at bootsystemctl --user enable docker + loginctl enable-linger john
Ports under 1024sysctl net.ipv4.ip_unprivileged_port_start=80
Won't workhost networking details, --privileged device access, some cap_add, macvlan, swap limits
Check`docker infogrep -i rootless → rootless` in Security Options

1. Prerequisites

sudo apt install uidmap dbus-user-session docker-ce-rootless-extras -y
grep ^john /etc/subuid /etc/subgid

Both files need a line like john:100000:65536 — the range of IDs your containers map into. Ubuntu adds it when the user is created; add it with sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 john if missing.

If the rootful daemon is running and you're migrating fully, stop it: sudo systemctl disable --now docker.service docker.socket.

2. Install the rootless daemon

As your user, not root:

dockerd-rootless-setuptool.sh install

It sets up a user-level systemd service and prints two lines to add to ~/.bashrc:

export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix:///run/user/1000/docker.sock

systemctl --user enable --now docker
sudo loginctl enable-linger john
docker info | grep -i rootless

loginctl enable-linger keeps your user services running when you're not logged in — otherwise containers stop when you log out.

3. Ports below 1024

The rootless daemon can't bind 80 or 443 by default:

echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-rootless.conf
sudo sysctl --system
systemctl --user restart docker

Or keep the reverse proxy (Nginx/Caddy) on the host and proxy to high ports — which many setups already do.

4. Migrate a stack

Images and volumes live in ~/.local/share/docker now, separate from the rootful /var/lib/docker. For each stack: docker compose pull && docker compose up -d as your user; bind-mounted ./data folders carry over unchanged (they're yours already). Named volumes need the tar trick (65) once. Then remove the rootful data when you're sure: sudo rm -rf /var/lib/docker.

Files written by a container's root user now appear on the host as UID 100000 (the mapped range) — ls -ln makes sense of it, and podman unshare-style tools or chown through the mapping if you need to touch them.

5. What doesn't work (and the workarounds)

6. Podman instead?

Podman is rootless by design, daemonless, and runs most compose files via podman-compose or podman compose. Systemd integration (Quadlet) is excellent for "a container as a service". If you're starting fresh on a security-first box, Podman is a fine choice; if you've got sixty tutorials' worth of Docker habits, rootless Docker is the smaller step.

Where it's worth it

Internet-facing hosts (a VPS with a public site, the Matrix server), the box that runs other people's images you haven't audited, and anything exposed via Cloudflare Tunnel (109). The home media box with a Coral stick: probably not — the hardware access fights you and the exposure is low.

Troubleshooting

docker: command not found / connects to the wrong daemon. DOCKER_HOST not exported in this shell; source ~/.bashrc.

Containers stop when you log out. loginctl enable-linger.

"permission denied" binding port 443. The sysctl in step 3.

Slow networking. The default userspace proxy (slirp4netns) is slower; install passt/pasta and set it as the network driver for near-native speed.

Wrapping up

Install the rootless extras, run the setup tool as yourself, linger on, low ports via sysctl, migrate the stacks that fit. Root is no longer one container escape away on the hosts that face the world — and the stacks that need raw hardware stay where they are.

Call us