Cómo entrar por SSH en un contenedor Docker

Casi nunca hace falta. Ejecuta docker exec -it web sh en la máquina donde corre el contenedor, o ssh -t user@server docker exec -it web sh desde otro sitio. Un contenedor normalmente no tiene servidor SSH, y añadir uno rara vez compensa. Para controlar un Docker remoto desde tu portátil, usa DOCKER_HOST=ssh://user@server.

Actualizada el . Las opciones de docker exec, los mensajes de error, el shell auxiliar y el Dockerfile con sshd se ejecutaron con Docker en Linux. Los errores de exec, el contenedor auxiliar y docker cp se volvieron a comprobar con Docker 29.5.

Obtener un shell: docker exec

docker ps
docker exec -it web sh

-i mantiene abierta la entrada y -t te da un terminal. Cambia web por el nombre que muestra docker ps. Usa bash si la imagen lo tiene. Opciones útiles:

docker exec -it -u root web sh              # as another user
docker exec -it -w /app web sh              # in another folder
docker exec -e DEBUG=1 web env              # with an extra variable
docker compose exec web sh                  # with Compose: no -it needed

Con Podman, los mismos comandos funcionan escribiendo podman en lugar de docker.

En un servidor remoto

Entra por SSH en el host, no en el contenedor. Para hacerlo en un solo paso, pide un terminal con -t:

ssh -t user@server docker exec -it web sh

Sin -t, las versiones recientes de Docker se detienen con cannot attach stdin to a TTY-enabled container because stdin is not a terminal, y las antiguas con the input device is not a TTY. Si vas a ejecutar más de un comando, lo más sencillo es entrar antes en el servidor.

Un nombre corto para el servidor ahorra escribir: consulta ejemplos del archivo de configuración de SSH.

Errores comunes

No hay shell en la imagen:

OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found in $PATH

Prueba con sh. Las imágenes Alpine tienen sh y no tienen bash. Si sh da el mismo error, la imagen no tiene ningún shell, algo habitual en imágenes mínimas. Inicia un contenedor auxiliar que comparta su vista de procesos y de red:

docker run --rm -it --pid=container:web --network=container:web alpine sh

Desde ahí, ps muestra los procesos del otro contenedor.

Contenedor detenido:

Error response from daemon: container 962d0cc0707e... is not running

No se puede hacer exec en un contenedor detenido. Lee por qué se detuvo y saca los archivos que necesites. docker cp también funciona con un contenedor detenido:

docker logs web
docker cp web:/etc/hostname .

Controlar un Docker remoto desde tu portátil

El cliente de Docker puede hablar con un daemon remoto a través de SSH, de modo que docker ps y docker exec en tu portátil actúan sobre el servidor. No se abre ningún puerto de Docker, solo se usa SSH:

DOCKER_HOST=ssh://user@server docker ps
DOCKER_HOST=ssh://user@server docker exec -it web sh

Para dejarlo fijo, crea un contexto:

docker context create --docker host=ssh://user@server remote
docker --context remote ps

Necesitas un acceso con clave que funcione al servidor, un cliente de Docker en tu portátil y un usuario del servidor con permiso para usar el socket de Docker. Ten en cuenta que el acceso al daemon de Docker equivale casi a ser root en esa máquina: la documentación de Docker dice que solo los usuarios de confianza deben tenerlo.

Cada comando abre una conexión nueva, así que Docker sugiere reutilizar una en ~/.ssh/config. Mira la multiplexación SSH.

Cuándo tiene sentido un sshd en un contenedor

Solo cuando SSH es el objetivo en sí:

  • Un servidor de pruebas para clientes SSH, scripts o Ansible.
  • Una herramienta que solo puede llegar a las cosas por SSH o SFTP, y que no puedes cambiar.
  • Un jump host o un buzón SFTP que ejecutas a propósito como contenedor.

Para entrar a depurar algo, añade un servicio, una clave y un puerto abierto, y docker exec ya hace ese trabajo. Si de verdad lo necesitas, esto arranca y permite entrar con una clave:

FROM debian:13-slim
RUN apt-get update && apt-get install -y --no-install-recommends openssh-server \
 && rm -f /etc/ssh/ssh_host_* \
 && useradd -m -s /bin/bash app && mkdir -p /run/sshd \
 && install -d -m 700 -o app -g app /home/app/.ssh
COPY authorized_keys /home/app/.ssh/authorized_keys
RUN chown app:app /home/app/.ssh/authorized_keys && chmod 600 /home/app/.ssh/authorized_keys
CMD ["sh", "-c", "ssh-keygen -A && exec /usr/sbin/sshd -D -e -o PasswordAuthentication=no"]
docker build -t sshd-demo .
docker run -d --name sshd-demo -p 127.0.0.1:2222:22 sshd-demo
ssh -p 2222 app@127.0.0.1

Aquí importan tres detalles:

  • Las claves del host se crean al arrancar, no en la imagen. Si no, todos los contenedores de la imagen comparten la misma clave privada del host. El inconveniente es una clave nueva cada vez que se recrea un contenedor, lo que provoca el aviso de clave del host. Guarda /etc/ssh en un volumen si eso te importa.
  • El puerto está enlazado a 127.0.0.1. Los puertos publicados se saltan ufw. La documentación de Docker dice que el tráfico se desvía antes de llegar a las reglas de ufw, así que -p 2222:22 puede quedar abierto al mundo aunque ufw esté activo.
  • Esta imagen no guarda secretos. authorized_keys solo tiene claves públicas. Nunca copies una clave privada en una imagen.

Preguntas

¿docker exec necesita SSH?

No. El comando docker habla con el daemon de Docker, que inicia el proceso dentro del contenedor.

¿Cómo abro un shell en un contenedor como root?

Añade -u root: docker exec -it -u root web sh. Funciona aunque la imagen se ejecute con otro usuario.

¿Cómo entro en un contenedor de un servidor remoto?

Entra por SSH en el servidor que lo ejecuta y usa docker exec. En un solo paso: ssh -t user@server docker exec -it web sh.

¿Un shell iniciado con docker exec sobrevive al reinicio del contenedor?

No. Solo funciona mientras el proceso principal del contenedor está en marcha, y no se vuelve a iniciar cuando el contenedor se reinicia.

Fuentes

Más en SSH en cada sistema

Todas las guías