Si alguna vez has querido tomar el control de tus propios servicios en la nube (self-hosting), tener una base sólida es fundamental. Hoy te traigo una guía completa para configurar un Ubuntu Server 24.04 LTS desde cero con Docker, Portainer y Traefik.

Esta configuración te permitirá desplegar aplicaciones en segundos, gestionarlas con una interfaz gráfica amigable (Portainer) y exponerlas a Internet de forma segura con certificados SSL automáticos gracias al router dinámico (Traefik).
Además, definiremos una estructura de directorios optimizada para mantener el orden, separando la configuración de los datos persistentes.
Ubuntu 24.04 facilita enormemente la vida, pero siempre es mejor usar el repositorio oficial de Docker para tener las últimas versiones.
Agrega la clave GPG y el repositorio oficial:
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
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.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Instala Docker y el plugin de Compose:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
(Opcional pero recomendado) Añade tu usuario al grupo docker para no usar sudo constantemente:
sudo usermod -aG docker $USER
Tendrás que cerrar sesión y volver a entrar para que se apliquen los cambios.
/opt/stacksPara evitar el caos, crearemos una estructura de carpetas unificada. Todos nuestros docker-compose.yml vivirán en /opt/stacks, y cada servicio tendrá su propia carpeta. Además, mapearemos los volúmenes de datos dentro de esas mismas carpetas (por ejemplo en una subcarpeta llamada data).
Creamos el directorio base y la red externa que usará Traefik:
sudo mkdir -p /opt/stacks
sudo chown $USER:$USER /opt/stacks
docker network create web
(Asumimos en adelante que ya tienes permisos en /opt/stacks)
Portainer es nuestra interfaz gráfica. Nos facilita la gestión de contenedores, volúmenes y redes. Lo desplegaremos usando un compose básico, sin enrutarlo aún por Traefik (para usarlo como salvavidas si Traefik falla).
mkdir -p /opt/stacks/portainer/data
cd /opt/stacks/portainer
nano docker-compose.yml
Añade este contenido:
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: always
security_opt:
- no-new-privileges:true
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data:/data
ports:
- 9000:9000
- 8000:8000
Levanta el servicio: docker compose up -d
(Accede a http://IP_DE_TU_SERVER:9000 para configurar la clave inicial).
Traefik es la joya de la corona. Actuará como router o proxy inverso. Leerá las etiquetas ("labels") que pongamos en nuestros otros contenedores y creará las reglas de enrutamiento y certificados LetsEncrypt mágicamente.
mkdir -p /opt/stacks/traefik/data
cd /opt/stacks/traefik
nano docker-compose.yml
Añade este docker-compose.yml. OJO: Cambia tucorreo@dominio.com:
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: always
security_opt:
- no-new-privileges:true
ports:
- 80:80
- 443:443
environment:
- CF_API_EMAIL=tucorreo@dominio.com # Si luego usas dns challenge
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
networks:
- web
networks:
web:
external: true
Antes de levantarlo, necesitamos crear los archivos que mapeamos:
touch data/acme.json
chmod 600 data/acme.json
nano data/traefik.yml
Configuración básica de traefik.yml para resolución por HTTP (Let's encrypt):
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: web
certificatesResolvers:
letsencrypt:
acme:
email: tucorreo@dominio.com
storage: acme.json
httpChallenge:
entryPoint: web
Levanta Traefik: docker compose up -d
A partir de ahora, cuando quieras levantar un nuevo servicio (por ejemplo, whoami para probar), el flujo es siempre este:
/opt/stacks:
mkdir -p /opt/stacks/whoamidocker-compose.yml en su directorio, mapeando sus datos en ./data, uniéndolo a la red web y añadiendo los labels para Traefik. Ejemplo:services:
whoami:
image: traefik/whoami
container_name: whoami
restart: always
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.tudominio.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
networks:
web:
external: true
¡Y eso es todo! Levantando este contenedor, Traefik detectará las etiquetas, pedirá el certificado a Let's Encrypt, y enrutará el tráfico del subdominio hacia el contenedor. Todo de forma transparente y manteniendo tus datos ordenador en /opt/stacks.