Just sometimes, it’s useful to SSH into a Docker Container. While docker exec or docker attach are usually sufficient to run commands in a container, sometimes you specifically need SSH. For example, to connect directly from a remote machine or when an application needs to run commands on your container. Most Docker images don’t come with the SSHd service installed so it is not possible to SSH to them. This post demonstrates how to install and run the SSHd service to an existing image so that you can connect to it.
Aug 27, 2021 To SSH into Docker containers with docker run: 1. Open a terminal on your local machine. Run the docker run command providing: The name of the container to run ( ubuntucontainerssh) The i flag indicating you’d like to open an interactive SSH session to the container. When we know why we need ssh on docker, let’s make it happen. Install ssh server on docker. There are two things which we need to configure: host and container. First, we’ll take care of the container. We’ll use php:7.3-apache image. It does not have an ssh server installed, so we need to add it. We create Dockerfile.
There are several reasons why you may not want or need to enable SSH on a Docker container. First, you often don’t need to run SSHd in Docker to do stuff you’d normally use SSH for. You can access logs, restart services and browse a container file system with docker attach or docker exec.
Second, it goes against the philosophy of Docker containers. A container should do exactly one thing. An nginx or HTTPd container serves web resources, a Redis or Mongo container provides NoSQL databases. A complex application is composed from several single-purpose containers orchestrated together. A container that that runs nginx and SSHd does two things. It’s not wrong but it’s just not the Docker way.
Finally, it may be a security risk. Exposing an additional means of accessing a container certainly increases the attack surface. You may also need to deal with password / key management.
That said, if you really want to SSH into a Docker Container, it’s not too hard.
In this example, I’ll demonstrate how to enable SSH for an nginx container but the same technique applies to other container types. So let’s start with the default nginx image:
Then we need to install the SSHd service to the container:
We want a specific user account for the SSH connection. We’ll allow access to this account and no other.
This creates an account called sshuser which belongs to the sshgroup. It creates a user directory in /home/sshuser and sets the user’s shell to Bash.
Next need to decide how to authenticate the user. It’s possible to allow username / password authentication but this is inadvisable. It bakes the password into the image definition and is generally less secure.
This sets a password of Pa$$word on our new account.
A better option is to use an SSH key. Plenty of good resources exist to help you do this. So let’s assume you’ve created a public key called id_rsa.pub and the private key called id_rsa. Copy the public key into your container in a file called ~/.ssh/authorized_keys.
Be sure to keep the private key private! Anyone with access to the private key will be able to access the container so this should not be shared or copied into the container.
This last step is a little fiddly. We can use CMD instruction to run a command when the container starts. An image can include only one CMD instruction but it’s already used to start nginx. The simple solution is to use && to run multiple commands. First we start the SSH service, then we run nginx:
We now have a container image that will allow SSH access. So let’s start it up and try it. I like using docker-compose to do my build, config and startup with a single simple command. My docker-compose.yml file looks like this:
I can run it like this:
And then I can SSH into a docker container like this:
That is, connect to localhost as the sshuser and use the id_rsa private key to authenticate. We specify port 1022 because that’s the port on our machine (localhost, the Docker host) that forwards to port 22 on the container.
After running this command we have a secure shell (Bash) on the nginx Docker container.
The full source code for this example is in GitHub.
We recommend using the Visual Studio Code Remote-SSH extension to connect to a remote machine running Docker engine, but it also possible to connect to the remote Docker engine directly, using SSH tunneling.
Use ssh-keygen or similar to get and configure a public/private key pair for SSH authentication. Password authentication is not supported by Docker and not possible with a
DOCKER_HOST-based configuration. If a key pair has already been set up, it can be used.
ssh-agent on the local system with the private key file produced above.
Windows (OpenSSH): The latest version(s) of Windows 10 include OpenSSH by default. There is a Windows service,
ssh-agent that is disabled by default, and needs to be re-enabled and set to automatic start. From an admin PowerShell prompt, run
Set-Service ssh-agent -StartupType 'Automatic' and
Start-Service ssh-agent. Then, do
Windows (Pageant): You can use Pageant instead of OpenSSH, in which case it is necessary to set the environment variable
SSH_AUTH_SOCK=pageant. Making that a user or system environment variable will be easiest.
ssh-agent is present by default. Do
ssh-add <keyfile>. Ubuntu was tested; you might have different results on other distributions.
ssh-agent is present by default, but
ssh-add does not persist across logins. Do
ssh-add <keyfile>. We recommend configuring VS Code to run this command on terminal startup with
terminal.integrated.shellArgs.osx or otherwise configuring a startup script. You can also manually run that command each login.
Verify that your identity is available to the agent with
ssh-add -l. It should list one or more identities that look something like
2048 SHA256:abcdefghijk somethingsomething (RSA). If it does not list any identity, you will not be able to connect. Also, it needs to have the right identity. The Docker CLI working does not mean that the Explorer window will work. The Explorer window uses dockerode (which in turn uses ssh2), whereas the Docker CLI uses the
ssh command, and benefits from an automatically inferred configuration.
Create a Docker context that points to the remote machine running Docker. Use
ssh://[email protected]:port as the Docker endpoint (replace 'host' with your remote machine name, or the remote machine IP address). Issue the following command from terminal window:
Always include the user name in the Docker endpoint address, even if it is the same as the local user name. If you omit the port, it defaults to 22.
Use the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)) to issue the Docker Context: Use command to activate the Docker context pointing to the remote machine. This command causes both VS Code and Docker CLI to use the remote machine context.
It is recommended to change the refresh rate to something longer than the default with the
docker.explorerRefreshInterval setting. The connection over SSH is slow, and it can result in trying to refresh again before the previous refresh even finished. We recommend at least 3000 ms.
The 'host' part in the Docker endpoint string (
ssh://[email protected]:port) must be either a globally-resolvable DNS machine name, or an IP address. Docker extension will not be able to use host aliases defined in the SSH configuration file.
Make sure the remote machine host key is already memorized in the known_hosts file. The simplest way to ensure this is to connect to the machine via
ssh client program (run
ssh [email protected]:port from the command line). Upon first-time connection, the
ssh program will display the host key and let you approve it, updating the
known_hosts file automatically.
There is an issue with ssh-keygen utility that comes with Windows 10 build 1909 and older that prevents it from working properly with newer SSH daemons (for example, the one that comes with Ubuntu 20.04 LTS and newer). The workaround is to use ECDSA-type key, not RSA-type key, for the SSH connection. You can generate an ECDSA SSH key and add it to SSH agent with following commands:
Windows 10 build 1909 and older are affected by an issue that prevents SSH from getting to your identities after Windows OS update. The workaround is to add a dummy service entry to system configuration. Run the following from administrative PowerShell window: