Introducción
En el post anterior te conté por qué Docker le da mil vueltas a las VMs para servicios de laboratorio. Hoy pasamos a la acción: instalamos Docker, aprendemos los 5 comandos que vas a usar el 90% del tiempo, y entendemos el comando básico de docker run -d -p 8080:80 --rm.
Al final de este post serás capaz de levantar cualquier aplicación vulnerable con un solo comando y saber exactamente qué está pasando por debajo.
1. Instalar Docker en Linux
1.1 Instalar dependencias
sudo apt update
sudo apt install -y ca-certificates curlBash1.2 Añadir la clave GPG oficial de Docker
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.ascBash1.3 Añadir el repositorio oficial
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable" | sudo tee /etc/apt/sources.list.d/docker.list
### OJO!! NECESITARÁS CAMBIAR LA URL https://download.docker.com/linux/ubuntu noble stable SEGÚN TU LINUX, EN MICASO VOY A USAR LINUX MINT 22 QUE ESTA BASADO EN UBUNTU 24.04 NOBLE NUMBAT ###
### PODRÍAMOS INSTALAR DOCKER DESDE LOS REPOSITORIOS PROPIOS DE MINT PERO CASI SEGURO NO OBTENDRÍAMOS LA ÚLTIMA VERSIÓN ###Bash1.4 Instalar Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginBash1.5 Verificar que Docker funciona
sudo docker run hello-worldBashDeberías ver algo como esto:
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/Bash2. Evitar sudo en cada comando (opcional pero cómodo)
Por defecto necesitas sudo para lanzar Docker. Para no teclearlo 40 veces al día:
sudo groupadd docker 2>/dev/null
sudo usermod -aG docker $USER
newgrp dockerBashCierra la sesión y vuelve a entrar (o reinicia la terminal). A partir de ahora docker run sin sudo debería funcionar.
3. Los 5 comandos que usarás siempre
Antes de desmenuzar docker run, necesitas un mapa mental de lo básico. Estos comandos son tu kit de supervivencia:
3.1 docker ps — ver qué está corriendo
docker psBashMuestra los contenedores activos ahora mismo. Si no tienes nada corriendo, verás solo la cabecera de la tabla. Añade -a para ver también los que están parados:
docker ps -aBashLa salida te da, para cada contenedor: su ID, la imagen que usa, el comando que ejecutó, cuándo se creó, su estado y los puertos mapeados. Ejemplo de salida:
apuntes@hacking:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
apuntes@hacking:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
65f182055985 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago elegant_dewdney
f9a5c81cfa2f hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago flamboyant_jepsenBash3.2 docker images — ver qué imágenes tienes descargadas
docker imagesBashUna imagen es una plantilla de solo lectura a partir de la cual se crean los contenedores. Cuando haces docker run nginx, Docker busca la imagen nginx en local y, si no la tiene, la descarga automáticamente de Docker Hub.
3.3 docker stop y docker rm — parar y borrar contenedores
docker stop <nombre_o_ID>
docker rm <nombre_o_ID>Bashstop envía una señal de apagado educada; rm lo elimina definitivamente. Puedes encadenarlos:
docker stop <nombre_o_ID> && docker rm <nombre_o_ID>Bash3.4 docker pull — descargar una imagen sin ejecutarla
docker pull nginxBashDescarga la imagen y la guarda en tu disco. Útil si quieres tenerla lista para cuando la necesites, sin arrancar nada todavía.
3.5 docker exec — ejecutar un comando dentro de un contenedor que ya está corriendo
docker exec -it <nombre_o_ID> bashBashEsto es oro para pentesting: te abre una shell dentro del contenedor como si estuvieras dentro de la máquina víctima. Verás su sistema de archivos, sus procesos, sus usuarios… Ideal para entender cómo está configurado el servicio vulnerable por dentro.
4. El comando estrella — docker run
Ahora sí, el plato fuerte. docker run crea y arranca un contenedor nuevo desde una imagen. Su sintaxis más común:
docker run [opciones] <imagen> [comando]BashUn ejemplo fucional:
docker run -d -p 8080:80 --rm nginxBashVamos a destriparlo:
4.1 -d — modo detached (segundo plano)
Sin -d:
docker run -p 8080:80 nginxBashEl terminal se queda «enganchado» mostrando los logs del servidor. Si pulsas Ctrl+C, matas el contenedor. Esto es útil a veces para depurar en tiempo real, pero normalmente quieres tu terminal libre para seguir trabajando.
Con -d:
docker run -d -p 8080:80 nginxBashEl contenedor se va al fondo (detached). Tu terminal queda libre inmediatamente y el contenedor sigue corriendo hasta que lo pares con docker stop.
Si estás depurando un exploit y quieres ver en vivo qué pide la aplicación vulnerable, quita el -d. Verás las peticiones HTTP llegando al servidor conforme las envías.
4.2 -p 8080:80 — mapeo de puertos (host:contenedor)
Esta opción es fundamental y se lleva mal al principio, así que pon atención.
Formato: -p :
- Puerto del host (8080): el puerto de tu máquina (el anfitrión) por el que vas a acceder.
- Puerto del contenedor (80): el puerto que la aplicación escucha dentro del contenedor.
En el ejemplo -p 8080:80:
- Nginx escucha en el puerto 80 dentro del contenedor (comportamiento por defecto).
- Tú quieres acceder desde tu navegador, así que mapeas ese 80 interno al 8080 de tu máquina.
- Abres http://localhost:8080 y ¡voilà!, ves Nginx.
¿Por qué no poner -p 80:80? Porque el puerto 80 de tu host puede estar ocupado por otro servicio o requerir permisos de root. Con 8080 evitas conflictos y no necesitas sudo.
Puedes mapear varios puertos a la vez:
docker run -d -p 8080:80 -p 443:443 nginxBash4.3 --rm — autodestrucción al parar
Sin --rm:
docker run -d -p 8080:80 nginx
docker stop <ID>
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d93594dcf3cb nginx "/docker-entrypoint.…" 17 seconds ago Exited (0) 3 seconds ago busy_kepler # <-- El contenedor sigue apareciendo como "Exited"
65f182055985 hello-world "/hello" 27 minutes ago Exited (0) 27 minutes ago elegant_dewdney
f9a5c81cfa2f hello-world "/hello" 34 minutes ago Exited (0) 34 minutes ago flamboyant_jepsenBashEl contenedor parado se queda ocupando un poquito de espacio en disco (metadatos, logs…). No es grave, pero se acumula rápido cuando pruebas 20 cosas al día.
Con –rm:
docker run -d -p 8080:80 --rm nginx
docker stop <ID>
docker ps -a # ¡Desapareció! No hay rastro.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
65f182055985 hello-world "/hello" 27 minutes ago Exited (0) 27 minutes ago elegant_dewdney
f9a5c81cfa2f hello-world "/hello" 34 minutes ago Exited (0) 34 minutes ago flamboyant_jepsenBashEl contenedor se borra automáticamente al detenerse. Ideal para laboratorio: pruebas algo, lo rompes, lo paras y como si no hubiera pasado nada. La imagen de Nginx sigue en tu disco, así que volver a levantarlo es inmediato (no se descarga otra vez).
Resumen:
docker run -d -p 8080:80 --rm nginxBashdockerinvoca al motor de Docker.runcrea un contenedor a partir de una imagen.-dlo arranca en segundo plano.-p 8080:80conecta el puerto 8080 de tu máquina con el 80 del contenedor.--rmprograma su autodestrucción cuando se pare.nginxes la imagen base que se descarga de Docker Hub si no la tienes en local.
El flujo completo de Docker es:
- Busca la imagen nginx en tu disco local.
- Si no la encuentra, la descarga (docker pull implícito).
- Crea un sistema de archivos aislado a partir de esa imagen.
- Le asigna una IP en la red virtual de Docker.
- Mapea los puertos según
-p. - Arranca el proceso que la imagen tiene definido como principal (en Nginx, el servidor web).
- Devuelve el control a tu terminal y el contenedor sigue vivo.
Otro ejemplo, esta vez levantamos un servidor Apache:
docker run -d -p 8080:80 --rm --name mi_apache httpd:2.4Bash- –name mi_apache le da un nombre legible (en vez de un ID hexadecimal aleatorio como
a3f7c2b9). - httpd:2.4 es la imagen oficial de Apache HTTP Server versión 2.4.
Verás el HTML de la página por defecto de Apache. Abre el navegador, ve a http://127.0.0.1:8080 y confírmalo visualmente.
¿Quieres husmear dentro del contenedor?
docker exec -it mi_apache bashBashEstás dentro. Prueba:
cat /etc/os-release # Ver qué "sistema operativo" tiene dentro
ls /usr/local/apache2/htdocs/ # Ver los archivos del sitio web
exit # Salir del contenedorBashLimpiar la casa, no dejes basura
Comandos de limpieza:
# Parar y borrar el contenedor activo
docker stop mi_apache # Si usaste --rm, ya se borra solo
# Ver todos los contenedores (activos e inactivos)
docker ps -a
# Borrar un contenedor específico
docker rm <ID_o_nombre>
# Borrar imágenes que ya no uses
docker rmi httpd:2.4
# Borrar TODO lo que no esté en uso (contenedores parados, imágenes sin usar, redes, caché...)
docker system prune -aBashdocker system prune -a borra todas las imágenes que no estén siendo usadas por al menos un contenedor activo. Úsalo cuando quieras hacer limpieza general.
Chuleta
# Ver qué está corriendo
docker ps
# Ver qué imágenes tengo descargadas
docker images
# Lanzar un servicio en segundo plano, puerto 8080, autodestruible y con nombre
docker run -d -p 8080:80 --rm --nombre <nombre> <imagen>
# Meter una shell dentro del contenedor
docker exec -it <nombre> bash
# Parar y borrar
docker stop <nombre> && docker rm <nombre>Bash

Deja una respuesta