How to Configure Docker Daemon TLS Encryption on RHEL 7

By default, the Docker daemon on RHEL 7 listens only on a Unix socket at /var/run/docker.sock, which limits access to processes on the same host. When you need to manage Docker remotely — from a CI server, a centralised management host, or a deployment automation tool — you must expose the daemon over TCP. Without encryption, this TCP endpoint transmits commands and image data in plain text and allows any host that can reach the port to control the Docker daemon as root. Configuring TLS mutual authentication ensures that only clients holding a valid certificate signed by your Certificate Authority can connect, and that all traffic is encrypted in transit. This tutorial walks through generating a CA, server certificate, and client certificate using OpenSSL, configuring the Docker daemon to enforce TLS, and connecting remotely from a management workstation.

Prerequisites

  • RHEL 7 Docker host with Docker CE installed and running
  • openssl available on the server (installed by default on RHEL 7)
  • Root or sudo access on the Docker host
  • The hostname or IP address of the Docker host (used in the certificate SAN)
  • Port 2376 open in the firewall between client and server
  • Docker CE installed on the client machine if testing remote access

Step 1: Creating a Certificate Authority (CA)

All certificates in this setup will be signed by a private CA that you control. Create a dedicated directory to hold the CA and generated certificates:

mkdir -p /etc/docker/tls
cd /etc/docker/tls
chmod 700 /etc/docker/tls

# Generate the CA private key (4096-bit RSA)
openssl genrsa -aes256 -out ca-key.pem 4096

# Generate the CA certificate (valid for 10 years)
openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 
  -out ca.pem 
  -subj "/C=US/ST=California/L=San Francisco/O=MyOrg/CN=docker-ca"

chmod 0444 ca.pem
ls -la

The ca.pem file is the public certificate that will be distributed to clients. The ca-key.pem must remain secret — it is used only to sign server and client certificates.

Step 2: Generating the Server Certificate

The server certificate must include Subject Alternative Names (SANs) matching every hostname and IP address through which clients will reach the Docker daemon. Connections will fail if the SAN does not match the address used by the client.

cd /etc/docker/tls

# Set your Docker host's hostname and IP (adjust these)
DOCKER_HOST_FQDN="docker-host.example.com"
DOCKER_HOST_IP="192.168.1.100"

# Generate server private key
openssl genrsa -out server-key.pem 4096

# Create a certificate signing request (CSR)
openssl req -subj "/CN=${DOCKER_HOST_FQDN}" 
  -sha256 -new -key server-key.pem -out server.csr

# Create the SAN extension file
cat > extfile-server.cnf <<EOF
subjectAltName = DNS:${DOCKER_HOST_FQDN},IP:${DOCKER_HOST_IP},IP:127.0.0.1
extendedKeyUsage = serverAuth
EOF

# Sign the server certificate with the CA (valid for 5 years)
openssl x509 -req -days 1825 
  -sha256 
  -in server.csr 
  -CA ca.pem 
  -CAkey ca-key.pem 
  -CAcreateserial 
  -out server-cert.pem 
  -extfile extfile-server.cnf

chmod 0444 server-cert.pem
chmod 0400 server-key.pem

Step 3: Generating Client Certificates

Each client that needs to connect to the Docker daemon requires its own certificate signed by the same CA. The extendedKeyUsage = clientAuth extension restricts these certificates to client authentication only:

cd /etc/docker/tls

# Generate client private key
openssl genrsa -out client-key.pem 4096

# Create client CSR (CN can be the username or machine name)
openssl req -subj "/CN=docker-client" 
  -new -key client-key.pem -out client.csr

# Create client extension file (clientAuth only)
cat > extfile-client.cnf <<EOF
extendedKeyUsage = clientAuth
EOF

# Sign the client certificate with the CA
openssl x509 -req -days 1825 
  -sha256 
  -in client.csr 
  -CA ca.pem 
  -CAkey ca-key.pem 
  -CAcreateserial 
  -out client-cert.pem 
  -extfile extfile-client.cnf

chmod 0444 client-cert.pem
chmod 0400 client-key.pem

# Remove CSR files — they are no longer needed
rm -f server.csr client.csr extfile-server.cnf extfile-client.cnf

Step 4: Configuring the Docker Daemon

Edit or create /etc/docker/daemon.json to enable TLS and point the daemon to the certificate files. The hosts array binds Docker to both the Unix socket (for local tools) and TCP 2376 with TLS:

cat > /etc/docker/daemon.json <<'EOF'
{
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
  "tlsverify": true,
  "tlscacert": "/etc/docker/tls/ca.pem",
  "tlscert": "/etc/docker/tls/server-cert.pem",
  "tlskey": "/etc/docker/tls/server-key.pem"
}
EOF

Because daemon.json sets hosts, you must remove the -H flag from the systemd unit file to avoid a conflict. Override the unit rather than editing it directly:

mkdir -p /etc/systemd/system/docker.service.d

cat > /etc/systemd/system/docker.service.d/override.conf <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl status docker

Verify that Docker is listening on TCP 2376:

ss -tlnp | grep 2376

Step 5: Opening the Firewall Port

On RHEL 7 with firewalld, open port 2376 for Docker TLS traffic. Restrict the source address to your management network for defence in depth:

# Open port 2376 for all sources (less secure)
sudo firewall-cmd --permanent --add-port=2376/tcp
sudo firewall-cmd --reload

# Better: restrict to a management subnet
sudo firewall-cmd --permanent 
  --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="2376" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

Step 6: Connecting Remotely with TLS

Copy the CA certificate and client key pair to the management workstation. Place them in ~/.docker/ for use by the Docker CLI:

# On the management workstation
mkdir -p ~/.docker
# Copy from Docker host
scp [email protected]:/etc/docker/tls/ca.pem ~/.docker/ca.pem
scp [email protected]:/etc/docker/tls/client-cert.pem ~/.docker/cert.pem
scp [email protected]:/etc/docker/tls/client-key.pem ~/.docker/key.pem
chmod 0600 ~/.docker/key.pem

Connect using explicit flags or environment variables:

# Using explicit flags
docker --tlsverify 
  --tlscacert=~/.docker/ca.pem 
  --tlscert=~/.docker/cert.pem 
  --tlskey=~/.docker/key.pem 
  -H=docker-host.example.com:2376 
  info

# Using environment variables (add to ~/.bashrc for convenience)
export DOCKER_HOST=tcp://docker-host.example.com:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=~/.docker

docker info
docker ps
docker images

Step 7: Verifying and Rotating Certificates

Check certificate validity and expiry dates at any time with OpenSSL:

# Check server certificate details
openssl x509 -in /etc/docker/tls/server-cert.pem -noout -text | 
  grep -E "Subject:|Not After|DNS:|IP:"

# Check client certificate expiry
openssl x509 -in ~/.docker/cert.pem -noout -enddate

# Test TLS handshake from client to server
openssl s_client 
  -connect docker-host.example.com:2376 
  -CAfile ~/.docker/ca.pem 
  -cert ~/.docker/cert.pem 
  -key ~/.docker/key.pem

When certificates approach expiry, generate new ones using the same CA and replace the files without rebuilding the CA:

# Revoke old certificate (optional, requires CRL setup)
# Generate replacement server cert with new expiry date
openssl genrsa -out /etc/docker/tls/server-key-new.pem 4096
# ... follow Steps 2-4 again with the new key
# Restart Docker after replacing the certificate files
sudo systemctl restart docker

Conclusion

Securing the Docker daemon with TLS mutual authentication on RHEL 7 is a straightforward but essential step for any environment where remote Docker management is required. By generating a private CA and requiring both server and client certificates signed by that CA, you ensure that neither eavesdroppers nor unauthorised hosts can interact with your Docker daemon over the network. The combination of daemon.json configuration, systemd service overrides, and firewall restrictions creates a defence-in-depth model appropriate for production RHEL 7 systems. Remember to monitor certificate expiry dates and establish a rotation process before certificates expire to avoid unplanned outages.