Docker/Moby
Rootless Docker/Moby was implemented in 2018 following rootless runc, containerd, and BuildKit. Rootless Docker has been merged to the Docker/Moby upstream since Docker 19.03.
Docker 19.03 provides almost full features for Rootless mode, including support
for port fowarding (docker run -p) and multi-container networking (docker network create),
but it doesn’t support limiting resources with cgroup.
Docker 20.10 added support for limiting resources using cgroup v2.
Docker 23 further simplified the installation process.
Docker 29.5 added support for --net=host and improved the support for propagating the original source IP address of incoming connections.
Note
Please read the common steps first.
Especially, make sure
$XDG_RUNTIME_DIRto be set properly.
Docker (since 20.10) provides docker-ce-rootless-extras RPMs and DEBs that can be installed by the root for all the users on the host.
The package is usually automatically installed on installing Docker from https://get.docker.com.
curl -o install.sh -fsSL https://get.docker.com
sudo sh install.sh
After installing Docker, run the following command as a non-root user to create the systemd user-instance unit:
dockerd-rootless-setuptool.sh install
This method does not use RPMs/DEBS and can be executed by a non-root user without sudo.
curl -o rootless-install.sh -fsSL https://get.docker.com/rootless
sh rootless-install.sh
export PATH=$HOME/bin:$PATH
Starting with Docker v23, the docker CLI connects to the rootless daemon by default when it is available.
Run docker info to confirm that the docker CLI is connecting to the rootless daemon:
$ docker info
Client: Docker Engine - Community
Version: 28.3.3
Context: rootless
...
Server:
...
Security Options:
seccomp
Profile: builtin
rootless
cgroupns
...
Historical information for Docker prior to v23
To connect to the rootless daemon, you had to set either the CLI context or an environment variable.
docker context use rootless
docker run hello-world
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
docker run hello-world
To start/stop the daemon, use systemctl --user <start|stop> docker instead of systemctl <start|stop> docker.
The systemd unit file is located as ~/.config/systemd/user/docker.service.
Resource-related flags of docker run, such as --cpus, --memory, --blkio-weight, and --pids-limit can be used only when the following conditions are satisfied:
- Docker/Moby version is 20.10 or later
- containerd version is 1.4 or later
- runc version is 1.0-rc91 or later
- The host is running with cgroup v2
- The host is running with systemd
To impose resource limitations without cgroup, see https://docs.docker.com/engine/security/rootless/#limiting-resources
Docker/Moby uses slirp4netns as the default network stack if slirp4netns v0.4.0 or later is installed. Otherwise it falls back to VPNKit, pasta, or gvisor-tap-vsock in that order.
To explicitly specify the network stack, create ~/.config/systemd/user/docker.service.d/override.conf with the following content:
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=gvisor-tap-vsock"
And then restart the daemon:
systemctl --user daemon-reload
systemctl --user restart docker
Docker/Moby also supports lxc-user-nic SETUID binary experimentally: https://docs.docker.com/engine/security/rootless/#changing-the-network-stack
Docker/Moby uses RootlessKit as the default port forwarder, but RootlessKit did not support propagating the original source IP address of incoming connections until RootlessKit v3.0 that is bundled with Docker v29.5.
For prior versions, you had to change the port forwarder to slirp4netns or pasta to keep source IP addresses of incoming connections.
RootlessKit v3.0 bundled with Docker v29.5 added the support for propagating the original source IP address of incoming connections, so there is no reason to use slirp4netns or pasta port forwarder anymore.
However, the source IP propagation requires disabling the userland proxy:
mkdir -p ~/.config/docker
echo '{"userland-proxy": false}' >~/.config/docker/daemon.json
systemctl --user restart docker
You may also need to load the br_netfilter kernel module:
sudo tee /etc/modules-load.d/docker.conf <<EOF >/dev/null
br_netfilter
EOF
sudo systemctl restart systemd-modules-load.service
Create ~/.config/systemd/user/docker.service.d/override.conf with the following content:
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
And then restart the daemon:
systemctl --user daemon-reload
systemctl --user restart docker
Create ~/.config/systemd/user/docker.service.d/override.conf with the following content:
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=pasta"
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=implicit"
(The port driver is called “implicit” in RootlessKit, because the ports are handled by pasta, not RootlessKit itself.)
And then restart the daemon:
systemctl --user daemon-reload
systemctl --user restart docker
You need to run sudo loginctl enable-linger .... See Getting Started/Login.
Run the following commands to remove all containers and configurations:
dockerd-rootless-setuptool.sh uninstall
~/bin/rootlesskit rm -rf ~/.local/share/docker ~/.config/docker
To uninstall binaries, run sudo apt-get remove docker-ce-*
or sudo dnf remove docker-ce-*.
If you installed Rootless Docker without using packages,
remove the following files under ~/bin:
containerd
containerd-shim
containerd-shim-runc-v2
ctr
docker
docker-init
docker-proxy
dockerd
dockerd-rootless-setuptool.sh
dockerd-rootless.sh
rootlesskit
rootlesskit-docker-proxy
runc
vpnkit