How to SSH into a Docker container

Whether you’re new to DevOps or have years of experience, you’re probably familiar with Docker, which is one of the most popular and reliable solutions for containerizing your applications. In this article, we’ll discuss how to SSH into Docker containers to read logs, debug errors, or just make sure they’re operating as expected.

Docker containers are self-contained environments that have all the files and dependencies required for an application to function. Containers are isolated from each other and provide a fresh slate to work with, though containers can also be set up to talk to each other. When you inspect or connect to a Docker container’s shell, you can debug logs, ensure the container is running as expected, execute arbitrary commands, and verify it’s reachable by other containers. This is easy to accomplish if you’re trying to inspect a container that’s running on your local machine, but becomes more cumbersome if you want to debug a remote container.

In this article, you’ll learn why and how you can access the shell for local containers. You’ll also learn how you can use Tailscale SSH to access a remote Docker container without the complexity of key management or bastions.

Why you need to inspect your containers

As a developer, you need to be able to inspect your containers to ensure that they’re running as expected and to debug any issues that might arise. This is a vital part of developing with Docker.

Following are the top three reasons you might want to have shell access to your Docker containers.

Debug logs

Logs are one of the most important data points needed when troubleshooting an application. Opening a shell into a container and fetching the application system logs helps you locate an instance where the application was faulty, or ensures that it was running as expected.

Execute commands

You may want to execute commands. For example, you may want to install dependencies or run custom code in your development environment — whether in virtual environments such as GitHub Codespaces, or in your local container — to keep the commands isolated from your primary environment.

Verify the container is reachable by other containers

Testing connectivity between containers in a network is important because it helps you make sure your services are interacting as required. For example, if you want to make sure your database is talking to your backend service when there’s an error, you can test the connectivity by accessing the container directly and then pinging other containers.

Opening a shell into a container

Now that you know why you would want to peek under the hood of a Docker container, let’s take a look at how you can actually do it. There are a few different approaches, but the most common is to use the docker exec command, which doesn’t require you to have an entry point.

The docker exec command lets you execute any commands you need to run inside the container, verify that the container is reachable by other containers, or do any of the other actions mentioned previously.

In order to use docker exec, you need to find the ID or the name of the container you want to inspect.

The docker ps or docker container ls command will list all the running containers, and you can obtain the ID or name of the container you wish to inspect:

hrittik@tail2:~$ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED              STATUS              PORTS                     NAMES
4277ba8ceb27   memcached   "docker-entrypoint.s…"   38 seconds ago       Up 37 seconds       11211/tcp                 mystifying_gauss
add801357cf7   neo4j       "tini -g -- /startup…"   41 seconds ago       Up 40 seconds       7473-7474/tcp, 7687/tcp   lucid_rhodes
caac7023ec74   nginx       "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp                    gallant_nobel
ada16dd695e5   mongo       "docker-entrypoint.s…"   About a minute ago   Up About a minute   27017/tcp                 vibrant_einstein
e6166f6bdb33   redis       "docker-entrypoint.s…"   3 minutes ago        Up 3 minutes        6379/tcp                  busy_driscoll

Once you’ve obtained the name or ID, you can use the docker exec command to run whatever commands you may want to:

docker exec -it <container_id> /bin/bash

You can read more about what exec is doing in the official Docker documentation — but in short, you’re telling Docker that you would like to open an interactive shell on <container_id> and run /bin/bash, which will open a bash session.

You can then use the session to install or access whatever you need to.

The specific commands you need to give to the Docker container will vary depending on the operating system that the Docker container is running.

SSH into a container using Tailscale

docker exec is very powerful for working locally, but what if you want to access your containers remotely? You could set up your containers to accept SSH connections, but then you need to worry about managing SSH keys, rotating credentials, and the usual headaches of running an SSH server.

Tailscale simplifies the entire process, allowing you to establish SSH connections between devices in your tailnet, as authorized by your access controls, without managing SSH keys. Tailscale authenticates your SSH connection using WireGuard.

Tailscale is a zero-config VPN that you can install on your devices to provide secure access to your resources. This means you can also install it on a Docker container, and Tailscale makes it easy to access your host and your containers over the network. You can even transfer files, such as your logs, between machines — all through a decentralized, open-source WireGuard protocol via point-to-point connections.

Install Tailscale

Tailscale supports multiple operating systems, and on Linux, the process is streamlined to run and install the software with one command on a host.

Before you begin, make sure you have curl installed. If you don’t, run the following command to add curl to any Debian container:

apt-get update; apt-get install curl -y

After curl is installed, install Tailscale using this command:

curl -fsSL https://tailscale.com/install.sh | sh

Tailscale supports Docker containers on a range of operating systems besides Linux:

Tailscale OS support

You can learn more about other installation methods on Tailscale’s download page.

Run and authenticate

Start the Tailscale daemon in userspace networking mode:

tailscaled --tun=userspace-networking --socks5-server=localhost:1055 &

This will connect to your network, but not act as a network device for your computer.

After your instance is installed on your server, you need to run it using tailscale up. As this is your first startup, you will receive the following prompt:

hrittik@tail3:~$ tailscale up
To authenticate, visit:
        https://login.tailscale.com/a/ff83ba3909f6

You will receive a prompt to authenticate at a specific URL; visit the URL to authenticate your device.

Setup SSH server using Tailscale

Once you’ve logged in to Tailscale, you should be able to see your device (in this case, a Docker machine) in the admin console:

Tailscale admin console

The portal lists every machine that has ever been registered under your account, even those that aren’t connected or where Tailscale needs to be updated. Additionally, this is where you can find your devices’ IP addresses and whether they are running an SSH server.

To set up your Docker container to act as a Tailscale SSH server, restart Tailscale in the container with the -ssh flag enabled:

tailscale up –ssh

Connect to the SSH server using Tailscale

Now you can connect to the SSH server using Tailscale SSH, without the need to configure authorization keys. To begin, use tailscale ip to find the Tailscale IP for the SSH server in your Docker container:

hrittik@tail2:~$ tailscale ip
100.95.96.66
fd7a:115c:a1e0:ab12:4843:cd96:625f:6042

If your account name is “username” and your Tailscale IP address for the Docker container is “100.95.96.66”, you can SSH into the container from any other device on the same Tailscale network with the following command:

ssh username@100.95.96.66

Note, however, that using SSH to connect machines owned by different users on the same may require changes to your ACLs.

Introducing MagicDNS

If you need to, you can find the Tailscale IPs for your other devices on the admin console; however, remembering all the IPs needed to do so can be tedious and time-consuming. This is where MagicDNS comes in.

MagicDNS is a feature provided by Tailscale that makes it easier for you to connect to other devices on your tailnet by automatically registering a human-readable DNS name for each device. When you have MagicDNS enabled, you can reach a device using its shortname instead of its Tailscale IP address.

To enable MagicDNS, navigate to the DNS page in the admin console, enter a DNS provider or choose from one of the pre-existing presets, and click Enable MagicDNS:

Tailscale DNS page

Now you can access Docker containers without caring about any underlying access infrastructure, keys, or networks.

If desired, you can configure the SSH server with an ACL tag, which provides more granular control, like key exchange duration and access controls.

Wrapping Up

As a developer, you need to be able to inspect your containers to ensure that they’re running as expected and to debug any issues that might arise — this is a vital part of developing with Docker.

In this article, you’ve learned how Tailscale can help you easily SSH into servers. If you have more than one server, the features that Tailscale offers — like providing secure, lower-latency connections with automatic key verification, file transfers, and the ability to switch networks without losing your work — are incredibly helpful while SSHing.

Get started with Tailscale today.

Frequently Asked Questions

Following are a few common questions related to SSH and Docker containers.

Can you SSH into the same Docker container from multiple devices simultaneously?

You can, because multiple SSH connections are possible by default and won’t cause an issue as long as you have sufficient bandwidth.

Does Tailscale log your access when you SSH into a Docker container?

You can optionally choose to record your SSH sessions by configuring Tailscale SSH. The logs will be stored at /var/lib/tailscale/ssh-sessions.

Are there more ways to access Docker containers?

You can always attach to the container using docker attach, where you need a defined entry point. Or you can install an SSH server inside a container; however, this unnecessarily bloats it and might not work on all containers.