Cómo instalar Portainer con Docker Compose v2
Más sobre este artículo
Resumen rápido
- Portainer CE, la UI web de gestión de contenedores Docker, se instala con Docker Compose v2 mediante un único `compose.yaml` de 15 líneas sin clave `version:`.
- Pinea la imagen a `portainer/portainer-ce:2.40.0` en lugar de `:latest` para controlar exactamente cuándo se actualiza el servidor.
- El volumen nombrado `portainer_data` conserva usuarios, endpoints y configuración entre actualizaciones sin pérdida de datos.
- El socket Docker se monta en solo-lectura (`:ro`) porque Portainer gestiona los contenedores vía API REST y no necesita acceso de escritura al socket del host.
Conceptos clave
- Requisitos previos: Docker Engine 24+ con el plugin `docker compose` integrado, acceso sudo y el puerto 9443 libre.
- Preparar compose.yaml: Fichero de 15 líneas con imagen pineada, volumen nombrado y socket Docker en solo-lectura.
- Lanzar el contenedor: Un único `docker compose up -d` arranca Portainer con HTTPS en el puerto 9443.
Enlaces útiles
Sigue leyendo
Actualizado: 2026-05-16
Portainer[1] es la UI web de referencia para gestionar contenedores Docker, stacks de Compose y clusters Swarm/Kubernetes. La edición CE 2.40 STS incluye soporte nativo de Docker Compose v2, HTTPS por defecto en el puerto 9443, y un panel unificado para recursos Docker Engine, Swarm, Kubernetes y ACI.
Esta guía instala Portainer CE con Docker Compose v2 en un servidor Debian/Ubuntu moderno (Ubuntu 24.04 LTS / Debian 13 Trixie), usando un fichero compose.yaml y el plugin oficial docker compose (sin guion, incluido con Docker Engine 20.10+).
Puntos clave
- Usa
compose.yaml(sin claveversion:) en lugar del antiguodocker-compose.ymlcon versión explícita. - Pinea la imagen (
portainer/portainer-ce:2.40.0) en lugar de:latestpara evitar upgrades silenciosos. - El volumen nombrado (
portainer_data) simplifica backups y actualizaciones. - El socket Docker se monta en solo-lectura (
:ro): Portainer no necesita escritura directa al socket. - El formulario de primer acceso expira a los 5 minutos: tenlo todo preparado antes de abrir el navegador.
Requisitos previos
Antes de empezar, necesitas:
- Servidor con Docker Engine 24+ instalado (incluye el plugin
docker composepor defecto). Ver la guía oficial de Docker para Debian[2] o Ubuntu[3]. - Acceso
sudoo usuario en el grupodocker. - Puerto
9443libre para la UI HTTPS y, opcionalmente, el8000para el Edge Agent Tunnel.
Preparar el fichero compose.yaml
Crea el directorio de trabajo y el fichero de configuración:
mkdir -p ~/docker/portainer
cd ~/docker/portainer
nano compose.yamlContenido recomendado:
services:
portainer:
image: portainer/portainer-ce:2.40.0
container_name: portainer
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "9443:9443" # UI HTTPS
- "8000:8000" # Edge Agent tunnel (opcional)
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- portainer_data:/data
volumes:
portainer_data:Diferencias respecto a guías antiguas que vale la pena conocer:
- Sin clave
version:. La Compose Specification la ignora desde 2023; hoy es redundante y genera advertencias en algunas versiones. - Nombre
compose.yamlpreferido sobredocker-compose.yml(ambos funcionan, pero el nuevo es el estándar oficial). - Imagen pineada a
2.40.0, no:latest. El pinning evita sorpresas por upgrades mayores silenciosos cuando el host lanza un pull. - Volumen nombrado (
portainer_data) en lugar de bind-mount. Lo gestiona Docker directamente y facilita backups con herramientas como restic[4] odocker cp. - Socket Docker en solo-lectura (
:ro). Portainer controla todo vía API, no necesita escritura directa al socket del host.

Panel de administración de Portainer CE mostrando la lista de contenedores Docker en ejecución
Lanzar el contenedor
Con el fichero compose.yaml en su lugar, levanta Portainer en segundo plano:
docker compose up -d
docker compose psVerás un contenedor portainer corriendo y escuchando en 0.0.0.0:9443. Si el comando docker compose no existe, asegúrate de estar usando Docker Engine 20.10+ con el plugin integrado, no la versión legada docker-compose (con guion).
Primer acceso
Abre en el navegador:
https://<IP-o-dominio>:9443La primera vez te pedirá crear el usuario admin con una contraseña mínima de 12 caracteres. El formulario expira a los 5 minutos desde que arranca el contenedor, si tardas, reinicia con docker compose restart y vuelve a entrar.
Como el certificado HTTPS es autofirmado en primera instalación, tu navegador avisará de «conexión no privada». Es normal; pulsa «Avanzado → Continuar» para acceder. Para producción, coloca Portainer detrás de un reverse proxy como Traefik[5] con Let’s Encrypt automático (ver más abajo).
Actualizar Portainer a una nueva versión
Actualizar Portainer es seguro porque el volumen portainer_data persiste usuarios, endpoints y configuración entre versiones:
# 1) Editar compose.yaml y cambiar la tag (p.ej. 2.40.0 -> 2.41.0)
# 2) Pull + recreate:
docker compose pull
docker compose up -d
# 3) Limpiar imagen anterior (opcional):
docker image prune -fEl volumen garantiza que la actualización no pierde datos. Si algo va mal, simplemente edita la tag al valor anterior y vuelve a hacer docker compose up -d.
Exponer Portainer con Traefik (opcional)
Si ya tienes Traefik como ingress con red traefik_public definida, añade labels al servicio y quita el mapping de puertos. Cuando Traefik termina TLS por ti, el puerto interno es 9000 (HTTP), no 9443:
services:
portainer:
image: portainer/portainer-ce:2.40.0
restart: unless-stopped
networks: [traefik_public]
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- portainer_data:/data
labels:
- traefik.enable=true
- traefik.http.routers.portainer.rule=Host(`portainer.example.com`)
- traefik.http.routers.portainer.entrypoints=websecure
- traefik.http.routers.portainer.tls.certresolver=letsencrypt
- traefik.http.services.portainer.loadbalancer.server.port=9000
- traefik.http.services.portainer.loadbalancer.server.scheme=http
networks:
traefik_public:
external: true
volumes:
portainer_data:Con esta configuración, Traefik gestiona el certificado TLS con Let’s Encrypt y Portainer queda accesible en https://portainer.example.com sin puertos no estándar. El mismo patrón aplica a cualquier servicio adicional que despliegues, ver cómo instalar servidores MCP locales como ejemplo de servicio complementario.
Conclusión
La instalación moderna de Portainer con Compose v2 es más limpia y robusta que las guías de hace tres años: un compose.yaml de 15 líneas, versión pineada, HTTPS por defecto, y persistencia en volumen nombrado. Para entornos con varios nodos, Swarm o Kubernetes, Portainer añade la misma UI sobre el endpoint del cluster sin cambiar el patrón de despliegue de esta guía.
Lo esencial que no cambia entre versiones:
- Pinea la imagen para controlar cuándo actualizas.
- Usa volumen nombrado, no bind-mount, para la carpeta
/data. - Monta el socket en solo-lectura.
- Pon un reverse proxy con TLS en producción.