El origen de todo esto
Estoy construyendo mi propia plataforma para subir mis proyectos y que sean accesibles desde cualquier lugar. Esta es mi primera opción para alojar mis proyectos.
Este tutorial te guía paso a paso para configurar un stack completo de gestión Docker con Traefik, Portainer, Dozzle y Uptime Kuma.
¿Qué hace cada servicio?
Traefik
Reverse proxy y load balancer moderno para microservicios. Detecta automáticamente los contenedores de Docker y genera certificados SSL con Let's Encrypt. Básicamente, le dices qué dominio quieres y él se encarga de todo.
Portainer
Interfaz web para gestionar Docker. Permite ver contenedores, logs, volúmenes, redes y desplegar stacks sin tocar la terminal. Muy útil cuando tienes varios proyectos corriendo.
Uptime Kuma
Sistema de monitoreo para tus servicios. Envía alertas a Telegram, Discord, Email o Slack cuando algo se cae. La tranquilidad de saber que si algo falla, te enterás al instante.
Dozzle
Visor de logs en tiempo real de todos los contenedores. Interfaz web ligera y sin base de datos. Perfecto para cuando necesitás ver qué está pasando en tus apps sin conectarte por SSH.
1. Requisitos Previos
VPS mínimo recomendado
- RAM: 2GB mínimo (4GB recomendado)
- CPU: 1 vCPU
- Disco: 20GB SSD
- OS: Ubuntu 22.04/24.04 LTS
Dominio configurado
Necesitas un dominio con registros DNS tipo A apuntando a tu VPS:
- traefik.tudominio.com → IP_VPS
- portainer.tudominio.com → IP_VPS
- logs.tudominio.com → IP_VPS
- uptime.tudominio.com → IP_VPS
Los DNS deben estar propagados ANTES de levantar los servicios, o Let's Encrypt fallará al generar certificados.
2. Preparar la VPS
2.1 Conectar por SSH
ssh usuario@IP_VPS2.2 Actualizar sistema
sudo apt update && sudo apt upgrade -y2.3 Instalar Docker
# Instalar dependencias
sudo apt install -y ca-certificates curl gnupg lsb-release
# Agregar GPG key de Docker
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Agregar repositorio
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Instalar Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Permitir usar Docker sin sudo
sudo usermod -aG docker $USER
# Aplicar cambios (o reconectar SSH)
newgrp docker2.4 Verificar instalación
docker --version
docker compose version2.5 Configurar firewall
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
sudo ufw status3. Crear Estructura del Proyecto
3.1 Crear directorios
mkdir -p ~/apps/traefik
cd ~/apps/traefik3.2 Crear red de Docker
docker network create traefik_network3.3 Crear volumen para Portainer
docker volume create portainer_data3.4 Crear archivo acme.json (certificados SSL)
touch acme.json
chmod 600 acme.jsonEl archivo acme.json DEBE tener permisos 600, o Traefik no arrancará.
4. Archivos de Configuración
4.1 Crear traefik.yml
api:
dashboard: 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: traefik_network
certificatesResolvers:
letsencrypt:
acme:
email: TU_EMAIL@ejemplo.com
storage: acme.json
httpChallenge:
entryPoint: web- exposedByDefault: false - Los contenedores NO se exponen automáticamente, debes usar labels
- httpChallenge - Let's Encrypt valida tu dominio via HTTP (puerto 80)
- Redirección automática HTTP → HTTPS
4.2 Crear docker-compose.yml
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
environment:
- TZ=America/Bogota
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.tudominio.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
networks:
- traefik_network
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
networks:
- traefik_network
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- uptime_kuma_data:/app/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.uptime.rule=Host(`uptime.tudominio.com`)"
- "traefik.http.routers.uptime.entrypoints=websecure"
- "traefik.http.routers.uptime.tls.certresolver=letsencrypt"
- "traefik.http.services.uptime.loadbalancer.server.port=3001"
networks:
- traefik_network
dozzle:
image: amir20/dozzle:latest
container_name: dozzle
restart: unless-stopped
security_opt:
- no-new-privileges:true
environment:
- DOZZLE_AUTH_PROVIDER=simple
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./dozzle_data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.dozzle.rule=Host(`logs.tudominio.com`)"
- "traefik.http.routers.dozzle.entrypoints=websecure"
- "traefik.http.routers.dozzle.tls.certresolver=letsencrypt"
- "traefik.http.services.dozzle.loadbalancer.server.port=8080"
networks:
- traefik_network
networks:
traefik_network:
name: traefik_network
driver: bridge
volumes:
portainer_data:
external: true
uptime_kuma_data:5. Configurar Autenticación Dozzle
mkdir -p dozzle_data
# Generar usuario (cambiar admin/admin por tus credenciales)
docker run --rm amir20/dozzle generate admin --password TU_PASSWORD --email tu@email.com --name Admin > dozzle_data/users.yml6. Levantar los Servicios
6.1 Iniciar stack
cd ~/apps/traefik
docker compose up -d6.2 Verificar que todo esté corriendo
docker ps6.3 Ver logs de Traefik
docker logs traefik -f7. Acceder a los Servicios
Una vez levantado, accede a:
- Traefik Dashboard: https://traefik.tudominio.com (solo visualización)
- Portainer: https://portainer.tudominio.com (crear usuario admin)
- Uptime Kuma: https://uptime.tudominio.com (crear usuario admin)
- Dozzle (logs): https://logs.tudominio.com (usuario creado en paso 5)
8. Agregar Nuevos Servicios
Para exponer cualquier nuevo servicio a través de Traefik, agrega estas labels:
services:
mi-app:
image: mi-imagen
labels:
- "traefik.enable=true"
- "traefik.http.routers.miapp.rule=Host(`app.tudominio.com`)"
- "traefik.http.routers.miapp.entrypoints=websecure"
- "traefik.http.routers.miapp.tls.certresolver=letsencrypt"
- "traefik.http.services.miapp.loadbalancer.server.port=PUERTO_INTERNO"
networks:
- traefik_network
networks:
traefik_network:
external: trueLos servicios en OTRO docker-compose deben usar external: true en la red.
9. Comandos Útiles
# Ver estado de contenedores
docker ps
# Ver logs de un servicio
docker logs traefik -f
# Reiniciar un servicio
docker compose restart traefik
# Actualizar imágenes
docker compose pull
docker compose up -d
# Limpiar imágenes viejas
docker image prune -f
# Ver certificados generados
cat acme.json | jq '.letsencrypt.Certificates[].domain'10. Solución de Problemas
Certificado SSL no se genera
- Verificar que el DNS esté propagado: dig +short traefik.tudominio.com
- Verificar permisos de acme.json (debe ser 600)
- Ver logs de Traefik para errores ACME: docker logs traefik 2>&1 | grep -i acme
Traefik no arranca
# Verificar configuración
docker compose config
# Ver logs de error
docker logs traefikBad Gateway (502)
- Verificar que el contenedor destino esté corriendo
- Verificar que el puerto en loadbalancer.server.port sea correcto
- Verificar que ambos contenedores estén en traefik_network
11. Seguridad Adicional
Proteger Dashboard de Traefik con BasicAuth
# Generar credenciales
sudo apt install apache2-utils -y
echo $(htpasswd -nb admin TU_PASSWORD_SEGURO)Agregar a labels de traefik:
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$..."
- "traefik.http.routers.traefik.middlewares=traefik-auth"En docker-compose, escapar $ con $$.
12. Backup
Archivos críticos a respaldar
- acme.json (certificados SSL)
- docker-compose.yml (configuración)
- traefik.yml (config de Traefik)
- dozzle_data/ (usuarios Dozzle)
Script de backup simple
#!/bin/bash
BACKUP_DIR=~/backups/traefik-$(date +%Y%m%d)
mkdir -p $BACKUP_DIR
cp -r ~/apps/traefik/* $BACKUP_DIR/
docker run --rm -v portainer_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/portainer_data.tar.gz /data
echo "Backup completado en $BACKUP_DIR"