SSH is one of the most-used commands in a sysadmin’s toolbox but it’s not commonly seen alongside Docker. Here’s how you can SSH into a running container and why you should think twice before you do.
Should You Use SSH With Docker Containers?
SSH-ing into a Docker container is generally a bad practice which you should avoid. It’s nearly always better to use the
docker exec command to get a shell inside a container.
Docker newcomers can be tempted to use SSH to update files inside a container. Containers are meant to be disposable though so they should be treated as immutable after creation, except for persistent data stored inside volumes. Create a new image and restart your container when you edit source code.
Aside from the multi-step configuration process, installing SSH in a Docker image adds several dependency packages and exposes another potential attack vector. On a system with several active containers, you’ll be running multiple independent SSH processes and will have to remember the correct port for each container.
Instead of adding SSH to individual containers, install it once on the physical host that’s running Docker. Use SSH to connect to your host, then run
docker exec -it my-container bash to access individual containers.
docker exec is the preferred approach, there are still scenarios where SSH might be useful. You could introduce it as a stopgap measure to integrate with legacy deployment systems. It may also be used by some IDEs and build tools to provide live reload capabilities during development.
Installing the SSH Server in a Docker Container
Most popular Docker base images are kept intentionally streamlined. You’ll need to add the OpenSSH server yourself, even on images derived from popular operating system distriubtions.
Here’s an example
Dockerfile for a Debian-based image:
RUN apt-get update && apt-get install -y openssh-server RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config ENTRYPOINT service ssh start && bash
The SSH configuration is modified so you can login as
root, the default user in a Docker container. For greater security, setup a dedicated user account instead:
RUN useradd -m -s /bin/bash sshuser
This creates a new user called
sshuser with a home directory (
-s switch sets the user’s default login shell to Bash.
The use of
ENTRYPOINT ensures the SSH service always starts when the container does. Execution is then handed off to Bash as the container’s foreground process. You could replace this with your application’s binary.
Next you need to setup an authentication system. You could assign a password to your
sshuser account and login with that:
RUN echo "sshuser:Changeme" | changepasswd
A more secure way is to set up SSH key authentication. You’ll need to create a key pair on your client machine, then copy the public part into the container. This way the SSH daemon can verify your machine’s identity when you connect.
Dockerfile to setup the
.ssh configuration folder for your user. Copy in a public key from your working directory, either with a
docker cp command or a
COPY instruction in the
Dockerfile. In the latter case, the key would be baked into the image, visible to anyone with access.
COPY id_rsa.pub /home/sshuser/.ssh/authorized_keys RUN chown -R sshuser:sshuser /home/sshuser/.ssh RUN chmod 600 /home/sshuser/.ssh/authorized_keys
This sequence of commands creates SSH’s
authorized_keys file with the
id_rsa.pub public key in your working directory. The filesystem permissions are adjusted to match SSH’s requirements.
Connecting to the Container
Now you’re ready to connect to your container. Run the container with port 22 bound to the host:
docker run -p 22:22 my-image:latest
ssh firstname.lastname@example.org will give you a shell inside your container.
You can skip binding the port if you’ll be connecting from the machine that’s hosting the Docker container. Use
docker inspect to get your container’s IP address, then pass it to the SSH connection command.
docker inspect <id-or-name> | grep 'IPAddress' | head -n 1
Use the SSH client on your machine to connect to the container:
ssh email@example.com # OR ssh firstname.lastname@example.org
You’ll need to use an alternative port if you’re running a separate SSH server on the host or you’ve got multiple containers that need port 22. Here’s how to initiate a connection when SSH is bound to port 2220:
docker run -p 22:2220 my-image:latest ssh email@example.com -p 2220
Setting Up Container Shortcuts With SSH Config
You can manipulate your SSH config file to simplify connections to individual containers. Edit
~/.ssh/config to define shorthand hosts with preconfigured ports:
Host my-container HostName 172.17.0.1 Port 2220 User sshuser
Now you can run
ssh my-container to drop straight into your container. This makes it easier to juggle multiple connections without remembering container IPs and ports.
The Dockssh project takes this a step further by providing another daemon that lets you run
ssh firstname.lastname@example.org, without any manual SSH configuration. You don’t need to install an SSH server in your containers; Dockssh automatically proxies SSH connections and runs the correct
docker exec command instead.
You must first install Redis to store Dockssh’s configuration data:
sudo apt install redis
Next, define the containers you want to expose by adding a Redis record with the container’s name and a password for SSH connections:
redis-cli set dockssh:my-container:pass "container-password-here"
Then download Dockssh:
sudo curl https://github.com/alash3al/dockssh/releases/download/v1.1.0/dockssh_linux_amd64 -O /usr/local/bin/dockssh sudo chmod +x /usr/local/bin/dockssh sudo ufw allow 22022 # Start DockSSH server dockssh
Now you can connect to your container:
ssh email@example.com -p 22022
Dockssh listens on port 22022 by default. The firewall is opened to allow incoming connections using the port.
You’ll be prompted for the container’s password when you connect. This was set as
container-password-here in our Redis record above.
Using Dockssh makes it easy to SSH into a large number of Docker containers. This approach is ideal when you regularly connect to your containers from a remote host as it streamlines the two-step “SSH then
docker exec” sequence into a single memorable command.
Register Dockssh as a system service for long-term use:
sudo nano /etc/systemd/system/dockssh.service
[Unit] Description=Dockssh service After=network.target [Service] type=simple Restart=always RestartSec=1 User=root ExecStart=/usr/local/bin/dockssh [Install] WantedBy=multi-user.target
Enable the service using
sudo systemctl enable dockssh.service sudo systemctl start dockssh
Dockssh will now start automatically when your system boots.
Combining SSH with Docker containers is broadly considered to be an anti-pattern yet it still has its uses in development, testing, and legacy environments. When there’s no alternative you can add the SSH server to your container, copy in a public key, and connect via the container’s IP or a host port binding.
System admins who want to remotely manage large numbers of Docker containers can try out Dockssh. It lets you run familiar
ssh commands via a seamless behind-the-scenes mapping to
docker exec, giving you the best of both worlds using unmodified images.