Running rootless Docker allows non-root users to run the Docker daemon and containers without special privileges. This adds an extra layer of security in an event a container gains access to its host.
Rootless mode has become part of Docker Engine on v20.10
. There are some known limitations that you should be aware of, see here. And, if you want to learn more about how it works, check out this article.
Pre-requirements
I'm installing Rootless Docker on a vanilla Debian 10 (Buster) x86_64
; but this mode is supported in other distributions as well, more details here.
lsb_release -d && arch
(out)Description: Debian GNU/Linux 10 (buster)
(out)x86_64
Installing Rootless Docker
1. As root
(or using sudo
, if you have that configured), let's create a new user called docker
with its home folder at /srv/docker
:
adduser --home /srv/docker docker
(out)Adding user `docker` ...
(out)Adding new group `docker` (1001) ...
(out)Adding new user `docker` (1001) with group `docker` ...
(out)Creating home directory `/srv/docker` ...
(out)Copying files from `/etc/skel` ...
(out)New password:
(out)Retype new password:
(out)passwd: password updated successfully
(out)Changing the user information for docker
(out)Enter the new value, or press ENTER for the default
(out) Full Name []:
(out) Room Number []:
(out) Work Phone []:
(out) Home Phone []:
(out) Other []:
(out)Is the information correct? [Y/n] Y
2. We need to change these kernel settings before we start:
kernel.unprivileged_userns_clone = 1
enables unprivileged users to create namespaces.net.ipv4.ip_unprivileged_port_start = 0
allows users to open privileged ports below 1024.
Load the new attributes using sysctl
after the changes.
cat > /etc/sysctl.d/50-rootless.conf <<EOL
(out)kernel.unprivileged_userns_clone = 1
(out)net.ipv4.ip_unprivileged_port_start = 0
(out)EOL
sysctl --system
3. We should also load the overlay2
module, the recommended storage driver:
Reload new system modules using the systemctl
command.
echo "options overlay permit_mounts_in_userns=1" > \
(out)/etc/modprobe.d/50-rootless.conf
systemctl restart systemd-modules-load.service
4. That's all needed from the root
for now. Let's open a new terminal or ssh
session with the newly created docker
user:
ssh [email protected]
5. Download and run the Rootless Docker install script:
curl -fsSL https://get.docker.com/rootless | sh
(out)...
(out)[INFO] Installed docker.service successfully.
(out)[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
(out)[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger docker`
(out)
(out)[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):
(out)
(out)export PATH=/srv/docker/bin:$
(out)export DOCKER_HOST=unix:///run/user/1001/docker.sock
6. If the install was successful, we want to add the Docker environment variables to .bashrc
, so the Docker commands are easily available in future logins:
cat >> ~/.bashrc <<EOL
(out)
(out)# Docker Environment
(out)export PATH=/srv/docker/bin:$PATH
(out)export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
(out)EOL
7. Finally, to enable the service to start automatically during the system boot:
systemctl --user enable docker
su -c "loginctl enable-linger $(whoami)"
8. I'd recommend a reboot
at this point, just to make sure everything is working. You should be able to run a systemctl status
to confirm the Docker daemon is running:
systemctl --user status docker
(out)● docker.service - Docker Application Container Engine (Rootless)
(out) Loaded: loaded (/srv/docker/.config/systemd/user/docker.service)
(out) Active: active (running) since Sat 2021-03-20 00:01:53 EDT; 11h ago
(out) Docs: https://docs.docker.com/engine/security/rootless/
(out) Main PID: 522 (rootlesskit)
(out) CGroup: /user.slice/user-1001.slice/[email protected]/docker.service
Installing Docker Compose
Docker Compose makes it easier to document, configure and manage your Docker containers.
There are many different ways on how to install it but for our rootless Docker, I decided to go meta and run it inside a container as well; which is pretty simple to do.
1. Download the small install script:
At the time this article was written the latest Docker Compose released was v1.28.5
, but you should check current version here.
curl -L --fail https://github.com/docker/compose/releases/download/1.28.5/run.sh \
(out)-o $HOME/bin/docker-compose
2. Make it executable:
chmod +x $HOME/bin/docker-compose
3. When you run docker-compose
for the first time, it will download all required images:
docker-compose version
(out)docker-compose version 1.28.5, build c4eb3a1
(out)docker-py version: 4.4.4
(out)CPython version: 3.7.10
(out)OpenSSL version: OpenSSL 1.1.1j 16 Feb 2021
Installing NGINX
While I don't fully intent to go over a NGINX installation, I didn't want to leave this article without something less tangible to test our rootless Docker setup.
In fact, this NGINX setup doesn't differ from your typical, root-enabled, Docker.
1. Let's create some folders structure to house our new NGINX container:
mkdir -p /srv/docker/containers/nginx && cd /srv/docker/containers/nginx
2. Using a docker-compose.yml
file, we will create a nginx
container using the nginx:alpine
image and open the port 80:80
:
vi docker-compose.yml
(out)version: "3.9"
(out)services:
(out) nginx:
(out) container_name: nginx
(out) image: nginx:alpine
(out) ports:
(out) - "80:80"
3. Finally, start your new container, when ran for the first time it will download any required images:
docker-compose start
4. On your browser, open http://your.docker.ip/
and you should be welcomed by NGINX's default page: