analyticsdockerdocker enginedocker enviromentsdocker managementgoogle cloud platformportainerraspberry pi
This tutorial is about managing a Docker Engine remotely using Portainer connected to the protected Docker daemon socket (
TCP port 2376). By default, you can manage Docker locally through a non-networked UNIX socket (option
-v /var/run/docker.sock:/var/run/docker.sockwhile running Portainer). But, if you want the Docker Engine to be reachable through the network in a safe manner, you need to enable TLS by specifying the
--tlsverifyflag and pointing Docker’s
--tlscacertflag to a CA certificate. Then, the daemon only accepts connections from clients that are authenticated by a certificate signed by that CA certificate.
This tutorial accomplishes the following:
- Create a CA, server and client keys with OpenSSL,
- Configure the remote API for dockerd (Docker Engine) to allow external connections,
- Deploy Portainer and connect it to the protected Docker daemon socket.
This tutorial summarizes and combines the following articles:
You need to install OpenSSL to follow the following steps. I will not go deep into this topic because there are plenty of tutorial about this, that you can find on Google.
To create the CA key and the CA certificate type the following on your terminal:
export HOST=<your-domain-name> openssl genrsa -aes256 -out ca-key.pem 4096 # enter a pass phrase to protect the ca-key openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
<your-domain-name>for the internal/external domain name, where the Docker Engine is running. You can change the valid days (
-days 365). Normally for internal certificates, "365-days" could be a too short period and you'll need to re-new often the certificates, which also means more security but, it can be annoying!. Enter the information asked (Country, State, City, Organization, Common Name & Email) and for the Common Name option use the environmental variable
Now create a server key and certificate signing request (CSR) typing:
openssl genrsa -out server-key.pem 4096 openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
Since TLS connections can be made through IP-address as well as DNS name (
$HOST), you can add IP-addresses (e.g. localhost and network) when creating the certificate. In the following case, I added the
127.0.0.1(localhost) as example:
echo subjectAltName = DNS:$HOST,IP:10.0.0.200,IP:127.0.0.1 >> extfile.cnf
Set the Docker daemon key’s extended usage attributes to be used only for server authentication:
echo extendedKeyUsage = serverAuth >> extfile.cnf
Finally, generate the server signed certificate:
penssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \ -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Again, you can change the valid days (
For client authentication, create a client key and certificate signing request using the following lines:
openssl genrsa -out key.pem 4096 openssl req -subj '/CN=client' -new -key key.pem -out client.csr
To make the key suitable for client authentication, create a new extensions config file:
echo extendedKeyUsage = clientAuth > extfile-client.cnf
Finally, generate the client signed certificate:
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \ -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Optional: You can protect your keys from accidental damage, removing their write permissions. Moreover, certificates can be world-readable, but you might want to remove write access to prevent accidental damage:
chmod -v 0400 ca-key.pem key.pem server-key.pem chmod -v 0444 ca.pem server-cert.pem cert.pem
server-key.pemfiles to a folder that you won't remove e.g.
mkdir ~/.certs cp ca.pem ~/.certs cp server-cert.pem ~/.certs cp server-key.pem ~/.certs
Then, create the file
startup_options.confand its path if they don't exist:
mkdir -p /etc/systemd/system/docker.service.d/ sudo nano /etc/systemd/system/docker.service.d/startup_options.conf
and put the following text inside that file:
# /etc/systemd/system/docker.service.d/override.conf [Service] ExecStart= ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/home/pi/.certs/ca.pem --tlscert=/home/pi/.certs/cert.pem --tlskey=/home/pi/.certs/key.pem -H fd:// -H tcp://0.0.0.0:2376
In my case, I managed the Docker Engine of a Raspberry Pi from a Portainer instance running on my PC. Thus, the path to the certificates started with
/home/pi/as you see above.
Then, reload the unit files and restart the Docker daemon with the new startup options:
sudo systemctl daemon-reload sudo systemctl restart docker.service
To remotely connect to the Docker socket protected with TLS, you only need the (
key.pemfiles. If you don't have Portainer installed follow the instructions on this article.
Go to the Portainer web interface, log in and then click on
Endpoints(left menu) >
+ Add Endpointand select the option
Docker (Docker environment). Complete only the endpoint
Endpoint URL(in my case
10.0.0.200:2376-don't forget the port
:2376!) and activate the
TLSswitch (see Fig. 1). This enables 4 options, you can choose between both first options:
- TLS with server and client verification (Use client certificates and server verification): upload the TLS CA Certificate
ca.pem, TLS certificate
cert.pemand the TLS key
- TLS with client verification only (Use client certificates without server verification): upload only the TLS certificate
cert.pemand the TLS key
Using the first option, the server verifies the authenticity of the client (using
key.pem), and the client that of the server (comparing
ca.pem), while in the second only the server only verifies the authenticity of the client (using
After doing this, click on the
+Add endpointbutton and you will see the endpoint listed on the home page and after clicking on it, you can manage it.
Fig. 1: TLS options!
This tutorial explains you how to manage a Docker Engine on a remote computer using Portainer. The connection is via the TCP socket protected using TLS (
port 2376). This means, the client (and the server) needs to verify its authenticity using (a) CA certificate(s). Then, you can manage all Docker Engines using only one running Portainer instance on your PC or a server, thus saving resources on your environment.