Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Use Remote Docker Host With SSH

Being able to run Docker commands on a remote Docker host can be quite handy. However, one needs to do this in a secure manner, and setting up TLS verification is a complex pain. Luckily, this can quickly and easily be done through SSH which this tutorial will show you how to do.

Related Posts

Table of Contents

Setting up An SSH Key

In order for Docker to work over SSH, we need to set up an SSH key, as it will not work with using passwords for server authentication.

It is quite likely that you have already set up an SSH key for connecting to the remote host, but if you haven't, then create a key with:

ssh-keygen

... and add it to the remote host so that we can connect with it.

SSH Key Passphrase

We now have a choice. We can either make sure the key does not have a passphrase, in which case we we don't need to do anything extra. (If you already have a passphrase, you can remove it).

Alternatively, if we want to use a passphrase on the key, we need to add it to our SSH agent, which will prompt us for the passphrase.

ssh-add /path/to/private/key

If your key does have a passphrase, and you don't add it to your SSH agent, you will get an error message (see troubleshooting).

SSH Config

Now we need to add the details to our SSH configuration by editing our ~/.ssh/config file. Below is an example, but be sure to update the Host, HostName, Port, IdentityFile as appropriate to you.

Host docker1.mydomain.com
    HostName docker1.mydomain.com
    User my-remote-user
    Port 2222
    IdentityFile /path/to/private/key
    ControlMaster     auto
    ControlPath       ~/.ssh/control-%C
    ControlPersist    yes
  • The control variables tell SSH to re-use the reuse the connection to the remote server using controlmaster directive [more info]. This was recommended by the Docker docs.
  • The HostName can be the hostname, or the IP address of the remote server.

Docker Configuration Methods

We now have a choice of how we want to tell Docker to connect to the remote host over SSH. There is a quick and dirty method, or a cleaner one that makes use of Docker contexts.

Quick and Dirty Method (Temporary)

If you just need a really quick and easily solution, such as for within a CI/CD pipeline, then you can do the following:

SSH_USER=my-remote-user
SSH_HOST="docker1.mydomain.com:2222"
export DOCKER_HOST=ssh://$SSH_USER@$SSH_HOST
  • The SSH_USER needs to be the name of a user on the remote host that has permissions to access the Docker socket (e.g. they are part of the docker group. This also needs to be the user you need to have set up the SSH key against.
  • I have specified the port in the SSH_HOST just to demonstrate how to do it if you are not using the default SSH port of 22. If you are using the default port, you do not need to specify :22.

Now all of your docker commands will run on the remote host. E.g. try spinning up an ubuntu container:

docker run -it --name="my-ubuntu-instance" ubuntu /bin/bash

If you log into the remote host, you will see that it is running there.

Using Docker Contexts Method

A much cleaner solution is to use a Docker contexts which allow you to easily manage and switch between using different remote hosts.

We can create a new context by doing the following:

CONTEXT_NAME=docker-host1
REMOTE_HOST="ssh://docker-user@host1.example.com:2222"

docker context create \
  --docker host=$REMOTE_HOST \
  --description="My first remote engine" \
  $CONTEXT_NAME

Now we can switch to using that remote engine for our future commands by running:

docker context use my-remote-engine

If we ever want to return to using our default local docker engine, then we would just run:

docker context use default

You are setting the context on the background Docker daemon, so you can think of them as "sticking". Opening up a new terminal will not result in that that terminal defaulting back to the default context, but the one that was last set. This is unlike using the quick and dirty method.

You can list previously created contexts by running docker context ls.

Troubleshooting

If your SSH key has a passphrase, and you didn't add it to your SSH agent, you will get the following error message:

error during connect: Get "http://docker.example.com/v1.24/containers/json": command [ssh -l stuart -- 192.168.2.191 docker system dial-stdio] has exited with exit status 255, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=ssh_askpass: exec(/usr/bin/ssh-askpass): No such file or directory
Permission denied, please try again.
ssh_askpass: exec(/usr/bin/ssh-askpass): No such file or directory
Permission denied, please try again.
ssh_askpass: exec(/usr/bin/ssh-askpass): No such file or directory
stuart@192.168.2.191: Permission denied (publickey,password).

To fix, go back and read the SSH Key Passphrase section for your various choices.

References

Last updated: 25th August 2022
First published: 25th August 2022