Before getting started, if you want to inspect or execute commands in a running Docker container, you should read our other article on how to run a Bash shell in Docker.
Writing a Dockerfile for an SSH server with password-based authentication
To create a containerized SSH server running in Ubuntu with minimal configuration to which you can connect using a username/password pair, you can use the following Dockerfile:
FROM ubuntu
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo "root:password" | chpasswd
RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
CMD ["/usr/sbin/sshd", "-D"]
Run in Warp
Where:
- FROM ubuntu will set the base image as the latest available version of Ubuntu.
- RUN apt-get update && apt-get install -y openssh-server will update the package index and install the openssh-server package used to run the SSH server.
- RUN mkdir /var/run/sshd will create the /var/run/sshd directory used by the SSH server to store temporary runtime data.
- RUN echo "root:mypassword" | chpasswd will set the password of the root user to mypassword.
- RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config will update the SSH configuration file to allow root login.
- CMD ["/usr/sbin/sshd", "-D"] will launch the SSH server as a background task when the container starts.
Writing a Dockerfile for an SSH server with SSH keys authentication
The second way to connect to an SSH server is to use a pair of public/private keys.
Generating a pair of SSH keys
To generate a new pair of SSH keys, you can use the ssh-keygen command as follows:
$ ssh-keygen -b 4096 -t rsa -f dockerkey
Run in Warp
Where:
- -b 4096 specifies a key length of 4096 bits.
- -t rsa specifies a RSA key type.
- -f dockerkey specifies dockerkey as the name of the key file.
Upon execution, this command will generate two files: dockerkey containing the private key and dockerkey.pub containing the public key.
Writing the Dockerfile
To create a containerized SSH server running in Ubuntu with minimal configuration to which you can connect using a pair of SSH keys, you can use the following Dockerfile:
FROM ubuntu:latest
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
COPY ./dockerkey.pub /root/.ssh/authorized_keys
CMD ["/usr/sbin/sshd", "-D"]
Run in Warp
Where:
- COPY ./dockerkey.pub /root/.ssh/authorized_keys will copy the public key generated using the ssh-keygen command from the local machine into the /root/.ssh/authorized_keys[.inline-code] directory of the image.
Building and running the SSH container
To build the Dockerfile into a runnable Docker image, you can use the following docker build command:
$ docker build . -t ssh-host
Run in Warp
Where:
- . specifies that the Dockerfile is located in the current directory.
- -t ssh-host specifies the name of the Docker image.
Once built, you can launch a new container from this image using the following docker run command:
$ docker run -p 2222:22 ssh-host
Run in Warp
Where:
- -p 2222:22 is used to map the port 2222 of the host to the SSH port 22 of the container.
Connecting to the SSH container
Connecting with a username/password pair
To connect to the SSH server running in the container using a username/password pair, you can use the ssh command as follows:
$ ssh <username>@<host> -p <port>
Run in Warp
Where:
- username is the username defined in the Dockerfile.
- host is the IP or address of the machine the container is running on.
- port is the port on the host system defined in the docker run command.
Once executed, you will be prompted to enter the password.
For example, the following command will connect to the SSH server running on your local machine through the port 2222 with the root user:
$ ssh root@localhost -p 2222
Run in Warp
Connecting with a private key file
To connect to the SSH server running in the container using a private key file, you can use the ssh command with the -i flag as follows:
$ ssh -i <key> <username>@<host> -p <port>
Run in Warp
Where:
- key is the path to the private key file.
- username is the username defined in the Dockerfile.
- host is the IP or address of the machine the container is running on.
- port is the port on the host system defined in the docker run command.
For example, the following command will connect to the SSH server running on your local machine through the port 2222 with the root user account using the dockerkey private key file:
$ ssh -i dockerkey root@localhost -p 2222
Run in Warp
Easily retrieve this syntax using the Warp AI feature
If you’re using Warp as your terminal, you can easily retrieve this syntax using the Warp AI feature:
Entering docker image with ssh and keys in the AI question input will prompt a human-readable step by step guide including code snippets.
Handling terminal signals gracefully
As Linux tends to disregard the signals sent to the primary process, thus preventing it from being manually stopped using for instance CTRL + C, you have to manually handle these signals by wrapping the main process in a script as follows:
#!/bin/bash
/usr/sbin/sshd -D &
pid="$!"
trap "kill -SIGTERM $pid" SIGINT SIGTERM
wait $pid
Run in Warp
Where:
- /usr/sbin/sshd -D & runs the SSH server as a background task.
- pid="$!" stores the process ID of the server into the pid variable.
- trap is used to catch and handle SIGINT and SIGTERM signals to kill the server.
- wait $pid prevents the container from terminating while the server is still running.
In the server's Dockerfile, you can then replace this instruction:
CMD ["/usr/sbin/sshd", "-D"]
Run in Warp
By the following one:
COPY ./init.sh /init.sh
RUN chmod +x /init.sh
CMD ["/init.sh"]
Run in Warp
Where the new lines:
- COPY ./init.sh /init.sh will copy the script into the container.
- RUN chmod +x /init.sh will make the script executable.
- CMD will set the script as the container's startup command.
Securing the SSH server configuration
When working with OpenSSH, you can mitigate potential exposure and enhance overall security measures by creating a configuration file named sshd_config containing the following properties:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
Run in Warp
Where:
- PermitRootLogin no will disable root login via SSH.
- PasswordAuthentication no will disable password-based authentication, encouraging the use of more secure authentication methods such as SSH keys.
- KbdInteractiveAuthentication no will disable keyboard-interactive authentication, which typically involves mechanisms like challenge-response authentication.
- AllowAgentForwarding no will prevent the SSH client from using the SSH keys stored on the local host to connect to other remote servers.
- AllowTcpForwarding no will prevent TCP traffic from being forwarded over the SSH connection.
- X11Forwarding no will prevent GUI applications running on the remote server to display on the local machine
- AcceptEnv LANG LC_* specifies that the only accepted environment variables from the client are related to language and locale settings.
- Subsystem sftp /usr/lib/openssh/sftp-server will define the subsystem for handling SFTP requests.
And add the following instruction to your Dockerfile:
COPY ./sshd_config /etc/ssh/sshd_config
Run in Warp
Which will copy the sshd_config file into the /etc/ssh/ directory of the image at build time.
Forwarding the SSH agent to a Docker container
ssh-agent is a command-line tool used to simplify the management of SSH keys by keeping them encrypted in memory and automatically providing them to SSH when needed.
This allows users to avoid repeatedly typing passphrases when using SSH keys, and in the context of Docker, to avoid copying SSH keys into containers to connect to third-party services like Git.
Creating a containerized SSH client
To create a containerized SSH client that allows you to connect to an SSH server from within a Docker container, you can use the following Dockerfile:
FROM ubuntu
RUN apt-get update && apt-get install -y openssh-client
CMD ["sleep", "infinity"]
Run in Warp
Where:
- FROM ubuntu will set the base image as the latest available version of Ubuntu.
- RUN apt-get update && apt-get install -y openssh-client will update the package index and install the OpenSSH client.
- CMD ["sleep", "infinity"] will make the container sleep indefinitely, keeping it running in the background without executing any other commands.
And build the Dockerfile into a Docker image named ssh-client using the following docker build command:
$ docker build . -t ssh-client
Run in Warp
Setting up the SSH agent for a standard Docker installation
ssh-agent works by creating a socket file where tools can proxy requests to communicate commands and authenticate, so to forward the agent into a container you basically have to mount this socket into the container and set an environment variable with the path to the socket. This will make all requests inside the container for ssh-agent essentially be forwarded to the host session.
In a standard CLI installation of Docker you can create a new ssh-agent session by running:
To start the ssh-agent tool in the background and set the value of the SSH_AUTH_SOCK environment variable to the path of the SSH agent socket, you can use the following command:
$ eval $(ssh-agent)
Run in Warp
Next, you can add SSH keys to the SSH agent session using the ssh-add command as follows:
$ ssh-add <path>
Run in Warp
Where:
- path is the relative or absolute path to the SSH key file.
Finally, you can run the ssh-client container in interactive mode using the following docker run command:
$ docker run -it -v $SSH_AUTH_SOCK:$SSH_AUTH_SOCK -e SSH_AUTH_SOCK=$SSH_AUTH_SOCK ssh-client bash
Run in Warp
Where:
- The -v flag is used to mount the SSH agent socket from the host into the container, whose location is stored in the SSH_AUTH_SOCK environment variable.
- The -e flag is used to set the SSH_AUTH_SOCK environment variable so that the SSH client inside the container knows where to find the SSH agent socket.
Written by
Gabriel Manricks
Chief Architect, ClearX
Filed Under
Related Articles
Override the Container Entrypoint With docker run
Learn how to override and customize the entrypoint of a Docker container using the docker run command.
The Dockerfile ARG Instruction
Learn how to define and set build-time variables for Docker images using the ARG instruction and the --build-arg flag.
Start a Docker Container
Learn how to start a new Docker container from an image in both the foreground and the background using the docker-run command.
Stop All Docker Containers
How to gracefully shutdown running containers and forcefully kill unresponsive containers with signals in Docker using the docker-stop and docker-kill commands.
Use An .env File In Docker
Learn how to write and use .env files in Docker to populate the environment of containers on startup.
Launch MySQL Using Docker Compose
Learn how to launch a MySQL container in Docker Compose.
Execute in a Docker Container
Learn how to execute one or multiple commands in a Docker container using the docker exec command.
Expose Docker Container Ports
Learn how to publish and expose Docker container ports using the docker run command and Dockerfiles.
Restart Containers In Docker Compose
Learn how to restart and rebuild one or more containers in Docker Compose.
Output Logs in Docker Compose
Learn how to output, monitor, customize and filter the logs of the containers related to one or more services in Docker Compose
Rename A Docker Image
Learn how to rename Docker images locally and remotely using the docker tag command.
Understand healthcheck in Docker Compose
Learn how to check if a service is healthy in Docker Compose using the healthcheck property.