This page looks best with JavaScript enabled

Exploring Rootless Docker

 ·   ·  ☕ 6 min read


Why rootless docker?

“Rootless” Docker refers to running Docker containers without granting the Docker daemon full root privileges on the host system. This can provide added security, as it reduces the potential attack surface and damage that could be caused by a malicious or compromised Docker daemon.

In normal Docker usage, the Docker daemon runs as the root user, which means it has complete access to the host system. While this is necessary for many Docker features and functionality, it can also represent a significant security risk, especially when running untrusted or unknown containers.

By using rootless Docker, you can reduce the level of privileged access that the Docker daemon has on your system, making it harder for attackers to exploit vulnerabilities in the Docker software or its containers.

It’s worth noting that some features and functionality may not be available in a rootless Docker setup, as they require full root access. However, for many users and use cases, rootless Docker provides a good balance between security and functionality.

In summary, the main difference between normal Docker and rootless Docker is the level of privileged access that the Docker daemon has on the host system. While normal Docker requires full root access, rootless Docker operates with reduced privileges for added security.

How to install

These instructions are for Linux. Similar instructions might exist for macOS. But certainly, Windows does not have a root concept, and I haven’t explored the Windows side of rootless docker. If you write a follow up post on Windows side, please left it in the comments section for other to view.

I am following these instructions on Ubuntu. If you are using the same, you might not be aware that docker command is provided by 2 different packages. One is from docker’s official repo which is available as docker-ce. Another one is from Debian’s official repository which is available as

If you want to proceed, please uninstall if you are using it:

sudo apt remove docker docker-engine containerd runc

Install docker-ce. If you are already using docker-ce, you’re good to go:

sudo apt update
sudo apt install docker-ce docker-ce-cli

I am assuming that your docker service is running, stop them using the following command:

sudo systemctl disable --now docker.service docker.socket

There is one dependency that is remaining, it’s uidmap. Do it like this:

sudo apt install uidmap

Now we are ready to do the final step:

curl -fsSL | sh

You can see the installation progressing, here is my log:

# Installing stable version 23.0.0
# Executing docker rootless install script, commit: 6647403
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 63.7M  100 63.7M    0     0   143M      0 --:--:-- --:--:-- --:--:--  143M
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 19.1M  100 19.1M    0     0  85.1M      0 --:--:-- --:--:-- --:--:-- 85.4M
+ PATH=/home/ubuntu/bin:/home/ubuntu/.local/bin:/home/ubuntu/.vscode-server/bin/e2816fe719a4026ffa1ee0189dc89bdfdbafb164/bin/remote-cli:/home/ubuntu/.local/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/var/lib/snapd/snap/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/var/lib/snapd/snap/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/var/lib/snapd/snap/bin /home/ubuntu/bin/ install
[INFO] Creating /home/ubuntu/.config/systemd/user/docker.service
[INFO] starting systemd service docker.service
+ systemctl --user start docker.service
+ sleep 3
+ systemctl --user --no-pager --full status docker.service
● docker.service - Docker Application Container Engine (Rootless)
     Loaded: loaded (/home/ubuntu/.config/systemd/user/docker.service; disabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-02-11 10:27:47 UTC; 3s ago
   Main PID: 1523 (rootlesskit)
      Tasks: 35
     Memory: 31.3M
        CPU: 535ms
     CGroup: /user.slice/user-1000.slice/[email protected]/app.slice/docker.service
             ├─1523 rootlesskit --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/ubuntu/bin/
             ├─1532 /proc/self/exe --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/ubuntu/bin/
             ├─1546 slirp4netns --mtu 65520 -r 3 --disable-host-loopback --enable-sandbox --enable-seccomp 1532 tap0
             ├─1554 dockerd
             └─1574 containerd --config /run/user/1000/docker/containerd/containerd.toml --log-level info

Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220314464Z" level=warning msg="WARNING: No io.max (wbps) support"
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220323424Z" level=warning msg="WARNING: No io.max (riops) support"
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220336374Z" level=warning msg="WARNING: No io.max (wiops) support"
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220346775Z" level=warning msg="WARNING: bridge-nf-call-iptables is disabled"
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220355915Z" level=warning msg="WARNING: bridge-nf-call-ip6tables is disabled"
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220391885Z" level=info msg="Docker daemon" commit=d7573ab graphdriver=overlay2 version=23.0.0
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.220586509Z" level=info msg="Daemon has completed initialization"
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.261491765Z" level=info msg="[core] [Server #10] Server created" module=grpc
Feb 11 10:27:47 ip-10-2-1-39 systemd[919]: Started Docker Application Container Engine (Rootless).
Feb 11 10:27:47 ip-10-2-1-39[1554]: time="2023-02-11T10:27:47.269415389Z" level=info msg="API listen on /run/user/1000/docker.sock"
+ DOCKER_HOST=unix:///run/user/1000/docker.sock /home/ubuntu/bin/docker version
 Version:           23.0.0
 API version:       1.42
 Go version:        go1.19.5
 Git commit:        e92dd87
 Built:             Wed Feb  1 17:43:29 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
  Version:          23.0.0
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.5
  Git commit:       d7573ab
  Built:            Wed Feb  1 17:46:24 2023
  OS/Arch:          linux/amd64
  Experimental:     false
  Version:          v1.6.16
  GitCommit:        31aa4358a36870b21a992d3ad2bef29e1d693bec
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
  Version:          0.19.0
  GitCommit:        de40ad0
  Version:          1.1.0
  ApiVersion:       1.1.1
  NetworkDriver:    slirp4netns
  PortDriver:       builtin
  StateDir:         /tmp/rootlesskit896353388
  Version:          1.0.1
  GitCommit:        6a7b16babc95b6a3056b33fb45b74a6f62262dd4
+ systemctl --user enable docker.service
Created symlink /home/ubuntu/.config/systemd/user/ → /home/ubuntu/.config/systemd/user/docker.service.
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger ubuntu`

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Use CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):

export PATH=/home/ubuntu/bin:$PATH
Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1000/docker.sock

We have finally installed docker. And what we have basically done is installed it on the user level.

At the end of the installation, you’ll be asked to stick some exports in your .bashrc. You need to do that in order to experience a flawless switch.

Things you should know

Start/Stop Container

To start or stop the docker daemon, you need same old systemctl command. But you’re going to pass --user flag after the command.

systemctl --user stop docker
systemctl --user start docker

Connect from Client

There are a few ways you can interact with docker daemon.

The most common way is the command line way, another is docker desktop. There are also different SDKs available in different languages.

When you use rootful docker, you do not have to explicitly DOCKER_HOST becuase it is already set. But after switching to rootless docker, you might need to specify this environment variable when you intend to connect to the host.

Value of this environment variable can be found by using this string:


You may want to expand the XDG_RUNTIME_DIR when you are trying to


Share on

Santosh Kumar
Santosh Kumar
Santosh is a Software Developer currently working with NuNet as a Full Stack Developer.