Expose Rootless Docker API socket via TCP with SSL

Published by moxlotus on

In my previous write-ups, I explained how to set up rootless Docker, and I also mentioned that I prefer using Portainer to manage my containers. However, to enable Portainer to manage Docker daemons on multiple servers, I need to be able to connect to these daemons and add them as Portainer environments. Exposing the Docker API socket via TCP is one way to achieve this.

By default, the Docker API socket is only accessible locally on the host machine. However, it is possible to expose the Docker API socket via TCP so that it can be accessed remotely.

You can configure the Docker daemon to expose the API socket via TCP by adding the following configuration to the daemon.json file, which can be found in ~/.config/systemd/docker/daemon.json

{
  "hosts": ["unix:///run/user/1001/docker.sock", "tcp://0.0.0.0:2375"],
}

To enable the rootless docker daemon to listen to specific ports, you will need to add the following line to the docker.service configuration file located at ~/.config/systemd/user

Environment=DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="-p 0.0.0.0:2375:2375/tcp"

After making changes to the docker.service configuration file and the daemon.json configuration file, you'll need to reload the daemon and restart the docker service for the changes to take effect. Here are the steps to do so:

  1. Reload the daemon by running the command:
    systemctl --user daemon-reload
  2. Restart the docker service by running the command:
    systemctl --user restart docker

However, it is a security risk to expose the Docker API socket via TCP as it allows remote access to the Docker API. Therefore, it is recommended to use TLS encryption and authentication to secure the connection.

To enable SSL, you will need to have the CA certificate, server certificate and server key. You may find the instruction on how to generate these files on docker.

Together with the files above, you will need to update the daemon.json as shown below

{
  "hosts": ["unix:///run/user/1001/docker.sock", "tcp://0.0.0.0:2376"],
  "tlsverify": true,
  "tlscacert": "/home/docker/.docker/certs/ca.crt",
  "tlscert": "/home/docker/.docker/certs/server.crt",
  "tlskey": "/home/docker/.docker/certs/server.key"
}

Lastly, change the port from 2375 to 2376 in docker.service

Environment=DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="-p 0.0.0.0:2376:2376/tcp"
[Unit]
Description=Docker Application Container Engine (Rootless)
Documentation=https://docs.docker.com/go/rootless/

[Service]
Environment=PATH=/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Environment=DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="-p 0.0.0.0:2376:2376/tcp"
ExecStart=/usr/bin/dockerd-rootless.sh
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
Type=notify
NotifyAccess=all
KillMode=mixed

[Install]
WantedBy=default.target

Just like before, reload the daemon and restart the docker to see the result.

Share it with others
Categories: Docker