SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-28

Guía de Docker Compose para servidores reales

Consulta los comandos de Compose V2 para el trabajo diario: ciclo de vida, cambios, logs, shells, redes, volúmenes y limpieza segura desde tu servidor.

Los comandos de Compose que realmente se usan

Docker Compose incluye más de cuarenta subcomandos. En el trabajo diario de un servidor se usan aproximadamente una docena. Esta página los agrupa según la tarea que se realiza, explica de forma sencilla para qué sirve cada uno y enlaza con la explicación detallada cuando un comando oculta algún problema.

Todo lo que aparece aquí usa Compose V2: docker compose con un espacio, no el script antiguo docker-compose. V2 es un plugin escrito en Go que se instala con Docker Engine, y V1 ya no está disponible en los paquetes actuales. Por eso, encontrar docker-compose: command not found en un equipo Ubuntu recién instalado en julio de 2026 es normal y no indica un fallo. Compruébelo con docker compose version. Si no muestra nada, instale el paquete docker-compose-plugin.

Todos los comandos siguientes se ejecutan desde el directorio que contiene compose.yaml, porque Compose obtiene el nombre del proyecto de ese directorio y busca el archivo en relación con él. Si ejecuta el mismo comando un nivel por encima, Compose se detiene con no configuration file provided: not found. Si el formato del archivo aún es nuevo para usted, empiece por un primer archivo de Compose en un VPS y vuelva aquí para consultar los comandos.

Ciclo de vida: los cuatro comandos que se escriben y el que elimina los contenedores

docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose down

up -d crea la red, crea los contenedores, los inicia y devuelve el control. Devuelve el control en cuanto los contenedores están creados. Por eso un script de despliegue que ejecuta después una comprobación curl suele fallar la primera vez. up -d --wait bloquea la ejecución hasta que todos los servicios que declaran una comprobación de estado informan de que están saludables, y termina con un código distinto de cero si alguno nunca alcanza ese estado. La opción sólo es tan fiable como la comprobación que la respalda. Por tanto, escriba una comprobación de estado que Compose pueda validar antes de depender de ella en la automatización.

stop detiene los contenedores y los conserva. Por tanto, start vuelve a iniciar los mismos contenedores con la misma capa de escritura. down los detiene y después elimina los contenedores y la red del proyecto. Todo lo que se haya escrito dentro del contenedor y fuera de un volumen se pierde con ellos. Este es el malentendido más costoso de Compose. La diferencia completa entre down y stop explica dónde puede causar problemas.

restart no recarga la configuración. Detiene e inicia el mismo contenedor con la configuración que ya tiene. Por tanto, una variable de entorno modificada, una nueva etiqueta de imagen o un mapeo de puertos editado no tienen ningún efecto. Para aplicar un cambio en el archivo, vuelva a ejecutar up -d. Compose compara cada servicio con su contenedor en ejecución y sólo vuelve a crear los contenedores cuya configuración haya cambiado.

Aplicar un cambio: recrear, extraer o volver a compilar

docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build web

up -d por sí solo no hace nada cuando no ha cambiado nada, lo que permite ejecutarlo repetidamente de forma segura. --force-recreate fuerza esa comparación y reemplaza todos los contenedores incluso cuando la configuración es idéntica, por lo que es la forma más rápida de eliminar un estado extraño dentro del contenedor.

Actualizar una imagen requiere dos comandos porque cada uno realiza una tarea distinta. pull descarga la imagen actual para cada etiqueta indicada en el archivo. up -d detecta que el ID de imagen del servicio ya no coincide con el de su contenedor en ejecución y lo vuelve a crear. Si omite la extracción, up -d mantiene en ejecución el latest del mes pasado sin mostrar ningún error. El riesgo contrario aparece en una pila con varios servicios, donde extraer latest para todos a la vez puede interrumpir una aplicación que funcionaba diez segundos antes. Por eso, un espacio de trabajo AFFiNE autohospedado fija cada una de sus cuatro etiquetas de imagen. Fijar las etiquetas también convierte una actualización en una edición deliberada de la etiqueta, seguida de la misma extracción y recreación. En una pila que migra la base de datos durante el arranque, conviene tener un volcado preparado antes de ejecutar cualquiera de los dos comandos. Este es el procedimiento que sigue una mesa de soporte Chatwoot autohospedada en cada actualización de versión.

build se aplica a los servicios que declaran una sección build: en lugar de una image:. up -d --build compila e inicia en un solo paso, que es el ciclo normal mientras cambia el código. Use --no-cache sólo cuando una capa almacenada en caché esté claramente obsoleta, porque vuelve a compilar todas las capas desde cero. Cuando una pila se implementa a partir de una etiqueta de git descargada en lugar de una imagen de un registro, ese mismo ciclo de compilación también es su ruta de actualización. Así es como un rastreador de entrenamientos openGym autoalojado pasa de una versión fijada a la siguiente.

Ver qué está en ejecución

docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose ls

ps sólo muestra los contenedores en ejecución. Un servicio que falló durante el arranque no aparece ahí hasta que se añade -a, por lo que un contenedor ausente en ps mientras ps -a lo muestra como Exited (1) es el patrón normal de un fallo de arranque. Lea el código de salida y, después, los registros.

logs -f sigue todos los servicios al mismo tiempo y añade el nombre del servicio al principio de cada línea. Esta es la vista adecuada cuando los servicios se comunican entre sí y el orden de los eventos es importante. Indique un servicio para limitar la salida. --tail=100 es importante en un contenedor que lleva un mes en ejecución, porque la salida predeterminada muestra todo el historial y llena el terminal. --since 15m responde a la pregunta habitual: qué ocurrió durante el reinicio que acaba de realizar.

top muestra los procesos dentro de cada contenedor. Esto permite distinguir entre «el contenedor está en ejecución» y «el proceso que contiene está en ejecución». ls sale del directorio actual y muestra todos los proyectos de Compose del host con su estado. Así puede localizar la pila que inició hace tres meses.

Obtener un shell dentro de un servicio

docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web sh

exec ejecuta un comando dentro de un contenedor que ya está en ejecución. run inicia un contenedor nuevo a partir de la misma definición del servicio. Esto es necesario cuando el servicio no permanece activo el tiempo suficiente para usar exec. Combine siempre run con --rm. Sin esta opción, cada ejecución deja un contenedor detenido, y estos se acumulan hasta que docker compose ps -a resulta ilegible.

Pruebe sh antes que bash. Las imágenes basadas en Alpine no incluyen bash, por lo que el error muestra exec: "bash": executable file not found in $PATH. Añadir --no-deps a run omite las dependencias del servicio. Así, una comprobación rápida de la configuración no inicia toda la base de datos.

run --rm web env es la forma más rápida de ver las variables de entorno que recibió realmente un servicio, después de combinar todos los archivos .env, bloques environment: y variables del shell. Cuando un valor es incorrecto, el orden de combinación suele ser la causa. cómo Compose resuelve los archivos env y los secretos explica qué origen tiene prioridad.

Redes, puertos y resolución de nombres

docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networks

Compose coloca todos los servicios en una red de proyecto, y cada nombre de servicio es un nombre DNS dentro de ella. Ejecutar getent hosts db dentro de web muestra la IP del contenedor cuando la resolución funciona y no muestra nada cuando falla, por lo que responde en dos segundos a la pregunta «¿pueden estos contenedores comunicarse entre sí?». Si el nombre se resuelve pero la conexión es rechazada, el proceso dentro de db está asociado a 127.0.0.1 en lugar de 0.0.0.0, por lo que nunca acepta paquetes de otro contenedor. El mismo límite explica por qué un contenedor iniciado fuera del proyecto, ya sea mediante docker run o como su propia pila, no puede resolver en absoluto un nombre como jellyfin. Esto es lo primero que debe comprobar cuando un frontend Halcyon para su biblioteca de Jellyfin no puede conectarse al servidor que tiene configurado. El resto de este modelo se explica en cómo funcionan las redes de Compose y el DNS de los servicios.

port web 80 muestra la dirección y el puerto del host donde está publicado un puerto del contenedor. Esto evita tener que adivinar cuando la asignación procede de una variable. Publicar un puerto también crea una regla de firewall que Docker administra por su cuenta. Esa regla se aplica antes que las reglas propias, por lo que un servicio que se creía privado puede quedar expuesto a Internet. Este caso se explica en por qué los puertos publicados de Docker omiten ufw. Dejar esos puertos sin publicar y colocar delante de los servicios un único proxy con autenticación en la red del proyecto es una arquitectura más segura. Eso es lo que proporciona ejecutar Authentik como capa de inicio de sesión único.

Volúmenes y datos

docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -v

config --volumes muestra los volúmenes con nombre que declara el proyecto, uno por línea. Esa lista es lo que debe incluir en la copia de seguridad. Cuando los volúmenes contienen datos irremplazables, el comando exacto de copia de seguridad es tan importante como la lista. Por eso la comparación entre PhotoPrism e Immich especifica los comandos de volcado y copia que necesita cada servidor de fotos. cp copia un archivo hacia o desde un contenedor sin abrir un shell. Usa la forma service:path en el lado donde se encuentra el contenedor.

down -v elimina esos volúmenes con nombre junto con los contenedores. Es el comando adecuado para desmontar una pila de prueba y el incorrecto para cualquier pila que contenga datos importantes. No solicita confirmación y no se puede deshacer. Los bind mounts sobreviven, porque residen en el sistema de archivos del host. Esta diferencia en el alcance del impacto es una de las razones para elegir deliberadamente entre bind mounts y volúmenes con nombre.

Limpieza que libera espacio en disco sin perder datos

docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune

--remove-orphans elimina los contenedores que pertenecen al proyecto pero que ya no aparecen en el archivo. Esto ocurre después de cambiar el nombre de un servicio. Sin esta opción, esos contenedores siguen ejecutándose y permanecen invisibles para docker compose ps.

docker system df muestra dónde se usa el disco antes de eliminar nada. Separa las imágenes, los contenedores, los volúmenes locales y la caché de compilación, e indica cuánto espacio puede recuperarse en cada categoría. image prune -a elimina todas las imágenes a las que no apunta ninguna etiqueta. En un servidor que ha descargado varias versiones de una imagen grande, normalmente esta acción libera más espacio. builder prune borra la caché de compilación, que crece silenciosamente en cualquier servidor que compile sus propias imágenes.

Ninguno de esos comandos modifica un volumen con nombre. Sólo docker volume prune y docker compose down -v lo hacen.

Comprobar el archivo antes de que cause problemas

docker compose config --quiet
docker compose config --services
docker compose --dry-run up -d

config --quiet valida el archivo y no muestra nada si la validación es correcta, por lo que resulta adecuado para una etapa previa al despliegue o un hook de Git. config sin opciones muestra el archivo completamente combinado e interpolado. Así puede confirmar que una variable se resolvió y que un archivo de sustituciones se aplicó en el orden esperado. Una variable no definida aparece como un valor vacío, junto con la advertencia The "X" variable is not set. Defaulting to a blank string.

--dry-run es una opción global, no una opción del subcomando, por lo que debe colocarse antes de up. Muestra todas las acciones que Compose ejecutaría y no modifica nada. Son treinta segundos bien invertidos antes de ejecutar down en una pila importante.

Trabajo con archivos, perfiles y proyectos

docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d

Varios indicadores -f se combinan en orden, y los archivos posteriores sobrescriben las claves de los archivos anteriores una por una. Esta es la forma estándar de mantener un archivo base con una pequeña anulación para producción. Sin embargo, las reglas difieren para las listas y los mapas, así que consulte cómo combina Compose varios archivos antes de investigar un resultado inesperado.

--profile inicia los servicios etiquetados con ese perfil junto con los que no tienen etiquetas, de modo que las herramientas de depuración no se incluyan en un up normal. -p establece el nombre del proyecto, por lo que dos copias de una misma pila pueden ejecutarse en paralelo con redes y nombres de volúmenes independientes. Recuperar la pila después de un reinicio no requiere escribir un comando. Se configura una unidad que lo ejecuta automáticamente, como se describe en iniciar pilas de Compose durante el arranque.

FAQ

¿Qué sustituyó a docker-compose con un guion?

Compose V2, invocado como docker compose con un espacio. Es un complemento incluido en Docker Engine, y las versiones actuales de los paquetes ya no instalan la herramienta V1 escrita en Python. Si la forma con espacio no muestra ninguna salida, instale el paquete docker-compose-plugin correspondiente a su distribución. Actualice los scripts antiguos para usar la forma con espacio en lugar de añadir un alias, porque V2 tiene flags que V1 nunca tuvo.

¿Por qué docker compose restart no aplica mi cambio de configuración?

restart detiene e inicia el contenedor existente con la configuración con la que se creó, y nunca vuelve a leer compose.yaml. Cualquier cambio en las variables de entorno, los puertos, los volúmenes o la etiqueta de la imagen requiere docker compose up -d, que compara cada servicio con su contenedor en ejecución y recrea los que son diferentes. Añada --force-recreate cuando quiera que la sustitución se realice aunque no haya cambiado nada en el archivo.

¿Cómo actualizo un servicio a una imagen más reciente?

Ejecute docker compose pull y después docker compose up -d. El primer comando descarga la imagen actual para cada etiqueta del archivo, y up -d recrea cualquier servicio cuyo ID de imagen ya no coincida con el de su contenedor. Ejecutar up -d por separado reutiliza la imagen que ya está almacenada en el disco. Por eso una pila fijada a latest puede seguir usando una compilación con meses de antigüedad sin mostrar ningún error.

¿Qué comandos de limpieza son seguros en un servidor en producción?

docker system df, docker image prune -a y docker builder prune eliminan sólo imágenes y caché. Los servicios en ejecución siguen funcionando y los volúmenes con nombre no se modifican. La pareja peligrosa es docker compose down -v y docker volume prune, que elimina los volúmenes con nombre sin pedir confirmación. Ejecute primero docker compose config --volumes para saber qué elementos están en riesgo.

¿Puedo ejecutar un comando sin iniciar toda la pila?

Sí. docker compose run --rm --no-deps web sh inicia un único contenedor a partir de la definición del servicio web, omite sus dependencias y elimina el contenedor cuando sale. Use exec cuando el contenedor ya esté en ejecución, porque exec se conecta al proceso activo y muestra el estado real del servicio.