← cd ../blog

Connect to a Docker Container on a Remote Server over SSH

Enable SSH tunneling from a remote Docker container and connect directly with VS Code.

Contents

The problem

↑ back to contents ↑

I work extensively with machine learning and deep learning algorithms written in Python. Because of the various frameworks available (such as PyTorch,TensorFlow,RAPIDS,TPOT …) I useDocker a lot, usually along with a Jupyter-enabled image (see my other article if you are interested) which allows me to do all the prototyping I need in a fast and clean way. It is common to put such containers on a remote server with the required hardware (mostly GPUs) rather than developing on the local machine.

Sometimes, though, JupyterLab is not enough, and some good oldVSCodecoding is the best thing I can hope for, especially when dealing with Python package development, which I will then have to test with Jupyter. And here we encounter our problem:

VS Code does not allow you to connect to a remote container on a remote server. It only allows you to connect to a remote machine or to local containers. If we attach VS Code to our remote server:VSCode Attach via SHHand then try to attach VS Code to a running container on the remote server:VSCode Attach via Dockerwe get the following error:VSCode Error

The best solution, in this case, is to enable SSH tunneling directly from the Docker container, allowing VS Code to connect seamlessly to the container as if it were a standalone remote machine:

SSH Tunnel

Mounting a Docker container

↑ back to contents ↑

Let’s use the Jupyter-enabled image we mentioned earlier as the base image for our container. After pulling it from Docker Hub:

docker pull davidelanz/jupyter

we can mount it exposing the container’s Jupyter port 8888 on, for example, my.server.local:2345 using the option --publish <SERVER-PORT>:<CONTAINER_PORT> (or -p), which publishes a container’s port (8888) to the specified server port (2345):

docker run\
    -p 2345:8888 \
    --name my-jupyter-workspace \
    davidelanz/jupyter

Now we can access Jupyter at my.server.local:2345, but can’t attach VSCode or connect via SSH to the my-jupyter-workspace container.

Mounting a Docker Container with SSH enabled

↑ back to contents ↑

In order to enable the SSH tunnel, we first have to expose the container’s SSH port 22 to a server port. In our case, we will use my.server.local:2344:

docker run\
    -p 2344:22 \
    -p 2345:8888 \
    --name my-jupyter-workspace \
    davidelanz/jupyter

Now, we have to enter the container. First, we enter the server via SSH:

ssh my.server.local

Then, we attach to the container with:

docker container exec -it my-jupyter-workspace /bin/bash

Now we are finally inside our running container, and we can install an SSH server directly in it:

apt-get update && \
    apt-get upgrade -y && \
    apt-get -y install openssh-server && \
    mkdir -p /var/run/sshd && \
    service ssh start

If it has not already been set, we must change the root password to log in during the SSH authentication process:

echo "root:<NEW_PASSWORD>"|chpasswd

Now we are able to start the SSH server process via service ssh restart, but we still can’t log in. In fact, we have to authorize SSH connections with the root account. To do that, we need to go to /etc/ssh/sshd_config and modify the optionPermitRootLogin from prohibit-password to yes. Moreover, if it is not commented, comment the UsePam yes line. We can open the text file with GNU nano:

apt-get install nano && nano /etc/ssh/sshd_config
BeforeAfter
# PermitRootLogin prohibit-passwordPermitRootLogin yes
UsePAM yes#UsePAM yes

Then we just need to restart the SSH process:

service ssh restart

Connect via command line

↑ back to contents ↑

Now we can connect from the command line to port 2344 on the Docker server, using the remote server’s address (my.address.local) and specifying the SSH port with -p <port>:

ssh -p 2344 my.address.local

Connect via VSCode

↑ back to contents ↑

We can now add my.address.local:2344 to the SSH configuration file:

Host my-remote-container
  HostName my.address.local
  User root
  Port 2344
  ForwardAgent yes

and we can use the VSCode Remote Explorertool to attach VSCode directly to the container running on the remote server.