Documentación completa del wiki en español
520
Backup.md
Normal file
520
Backup.md
Normal file
@@ -0,0 +1,520 @@
|
||||
# Backup y Restauración
|
||||
|
||||
Esta guía explica cómo realizar copias de seguridad y restaurar los datos de Portainer CE.
|
||||
|
||||
## ¿Qué se Respalda?
|
||||
|
||||
Portainer almacena todos sus datos en el volumen Docker **`portainer_data`**, que incluye:
|
||||
|
||||
- 🔐 **Configuración de usuarios y autenticación**
|
||||
- 🌐 **Entornos (endpoints) configurados**
|
||||
- 📦 **Stacks, plantillas y configuraciones**
|
||||
- 🔑 **Secretos, configs, y credenciales**
|
||||
- 📊 **Configuraciones de roles y permisos**
|
||||
- 🎨 **Personalizaciones de UI y configuraciones**
|
||||
|
||||
⚠️ **Importante**: El volumen `portainer_data` contiene información sensible. Protege los backups adecuadamente.
|
||||
|
||||
## Estrategias de Backup
|
||||
|
||||
### Opción 1: Backup Manual del Volumen
|
||||
|
||||
#### Crear Backup
|
||||
|
||||
```bash
|
||||
# Detener Portainer (recomendado para consistencia)
|
||||
docker compose down
|
||||
|
||||
# Crear backup del volumen usando contenedor temporal
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
|
||||
|
||||
# Reiniciar Portainer
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
**Resultado**: Archivo `portainer-backup-YYYYMMDD-HHMMSS.tar.gz` en el directorio actual.
|
||||
|
||||
#### Backup sin Detener Portainer (En Caliente)
|
||||
|
||||
```bash
|
||||
# Crear backup sin detener el servicio
|
||||
docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
|
||||
```
|
||||
|
||||
⚠️ **Nota**: Los backups en caliente pueden tener inconsistencias si hay cambios durante la copia. Para backups críticos, detén Portainer primero.
|
||||
|
||||
#### Restaurar Backup
|
||||
|
||||
```bash
|
||||
# 1. Detener Portainer
|
||||
docker compose down
|
||||
|
||||
# 2. Eliminar volumen existente (⚠️ cuidado!)
|
||||
docker volume rm portainer_data
|
||||
|
||||
# 3. Crear nuevo volumen
|
||||
docker volume create portainer_data
|
||||
|
||||
# 4. Restaurar datos desde backup
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/portainer-backup-YYYYMMDD-HHMMSS.tar.gz -C /data
|
||||
|
||||
# 5. Verificar permisos
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
alpine \
|
||||
chown -R root:root /data
|
||||
|
||||
# 6. Reiniciar Portainer
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Opción 2: Backup con Script Automatizado
|
||||
|
||||
Crear script `backup-portainer.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Configuración
|
||||
BACKUP_DIR="/var/backups/portainer"
|
||||
RETENTION_DAYS=30
|
||||
VOLUME_NAME="portainer_data"
|
||||
COMPOSE_PATH="/ruta/a/tu/portainer"
|
||||
|
||||
# Crear directorio de backups si no existe
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Timestamp
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
BACKUP_FILE="$BACKUP_DIR/portainer-backup-$TIMESTAMP.tar.gz"
|
||||
|
||||
echo "[$(date)] Iniciando backup de Portainer..."
|
||||
|
||||
# Opción 1: Backup en caliente (servicio corriendo)
|
||||
docker run --rm \
|
||||
-v "$VOLUME_NAME":/data:ro \
|
||||
-v "$BACKUP_DIR":/backup \
|
||||
alpine \
|
||||
tar czf "/backup/portainer-backup-$TIMESTAMP.tar.gz" -C /data .
|
||||
|
||||
# Opción 2: Backup con detención (más seguro, comentar la opción 1 si usas esta)
|
||||
# cd "$COMPOSE_PATH"
|
||||
# docker compose down
|
||||
# docker run --rm \
|
||||
# -v "$VOLUME_NAME":/data \
|
||||
# -v "$BACKUP_DIR":/backup \
|
||||
# alpine \
|
||||
# tar czf "/backup/portainer-backup-$TIMESTAMP.tar.gz" -C /data .
|
||||
# docker compose up -d
|
||||
|
||||
# Verificar que el backup se creó
|
||||
if [ -f "$BACKUP_FILE" ]; then
|
||||
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
||||
echo "[$(date)] Backup completado: $BACKUP_FILE ($SIZE)"
|
||||
else
|
||||
echo "[$(date)] ERROR: Backup falló"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Limpiar backups antiguos
|
||||
echo "[$(date)] Limpiando backups antiguos (>$RETENTION_DAYS días)..."
|
||||
find "$BACKUP_DIR" -name "portainer-backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||||
|
||||
echo "[$(date)] Proceso completado"
|
||||
```
|
||||
|
||||
Hacer ejecutable y probar:
|
||||
|
||||
```bash
|
||||
chmod +x backup-portainer.sh
|
||||
./backup-portainer.sh
|
||||
```
|
||||
|
||||
### Opción 3: Backup Automatizado con Cron
|
||||
|
||||
Programar backups diarios a las 2:00 AM:
|
||||
|
||||
```bash
|
||||
# Editar crontab
|
||||
crontab -e
|
||||
|
||||
# Añadir línea:
|
||||
0 2 * * * /ruta/a/backup-portainer.sh >> /var/log/portainer-backup.log 2>&1
|
||||
```
|
||||
|
||||
Verificar cron:
|
||||
|
||||
```bash
|
||||
# Ver crontab actual
|
||||
crontab -l
|
||||
|
||||
# Ver logs de backup
|
||||
tail -f /var/log/portainer-backup.log
|
||||
```
|
||||
|
||||
### Opción 4: Backup a Almacenamiento Remoto
|
||||
|
||||
#### Backup a NFS/CIFS
|
||||
|
||||
```bash
|
||||
# Montar share remoto
|
||||
mount -t nfs servidor.local:/backups /mnt/backups
|
||||
|
||||
# Crear backup directamente en share
|
||||
docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v /mnt/backups:/backup \
|
||||
alpine \
|
||||
tar czf /backup/portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
|
||||
```
|
||||
|
||||
#### Backup a S3/MinIO
|
||||
|
||||
Usando `rclone`:
|
||||
|
||||
```bash
|
||||
# Configurar rclone primero
|
||||
rclone config
|
||||
|
||||
# Crear backup y subir a S3
|
||||
BACKUP_FILE="portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf "/backup/$BACKUP_FILE" -C /data .
|
||||
|
||||
rclone copy "$BACKUP_FILE" s3-remote:bucket-name/portainer-backups/
|
||||
rm "$BACKUP_FILE"
|
||||
```
|
||||
|
||||
#### Backup con rsync
|
||||
|
||||
```bash
|
||||
# Crear backup local
|
||||
BACKUP_FILE="portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf "/backup/$BACKUP_FILE" -C /data .
|
||||
|
||||
# Copiar a servidor remoto
|
||||
rsync -avz --progress "$BACKUP_FILE" usuario@servidor-backup:/backups/portainer/
|
||||
|
||||
# Opcional: eliminar backup local
|
||||
rm "$BACKUP_FILE"
|
||||
```
|
||||
|
||||
## Restauración de Emergencia
|
||||
|
||||
### Escenario 1: Corrupción de Datos
|
||||
|
||||
```bash
|
||||
# 1. Detener Portainer inmediatamente
|
||||
docker compose down
|
||||
|
||||
# 2. Renombrar volumen corrupto (por si acaso)
|
||||
docker volume create portainer_data_corrupted
|
||||
docker run --rm \
|
||||
-v portainer_data:/source \
|
||||
-v portainer_data_corrupted:/dest \
|
||||
alpine \
|
||||
sh -c "cp -a /source/. /dest/"
|
||||
|
||||
# 3. Limpiar volumen original
|
||||
docker volume rm portainer_data
|
||||
docker volume create portainer_data
|
||||
|
||||
# 4. Restaurar desde último backup válido
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/portainer-backup-YYYYMMDD-HHMMSS.tar.gz -C /data
|
||||
|
||||
# 5. Reiniciar
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Escenario 2: Migración a Nuevo Servidor
|
||||
|
||||
En el **servidor antiguo**:
|
||||
|
||||
```bash
|
||||
# Crear backup
|
||||
docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/portainer-migration.tar.gz -C /data .
|
||||
|
||||
# Copiar a nuevo servidor
|
||||
scp portainer-migration.tar.gz usuario@nuevo-servidor:/tmp/
|
||||
```
|
||||
|
||||
En el **servidor nuevo**:
|
||||
|
||||
```bash
|
||||
# 1. Clonar repositorio o copiar docker-compose.yaml
|
||||
git clone https://git.ictiberia.com/groales/portainer
|
||||
cd portainer
|
||||
|
||||
# 2. Crear volumen
|
||||
docker volume create portainer_data
|
||||
|
||||
# 3. Restaurar datos
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
-v /tmp:/backup \
|
||||
alpine \
|
||||
tar xzf /backup/portainer-migration.tar.gz -C /data
|
||||
|
||||
# 4. Iniciar Portainer
|
||||
docker compose up -d
|
||||
|
||||
# 5. Verificar
|
||||
docker logs portainer
|
||||
```
|
||||
|
||||
### Escenario 3: Rollback a Versión Anterior
|
||||
|
||||
Si una actualización de Portainer causa problemas:
|
||||
|
||||
```bash
|
||||
# 1. Detener versión actual
|
||||
docker compose down
|
||||
|
||||
# 2. Editar docker-compose.yaml y cambiar tag
|
||||
# De: portainer/portainer-ce:lts
|
||||
# A: portainer/portainer-ce:2.19.4 (versión específica)
|
||||
|
||||
# 3. Restaurar backup de antes de la actualización
|
||||
docker volume rm portainer_data
|
||||
docker volume create portainer_data
|
||||
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/portainer-backup-pre-update.tar.gz -C /data
|
||||
|
||||
# 4. Iniciar versión anterior
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Verificación de Backups
|
||||
|
||||
### Test de Restauración
|
||||
|
||||
Es crítico **probar tus backups regularmente**:
|
||||
|
||||
```bash
|
||||
# 1. Crear volumen de test
|
||||
docker volume create portainer_data_test
|
||||
|
||||
# 2. Restaurar backup en volumen de test
|
||||
docker run --rm \
|
||||
-v portainer_data_test:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/portainer-backup-YYYYMMDD-HHMMSS.tar.gz -C /data
|
||||
|
||||
# 3. Iniciar Portainer temporal en otro puerto
|
||||
docker run -d \
|
||||
-p 19443:9443 \
|
||||
--name portainer-test \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v portainer_data_test:/data \
|
||||
portainer/portainer-ce:lts
|
||||
|
||||
# 4. Verificar en https://localhost:19443
|
||||
# Login y verificar que los datos son correctos
|
||||
|
||||
# 5. Limpiar
|
||||
docker stop portainer-test
|
||||
docker rm portainer-test
|
||||
docker volume rm portainer_data_test
|
||||
```
|
||||
|
||||
### Validar Integridad de Backup
|
||||
|
||||
```bash
|
||||
# Verificar que el tar.gz no está corrupto
|
||||
tar tzf portainer-backup-YYYYMMDD-HHMMSS.tar.gz > /dev/null
|
||||
echo $? # Debe devolver 0 si OK
|
||||
|
||||
# Ver contenido del backup
|
||||
tar tzf portainer-backup-YYYYMMDD-HHMMSS.tar.gz | head -20
|
||||
|
||||
# Ver tamaño
|
||||
du -h portainer-backup-YYYYMMDD-HHMMSS.tar.gz
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Estrategia 3-2-1
|
||||
|
||||
- ✅ **3 copias** de tus datos (original + 2 backups)
|
||||
- ✅ **2 medios diferentes** (ej: disco local + NAS)
|
||||
- ✅ **1 copia offsite** (ej: cloud, otro datacenter)
|
||||
|
||||
### 2. Frecuencia de Backups
|
||||
|
||||
Según criticidad:
|
||||
|
||||
| Entorno | Frecuencia Recomendada |
|
||||
|---------|------------------------|
|
||||
| Producción crítica | Cada 6-12 horas |
|
||||
| Producción estándar | Diario |
|
||||
| Desarrollo/Testing | Semanal |
|
||||
|
||||
### 3. Retención
|
||||
|
||||
Ejemplo de política:
|
||||
|
||||
- **Diarios**: 7 días
|
||||
- **Semanales**: 4 semanas
|
||||
- **Mensuales**: 12 meses
|
||||
- **Anuales**: 3 años
|
||||
|
||||
Script de retención:
|
||||
|
||||
```bash
|
||||
# Diarios (últimos 7)
|
||||
find /backups -name "portainer-backup-*.tar.gz" -mtime +7 -mtime -30 -delete
|
||||
|
||||
# Mantener un backup semanal (domingos)
|
||||
# Mantener un backup mensual (día 1)
|
||||
# (implementar lógica adicional según necesidades)
|
||||
```
|
||||
|
||||
### 4. Encriptación de Backups
|
||||
|
||||
Para backups con datos sensibles:
|
||||
|
||||
```bash
|
||||
# Crear backup encriptado con GPG
|
||||
BACKUP_FILE="portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf "/backup/$BACKUP_FILE" -C /data .
|
||||
|
||||
# Encriptar
|
||||
gpg --symmetric --cipher-algo AES256 "$BACKUP_FILE"
|
||||
|
||||
# Resultado: portainer-backup-YYYYMMDD-HHMMSS.tar.gz.gpg
|
||||
rm "$BACKUP_FILE" # Eliminar versión sin encriptar
|
||||
```
|
||||
|
||||
Restaurar encriptado:
|
||||
|
||||
```bash
|
||||
# Desencriptar
|
||||
gpg --decrypt portainer-backup-YYYYMMDD-HHMMSS.tar.gz.gpg > portainer-backup.tar.gz
|
||||
|
||||
# Restaurar normalmente
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/portainer-backup.tar.gz -C /data
|
||||
```
|
||||
|
||||
### 5. Monitorización de Backups
|
||||
|
||||
Script con notificaciones:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# backup-portainer-monitored.sh
|
||||
|
||||
BACKUP_DIR="/var/backups/portainer"
|
||||
WEBHOOK_URL="https://hooks.slack.com/services/TU_WEBHOOK" # O email, etc.
|
||||
|
||||
# ... (lógica de backup) ...
|
||||
|
||||
# Notificar resultado
|
||||
if [ $? -eq 0 ]; then
|
||||
curl -X POST "$WEBHOOK_URL" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"text\":\"✅ Backup Portainer completado: $BACKUP_FILE\"}"
|
||||
else
|
||||
curl -X POST "$WEBHOOK_URL" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"text\":\"❌ ERROR: Backup Portainer falló\"}"
|
||||
fi
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Permission denied"
|
||||
|
||||
```bash
|
||||
# Ejecutar backup con sudo
|
||||
sudo docker run --rm \
|
||||
-v portainer_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/portainer-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
|
||||
```
|
||||
|
||||
### Backup Muy Grande
|
||||
|
||||
```bash
|
||||
# Ver tamaño del volumen
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
alpine \
|
||||
du -sh /data
|
||||
|
||||
# Limpiar logs/cache dentro del volumen si es necesario
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
alpine \
|
||||
sh -c "find /data -name '*.log' -delete"
|
||||
```
|
||||
|
||||
### Restauración No Funciona
|
||||
|
||||
```bash
|
||||
# Verificar contenido del backup
|
||||
tar tzf portainer-backup-YYYYMMDD-HHMMSS.tar.gz | less
|
||||
|
||||
# Listar contenido del volumen restaurado
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
alpine \
|
||||
ls -laR /data
|
||||
|
||||
# Verificar permisos
|
||||
docker run --rm \
|
||||
-v portainer_data:/data \
|
||||
alpine \
|
||||
chown -R root:root /data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Recursos adicionales**:
|
||||
- [Documentación oficial de Portainer](https://docs.portainer.io/)
|
||||
- [Docker Volume Backup Strategies](https://docs.docker.com/storage/volumes/)
|
||||
|
||||
**Volver a**: [Página Principal](Home) | [Instalación Avanzada](Instalacion)
|
||||
385
Edge-Agents.md
Normal file
385
Edge-Agents.md
Normal file
@@ -0,0 +1,385 @@
|
||||
# Edge Agents
|
||||
|
||||
Los **Edge Agents** permiten gestionar entornos Docker remotos que no tienen conectividad directa bidireccional con Portainer Server. Son ideales para:
|
||||
|
||||
- Hosts detrás de firewalls o NAT
|
||||
- Dispositivos IoT en ubicaciones remotas
|
||||
- Entornos edge computing
|
||||
- Sitios con conectividad limitada o intermitente
|
||||
|
||||
## ¿Cómo Funcionan?
|
||||
|
||||
A diferencia del Portainer Agent estándar (que requiere puerto 9001 accesible), el Edge Agent:
|
||||
|
||||
1. **Inicia la conexión** hacia Portainer Server (puerto 8000)
|
||||
2. **Mantiene un túnel** para comunicación bidireccional
|
||||
3. **Polling periódico** cuando la conexión se pierde
|
||||
4. **Modo async** para operaciones cuando está offline
|
||||
|
||||
## Requisitos
|
||||
|
||||
### En Portainer Server
|
||||
|
||||
- ✅ Puerto **8000** expuesto y accesible desde Internet/red remota
|
||||
- ✅ Dominio o IP pública (recomendado)
|
||||
- ✅ Certificado SSL válido (recomendado para producción)
|
||||
|
||||
### En el Host Remoto
|
||||
|
||||
- ✅ Docker instalado
|
||||
- ✅ Conectividad saliente a Portainer Server (puerto 8000)
|
||||
- ✅ NO requiere puertos abiertos hacia el host remoto
|
||||
|
||||
## Habilitar Edge en Portainer Server
|
||||
|
||||
### 1. Exponer Puerto 8000
|
||||
|
||||
Edita `docker-compose.yaml` y descomenta el puerto 8000:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
container_name: portainer
|
||||
image: portainer/portainer-ce:lts
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer_data:/data
|
||||
ports:
|
||||
- "9443:9443"
|
||||
- "8000:8000" # ← Descomentar para Edge Agents
|
||||
networks:
|
||||
- portainer_network
|
||||
```
|
||||
|
||||
### 2. Reiniciar Portainer
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 3. Verificar Puerto
|
||||
|
||||
```bash
|
||||
# Verificar que el puerto está escuchando
|
||||
sudo netstat -tulpn | grep :8000
|
||||
# o con ss
|
||||
ss -tulpn | grep :8000
|
||||
```
|
||||
|
||||
### 4. Configurar Firewall
|
||||
|
||||
```bash
|
||||
# UFW (Ubuntu/Debian)
|
||||
sudo ufw allow 8000/tcp
|
||||
|
||||
# firewall-cmd (RHEL/CentOS/Fedora)
|
||||
sudo firewall-cmd --permanent --add-port=8000/tcp
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
# iptables
|
||||
sudo iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
|
||||
sudo iptables-save > /etc/iptables/rules.v4
|
||||
```
|
||||
|
||||
## Desplegar Edge Agent en Host Remoto
|
||||
|
||||
### Desde la Interfaz de Portainer
|
||||
|
||||
1. **Ir a Environments**:
|
||||
- Click en **Environments** en el menú lateral
|
||||
- Click en **Add environment**
|
||||
|
||||
2. **Seleccionar Tipo**:
|
||||
- Selecciona **Docker Standalone**
|
||||
- Click en **Start Wizard**
|
||||
|
||||
3. **Elegir Edge Agent**:
|
||||
- Selecciona la opción **Edge Agent**
|
||||
- Elige tu sistema operativo (Linux / Windows WSL / Windows WCS)
|
||||
|
||||
4. **Configurar Opciones**:
|
||||
- **Name**: Nombre descriptivo del entorno (ej: `produccion-server1`)
|
||||
- **Portainer server URL**: `https://portainer.tudominio.com` o `https://IP:9443`
|
||||
- **Edge ID**: Se genera automáticamente
|
||||
- **Polling interval**: Frecuencia de sincronización (por defecto 5 segundos)
|
||||
|
||||
5. **Copiar Comando**:
|
||||
|
||||
Portainer generará un comando similar a este:
|
||||
|
||||
**Linux / WSL**:
|
||||
```bash
|
||||
docker run -d \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
|
||||
-v /:/host \
|
||||
-v portainer_agent_data:/data \
|
||||
--restart always \
|
||||
-e EDGE=1 \
|
||||
-e EDGE_ID=<tu-edge-id> \
|
||||
-e EDGE_KEY=<tu-edge-key> \
|
||||
-e EDGE_INSECURE_POLL=0 \
|
||||
--name portainer_edge_agent \
|
||||
portainer/agent:latest
|
||||
```
|
||||
|
||||
**Windows WCS**:
|
||||
```powershell
|
||||
docker run -d `
|
||||
-v \\.\pipe\docker_engine:\\.\pipe\docker_engine `
|
||||
-v portainer_agent_data:C:\ProgramData\Portainer `
|
||||
--restart always `
|
||||
-e EDGE=1 `
|
||||
-e EDGE_ID=<tu-edge-id> `
|
||||
-e EDGE_KEY=<tu-edge-key> `
|
||||
--name portainer_edge_agent `
|
||||
portainer/agent:latest
|
||||
```
|
||||
|
||||
6. **Ejecutar en Host Remoto**:
|
||||
- Conéctate por SSH al host remoto
|
||||
- Pega y ejecuta el comando
|
||||
- Espera a que el contenedor se descargue e inicie
|
||||
|
||||
### Verificar Conexión
|
||||
|
||||
En el host remoto:
|
||||
|
||||
```bash
|
||||
# Ver logs del Edge Agent
|
||||
docker logs portainer_edge_agent
|
||||
|
||||
# Deberías ver mensajes como:
|
||||
# [INFO] Edge agent started
|
||||
# [INFO] Polling Portainer server
|
||||
# [INFO] Successfully connected to Portainer server
|
||||
```
|
||||
|
||||
En Portainer Server:
|
||||
|
||||
1. Ve a **Environments**
|
||||
2. El nuevo entorno debería aparecer con estado **Connected** (punto verde)
|
||||
3. Click en el entorno para gestionarlo
|
||||
|
||||
## Configuración Avanzada
|
||||
|
||||
### Intervalo de Polling Personalizado
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
# ... resto de opciones ...
|
||||
-e EDGE_POLL_INTERVAL=10s \ # Cambiar intervalo (default: 5s)
|
||||
portainer/agent:latest
|
||||
```
|
||||
|
||||
⚠️ **Nota**: Intervalos muy cortos aumentan el tráfico de red.
|
||||
|
||||
### Edge Agent con Host Management
|
||||
|
||||
Para habilitar funciones de gestión del host (CPU, memoria, procesos):
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
# ... resto de opciones ...
|
||||
-v /:/host \ # Montar filesystem del host
|
||||
portainer/agent:latest
|
||||
```
|
||||
|
||||
### Modo Inseguro (Solo para Desarrollo)
|
||||
|
||||
Si usas certificados autofirmados o HTTP:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
# ... resto de opciones ...
|
||||
-e EDGE_INSECURE_POLL=1 \ # ⚠️ NO usar en producción
|
||||
portainer/agent:latest
|
||||
```
|
||||
|
||||
### Edge Agent con Docker Compose
|
||||
|
||||
Crear `docker-compose.yaml` en el host remoto:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
portainer_edge_agent:
|
||||
image: portainer/agent:latest
|
||||
container_name: portainer_edge_agent
|
||||
restart: always
|
||||
environment:
|
||||
EDGE: "1"
|
||||
EDGE_ID: "<tu-edge-id>"
|
||||
EDGE_KEY: "<tu-edge-key>"
|
||||
EDGE_INSECURE_POLL: "0"
|
||||
EDGE_POLL_INTERVAL: "5s"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /var/lib/docker/volumes:/var/lib/docker/volumes
|
||||
- /:/host
|
||||
- portainer_agent_data:/data
|
||||
|
||||
volumes:
|
||||
portainer_agent_data:
|
||||
```
|
||||
|
||||
Desplegar:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Edge Groups y Tags
|
||||
|
||||
### Crear Edge Group
|
||||
|
||||
Los Edge Groups permiten agrupar múltiples entornos edge para gestión centralizada:
|
||||
|
||||
1. **Ir a Edge Groups**:
|
||||
- Menú lateral → **Edge Groups**
|
||||
- Click **Add edge group**
|
||||
|
||||
2. **Configurar Grupo**:
|
||||
- **Name**: Nombre del grupo (ej: `iot-devices`)
|
||||
- **Endpoints**: Seleccionar entornos edge a incluir
|
||||
- **Tags**: Opcional, para filtrado avanzado
|
||||
|
||||
3. **Deploy Stack a Grupo**:
|
||||
- Puedes desplegar stacks en todos los entornos del grupo simultáneamente
|
||||
- Los cambios se sincronizan automáticamente
|
||||
|
||||
## Edge Stacks
|
||||
|
||||
Los **Edge Stacks** son stacks Docker Compose que se despliegan en múltiples entornos edge:
|
||||
|
||||
1. **Crear Edge Stack**:
|
||||
- **Edge Compute** → **Edge Stacks** → **Add stack**
|
||||
|
||||
2. **Configurar Stack**:
|
||||
- **Name**: Nombre del stack
|
||||
- **Edge groups**: Seleccionar grupos target
|
||||
- **Compose file**: Pegar tu docker-compose.yaml
|
||||
|
||||
3. **Deployment type**:
|
||||
- **Static**: Se despliega una vez
|
||||
- **Git**: Se sincroniza desde un repo Git
|
||||
|
||||
4. **Pre-pull images**: Descargar imágenes antes de desplegar (recomendado)
|
||||
|
||||
## Edge Jobs
|
||||
|
||||
Ejecutar comandos en múltiples entornos edge:
|
||||
|
||||
1. **Crear Edge Job**:
|
||||
- **Edge Compute** → **Edge Jobs** → **Add edge job**
|
||||
|
||||
2. **Opciones**:
|
||||
- **Basic**: Comando simple
|
||||
- **Advanced**: Scripts complejos
|
||||
|
||||
3. **Scheduling**:
|
||||
- **One-off**: Se ejecuta una vez
|
||||
- **Recurring**: Programado (cron-like)
|
||||
|
||||
Ejemplo:
|
||||
|
||||
```bash
|
||||
# Actualizar todos los contenedores en entornos edge
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Edge Agent No Conecta
|
||||
|
||||
1. **Verificar firewall en servidor**:
|
||||
```bash
|
||||
sudo ufw status | grep 8000
|
||||
```
|
||||
|
||||
2. **Verificar puerto 8000 accesible**:
|
||||
Desde el host remoto:
|
||||
```bash
|
||||
telnet <portainer-server-ip> 8000
|
||||
# o
|
||||
nc -zv <portainer-server-ip> 8000
|
||||
```
|
||||
|
||||
3. **Revisar logs**:
|
||||
```bash
|
||||
docker logs portainer_edge_agent --tail 50
|
||||
```
|
||||
|
||||
### Certificado SSL Inválido
|
||||
|
||||
Si usas certificados autofirmados, usa `EDGE_INSECURE_POLL=1` (solo desarrollo):
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
# ... resto de opciones ...
|
||||
-e EDGE_INSECURE_POLL=1 \
|
||||
portainer/agent:latest
|
||||
```
|
||||
|
||||
### Edge Agent Se Desconecta Frecuentemente
|
||||
|
||||
1. **Aumentar timeout**:
|
||||
```bash
|
||||
-e EDGE_POLL_TIMEOUT=30s
|
||||
```
|
||||
|
||||
2. **Verificar estabilidad de red**:
|
||||
```bash
|
||||
ping -c 100 <portainer-server-ip>
|
||||
```
|
||||
|
||||
3. **Revisar recursos del host**:
|
||||
```bash
|
||||
docker stats portainer_edge_agent
|
||||
```
|
||||
|
||||
### Actualizar Edge Agent
|
||||
|
||||
```bash
|
||||
# Detener y eliminar contenedor actual
|
||||
docker stop portainer_edge_agent
|
||||
docker rm portainer_edge_agent
|
||||
|
||||
# Pull nueva imagen
|
||||
docker pull portainer/agent:latest
|
||||
|
||||
# Re-ejecutar comando de despliegue con las mismas variables EDGE_ID y EDGE_KEY
|
||||
```
|
||||
|
||||
⚠️ **Importante**: No cambies `EDGE_ID` o `EDGE_KEY`, o necesitarás re-agregar el entorno en Portainer.
|
||||
|
||||
## Seguridad
|
||||
|
||||
### Recomendaciones
|
||||
|
||||
1. ✅ **Usar HTTPS** con certificados válidos
|
||||
2. ✅ **NO usar** `EDGE_INSECURE_POLL=1` en producción
|
||||
3. ✅ **Limitar acceso** al puerto 8000 con firewall
|
||||
4. ✅ **Rotar Edge Keys** periódicamente (re-deploy agent)
|
||||
5. ✅ **Monitorizar logs** de conexiones sospechosas
|
||||
|
||||
### Exponer Solo con VPN (Alternativa Segura)
|
||||
|
||||
Si no quieres exponer el puerto 8000 a Internet:
|
||||
|
||||
1. **Configurar VPN** (WireGuard, OpenVPN, Tailscale)
|
||||
2. **Conectar hosts remotos** a la VPN
|
||||
3. **Configurar Portainer Server URL** con IP privada de VPN
|
||||
4. **Edge Agents** conectan a través del túnel VPN
|
||||
|
||||
---
|
||||
|
||||
**Recursos adicionales**:
|
||||
- [Documentación oficial Edge Compute](https://docs.portainer.io/admin/edge-compute)
|
||||
- [Edge Agent en GitHub](https://github.com/portainer/agent)
|
||||
|
||||
**Volver a**: [Página Principal](Home) | [Instalación Avanzada](Instalacion)
|
||||
104
Home.md
Normal file
104
Home.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Portainer CE - Documentación
|
||||
|
||||
Bienvenido a la documentación del despliegue de **Portainer Community Edition** usando Docker Compose.
|
||||
|
||||
## ¿Qué es Portainer?
|
||||
|
||||
Portainer es una plataforma de gestión de contenedores ligera y fácil de usar que te permite administrar tus entornos Docker, Kubernetes, y más a través de una interfaz web intuitiva.
|
||||
|
||||
## Componentes del Stack
|
||||
|
||||
Este repositorio despliega **Portainer Server** con la siguiente configuración:
|
||||
|
||||
### Servicio Principal
|
||||
- **Imagen**: `portainer/portainer-ce:lts`
|
||||
- **Contenedor**: `portainer`
|
||||
- **Reinicio**: Automático (`always`)
|
||||
|
||||
### Puertos Expuestos
|
||||
- **9443**: Interfaz web HTTPS de Portainer (obligatorio)
|
||||
- **8000**: Túnel TCP para Edge Agents (opcional, no incluido por defecto)
|
||||
|
||||
### Volúmenes
|
||||
- `/var/run/docker.sock:/var/run/docker.sock` - Socket Docker para gestión del host
|
||||
- `portainer_data:/data` - Almacenamiento persistente de configuración y datos
|
||||
|
||||
### Red
|
||||
- `portainer_network` - Red dedicada para el stack
|
||||
|
||||
## Requisitos Previos
|
||||
|
||||
Antes de desplegar Portainer, asegúrate de tener:
|
||||
|
||||
- ✅ Docker Engine instalado (versión compatible según [requisitos oficiales](https://docs.portainer.io/start/requirements-and-prerequisites))
|
||||
- ✅ Docker Compose instalado
|
||||
- ✅ Usuario con permisos para acceder a `/var/run/docker.sock`
|
||||
- ✅ Puertos 9443 (y opcionalmente 8000) disponibles
|
||||
- ✅ SELinux deshabilitado (Linux) o usar flag `--privileged` si es necesario
|
||||
|
||||
## Despliegue Rápido
|
||||
|
||||
### 1. Clonar el Repositorio
|
||||
|
||||
```bash
|
||||
git clone https://git.ictiberia.com/groales/portainer
|
||||
cd portainer
|
||||
```
|
||||
|
||||
### 2. Revisar Configuración (Opcional)
|
||||
|
||||
Edita `docker-compose.yaml` si necesitas personalizar puertos, redes o volúmenes.
|
||||
|
||||
### 3. Levantar el Stack
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 4. Verificar el Estado
|
||||
|
||||
```bash
|
||||
docker ps --filter name=portainer
|
||||
```
|
||||
|
||||
Deberías ver el contenedor `portainer` en estado `Up`.
|
||||
|
||||
### 5. Acceder a la Interfaz Web
|
||||
|
||||
Abre tu navegador en:
|
||||
|
||||
```
|
||||
https://<IP-del-servidor>:9443
|
||||
```
|
||||
|
||||
🔐 **Primera vez**: Portainer te pedirá crear un usuario administrador.
|
||||
|
||||
⚠️ **Certificado SSL**: Por defecto, Portainer usa un certificado autofirmado. Tu navegador mostrará una advertencia de seguridad. Para producción, configura certificados válidos (ver [Configuración SSL](#)).
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
- 📖 [Instalación Avanzada](Instalacion) - Configuración de TLS, variables de entorno y opciones avanzadas
|
||||
- 💾 [Backup y Restauración](Backup) - Cómo respaldar y restaurar datos de Portainer
|
||||
- 🌐 [Integración con Traefik](Traefik) - Configurar proxy inverso con TLS automático
|
||||
- 🔌 [Edge Agents](Edge-Agents) - Gestionar entornos remotos con agentes Edge
|
||||
|
||||
## Solución Rápida de Problemas
|
||||
|
||||
| Problema | Solución |
|
||||
|----------|----------|
|
||||
| Puerto 9443 ocupado | Cambia el puerto en `docker-compose.yaml`: `- "XXXX:9443"` |
|
||||
| Contenedor no arranca | Revisa logs: `docker logs portainer` |
|
||||
| No se puede conectar | Verifica firewall y que Docker esté corriendo |
|
||||
| Error de permisos socket | Añade tu usuario al grupo `docker`: `sudo usermod -aG docker $USER` |
|
||||
|
||||
## Recursos Oficiales
|
||||
|
||||
- 📘 [Documentación Oficial](https://docs.portainer.io/)
|
||||
- 🏠 [Sitio Web Portainer](https://www.portainer.io/)
|
||||
- 💬 [Comunidad](https://www.portainer.io/community)
|
||||
- 🐛 [Reportar Issues](https://github.com/portainer/portainer/issues)
|
||||
|
||||
---
|
||||
|
||||
**Versión**: Portainer CE LTS
|
||||
**Última actualización**: Noviembre 2025
|
||||
263
Instalacion.md
Normal file
263
Instalacion.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# Instalación Avanzada
|
||||
|
||||
Esta página cubre opciones avanzadas de instalación y configuración para Portainer CE.
|
||||
|
||||
## Configuración con Variables de Entorno
|
||||
|
||||
Puedes usar un archivo `.env` para gestionar variables de configuración. Crea el archivo en la raíz del proyecto:
|
||||
|
||||
```bash
|
||||
# .env
|
||||
PORTAINER_HTTPS_PORT=9443
|
||||
PORTAINER_EDGE_PORT=8000
|
||||
PORTAINER_DATA_VOLUME=portainer_data
|
||||
PORTAINER_NETWORK=portainer_network
|
||||
```
|
||||
|
||||
Luego referencia estas variables en `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
container_name: portainer
|
||||
image: portainer/portainer-ce:lts
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${PORTAINER_DATA_VOLUME:-portainer_data}:/data
|
||||
ports:
|
||||
- "${PORTAINER_HTTPS_PORT:-9443}:9443"
|
||||
# - "${PORTAINER_EDGE_PORT:-8000}:8000" # Descomenta para Edge Agents
|
||||
networks:
|
||||
- ${PORTAINER_NETWORK:-portainer_network}
|
||||
```
|
||||
|
||||
## Configuración de Certificados SSL/TLS
|
||||
|
||||
### Opción 1: Certificado Autofirmado (Por Defecto)
|
||||
|
||||
Portainer genera automáticamente un certificado autofirmado al iniciar. No requiere configuración adicional, pero los navegadores mostrarán advertencias de seguridad.
|
||||
|
||||
### Opción 2: Certificados Propios
|
||||
|
||||
Para usar tus propios certificados SSL:
|
||||
|
||||
1. **Prepara tus certificados**:
|
||||
- `cert.pem` - Certificado público
|
||||
- `key.pem` - Clave privada
|
||||
|
||||
2. **Crea una carpeta para certificados**:
|
||||
```bash
|
||||
mkdir -p ./certs
|
||||
cp /ruta/a/tu/cert.pem ./certs/
|
||||
cp /ruta/a/tu/key.pem ./certs/
|
||||
chmod 600 ./certs/*.pem
|
||||
```
|
||||
|
||||
3. **Modifica docker-compose.yaml**:
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
# ... configuración existente ...
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer_data:/data
|
||||
- ./certs:/certs:ro
|
||||
command: --sslcert /certs/cert.pem --sslkey /certs/key.pem
|
||||
```
|
||||
|
||||
4. **Reinicia Portainer**:
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Opción 3: Proxy Inverso con Let's Encrypt
|
||||
|
||||
La forma más profesional es usar un proxy inverso como Traefik o Nginx con certificados Let's Encrypt. Ver [Integración con Traefik](Traefik).
|
||||
|
||||
## Habilitar Edge Agents
|
||||
|
||||
Los Edge Agents permiten gestionar entornos Docker remotos que no tienen conectividad directa con Portainer Server.
|
||||
|
||||
### 1. Exponer Puerto 8000
|
||||
|
||||
Edita `docker-compose.yaml` y descomenta la línea del puerto 8000:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "9443:9443"
|
||||
- "8000:8000" # ← Descomentar esta línea
|
||||
```
|
||||
|
||||
### 2. Configurar Firewall
|
||||
|
||||
Asegúrate de que el puerto 8000 esté accesible desde tus agentes remotos:
|
||||
|
||||
```bash
|
||||
# Ejemplo con UFW (Ubuntu)
|
||||
sudo ufw allow 8000/tcp
|
||||
|
||||
# Ejemplo con firewall-cmd (RHEL/CentOS)
|
||||
sudo firewall-cmd --permanent --add-port=8000/tcp
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
### 3. Desplegar Edge Agent
|
||||
|
||||
Desde la interfaz de Portainer:
|
||||
1. Ve a **Environments** → **Add environment**
|
||||
2. Selecciona **Docker Standalone**
|
||||
3. Elige **Edge Agent**
|
||||
4. Copia el comando de instalación y ejecútalo en el host remoto
|
||||
|
||||
📖 Más información: [Documentación oficial de Edge Agents](https://docs.portainer.io/admin/environments/add/docker/edge)
|
||||
|
||||
## Configuración de SELinux
|
||||
|
||||
Si usas SELinux en Linux, necesitas ejecutar Portainer con el flag `--privileged`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
# ... configuración existente ...
|
||||
privileged: true
|
||||
```
|
||||
|
||||
O configurar políticas SELinux específicas (recomendado para producción):
|
||||
|
||||
```bash
|
||||
sudo semanage fcontext -a -t svirt_sandbox_file_t "/var/lib/docker/volumes/portainer_data(/.*)?"
|
||||
sudo restorecon -R /var/lib/docker/volumes/portainer_data
|
||||
```
|
||||
|
||||
## Docker Rootless
|
||||
|
||||
Portainer puede ejecutarse con Docker rootless, pero con algunas limitaciones:
|
||||
|
||||
1. **Montar socket rootless**:
|
||||
```yaml
|
||||
volumes:
|
||||
- $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
2. **Limitaciones conocidas**:
|
||||
- No se puede gestionar el host (stats, eventos del sistema)
|
||||
- Algunas funciones de networking pueden no funcionar
|
||||
- Host management features deshabilitadas
|
||||
|
||||
📖 Más información: [Docker Rootless](https://docs.docker.com/engine/security/rootless/)
|
||||
|
||||
## Despliegue con Docker Run
|
||||
|
||||
Si prefieres no usar Docker Compose:
|
||||
|
||||
```bash
|
||||
# Crear volumen
|
||||
docker volume create portainer_data
|
||||
|
||||
# Ejecutar Portainer
|
||||
docker run -d \
|
||||
-p 9443:9443 \
|
||||
--name portainer \
|
||||
--restart=always \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v portainer_data:/data \
|
||||
portainer/portainer-ce:lts
|
||||
```
|
||||
|
||||
## Configuración de Red Avanzada
|
||||
|
||||
### Usar Red Externa
|
||||
|
||||
Si ya tienes una red Docker existente:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
portainer_network:
|
||||
external: true
|
||||
name: mi_red_existente
|
||||
```
|
||||
|
||||
### IPv6
|
||||
|
||||
Para habilitar IPv6:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
portainer_network:
|
||||
enable_ipv6: true
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "fd00::/64"
|
||||
```
|
||||
|
||||
## Limitar Recursos
|
||||
|
||||
Para limitar CPU y memoria de Portainer:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
# ... configuración existente ...
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.5'
|
||||
memory: 256M
|
||||
```
|
||||
|
||||
## Configuración de Logging
|
||||
|
||||
Personalizar el driver de logs:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
# ... configuración existente ...
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
```
|
||||
|
||||
## Troubleshooting Avanzado
|
||||
|
||||
### Logs Detallados
|
||||
|
||||
Habilitar modo debug:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
# ... configuración existente ...
|
||||
command: --log-level=DEBUG
|
||||
```
|
||||
|
||||
### Verificar Conectividad al Socket Docker
|
||||
|
||||
```bash
|
||||
# Desde dentro del contenedor
|
||||
docker exec -it portainer ls -la /var/run/docker.sock
|
||||
|
||||
# Verificar permisos
|
||||
docker exec -it portainer stat -c '%a %U:%G' /var/run/docker.sock
|
||||
```
|
||||
|
||||
### Reset de Admin Password
|
||||
|
||||
Si olvidaste la contraseña del admin:
|
||||
|
||||
```bash
|
||||
docker stop portainer
|
||||
docker run --rm -v portainer_data:/data portainer/helper-reset-password
|
||||
docker start portainer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Próximos pasos**: [Backup y Restauración](Backup) | [Integración con Traefik](Traefik)
|
||||
549
Traefik.md
Normal file
549
Traefik.md
Normal file
@@ -0,0 +1,549 @@
|
||||
# Integración con Traefik
|
||||
|
||||
Esta guía explica cómo integrar Portainer CE con **Traefik** como proxy inverso para obtener:
|
||||
|
||||
- 🔒 **Certificados SSL/TLS automáticos** con Let's Encrypt
|
||||
- 🌐 **Acceso mediante dominio** en lugar de IP:puerto
|
||||
- 🔐 **Capa adicional de seguridad** con middlewares
|
||||
- 📊 **Balanceo de carga** (si usas múltiples instancias)
|
||||
|
||||
## Requisitos Previos
|
||||
|
||||
- ✅ Traefik instalado y funcionando
|
||||
- ✅ Red Docker compartida entre Traefik y Portainer
|
||||
- ✅ Dominio apuntando a tu servidor (para Let's Encrypt)
|
||||
- ✅ Puertos 80 y 443 accesibles desde Internet (para validación de Let's Encrypt)
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
Internet → Traefik (80/443) → Portainer (9443)
|
||||
↓
|
||||
Let's Encrypt
|
||||
```
|
||||
|
||||
Traefik gestiona:
|
||||
- Terminación SSL/TLS
|
||||
- Renovación automática de certificados
|
||||
- Redirección HTTP → HTTPS
|
||||
- Headers de seguridad
|
||||
|
||||
## Configuración Básica
|
||||
|
||||
### 1. Crear Red Compartida
|
||||
|
||||
Si no existe, crear una red para que Traefik y Portainer se comuniquen:
|
||||
|
||||
```bash
|
||||
docker network create traefik_network
|
||||
```
|
||||
|
||||
### 2. Modificar docker-compose.yaml de Portainer
|
||||
|
||||
Opción recomendada: usar `docker-compose.override.yaml` (ver abajo).
|
||||
|
||||
O editar directamente `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
container_name: portainer
|
||||
image: portainer/portainer-ce:lts
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer_data:/data
|
||||
# NO exponer puertos directamente
|
||||
# ports:
|
||||
# - "9443:9443"
|
||||
networks:
|
||||
- portainer_network
|
||||
- traefik_network # Añadir red de Traefik
|
||||
labels:
|
||||
# Habilitar Traefik
|
||||
- "traefik.enable=true"
|
||||
|
||||
# Router HTTP (redirección a HTTPS)
|
||||
- "traefik.http.routers.portainer-http.rule=Host(`portainer.tudominio.com`)"
|
||||
- "traefik.http.routers.portainer-http.entrypoints=web"
|
||||
- "traefik.http.routers.portainer-http.middlewares=redirect-to-https"
|
||||
|
||||
# Router HTTPS
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
|
||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||
- "traefik.http.routers.portainer.tls=true"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||
|
||||
# Service
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
|
||||
|
||||
# Middleware de redirección
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
|
||||
|
||||
volumes:
|
||||
portainer_data:
|
||||
name: portainer_data
|
||||
|
||||
networks:
|
||||
portainer_network:
|
||||
name: portainer_network
|
||||
traefik_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
### 3. Usar docker-compose.override.yaml (Recomendado)
|
||||
|
||||
En el repositorio ya existe `docker-compose.override.yaml.example`. Copiarlo:
|
||||
|
||||
```bash
|
||||
cp docker-compose.override.yaml.example docker-compose.override.yaml
|
||||
```
|
||||
|
||||
Editar `docker-compose.override.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
portainer:
|
||||
networks:
|
||||
- traefik_network
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.portainer-http.rule=Host(`portainer.tudominio.com`)"
|
||||
- "traefik.http.routers.portainer-http.entrypoints=web"
|
||||
- "traefik.http.routers.portainer-http.middlewares=redirect-to-https"
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
|
||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||
- "traefik.http.routers.portainer.tls=true"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
|
||||
- "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
|
||||
|
||||
networks:
|
||||
traefik_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
**Ventaja**: El `docker-compose.yaml` base permanece sin cambios, y los overrides se aplican automáticamente.
|
||||
|
||||
### 4. Reiniciar Portainer
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 5. Verificar
|
||||
|
||||
```bash
|
||||
# Ver logs de Traefik
|
||||
docker logs traefik
|
||||
|
||||
# Verificar que Portainer está en la red de Traefik
|
||||
docker network inspect traefik_network
|
||||
```
|
||||
|
||||
Acceder a: `https://portainer.tudominio.com`
|
||||
|
||||
## Configuración de Traefik
|
||||
|
||||
### traefik.yml Mínimo
|
||||
|
||||
Si aún no tienes Traefik configurado, aquí un ejemplo básico:
|
||||
|
||||
```yaml
|
||||
# traefik.yml
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: false
|
||||
|
||||
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: admin@tudominio.com
|
||||
storage: /letsencrypt/acme.json
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
### docker-compose.yml de Traefik
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:latest
|
||||
container_name: traefik
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080" # Dashboard (proteger en producción)
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik.yml:/traefik.yml:ro
|
||||
- ./letsencrypt:/letsencrypt
|
||||
networks:
|
||||
- traefik_network
|
||||
labels:
|
||||
# Dashboard (opcional, configurar autenticación)
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.tudominio.com`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls=true"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.traefik.service=api@internal"
|
||||
|
||||
networks:
|
||||
traefik_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
Iniciar Traefik:
|
||||
|
||||
```bash
|
||||
docker network create traefik_network
|
||||
mkdir letsencrypt
|
||||
touch letsencrypt/acme.json
|
||||
chmod 600 letsencrypt/acme.json
|
||||
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Configuración Avanzada
|
||||
|
||||
### Autenticación Básica (Opcional)
|
||||
|
||||
Proteger Portainer con autenticación HTTP básica:
|
||||
|
||||
```bash
|
||||
# Generar password hash
|
||||
echo $(htpasswd -nb admin tu_password) | sed -e s/\\$/\\$\\$/g
|
||||
# Resultado: admin:$$apr1$$...
|
||||
```
|
||||
|
||||
Añadir labels:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# ... labels existentes ...
|
||||
- "traefik.http.routers.portainer.middlewares=portainer-auth"
|
||||
- "traefik.http.middlewares.portainer-auth.basicauth.users=admin:$$apr1$$..."
|
||||
```
|
||||
|
||||
### Headers de Seguridad
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# ... labels existentes ...
|
||||
- "traefik.http.routers.portainer.middlewares=security-headers"
|
||||
- "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
|
||||
- "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.stsPreload=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.forceSTSHeader=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.frameDeny=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
Limitar peticiones para prevenir abusos:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# ... labels existentes ...
|
||||
- "traefik.http.routers.portainer.middlewares=rate-limit"
|
||||
- "traefik.http.middlewares.rate-limit.ratelimit.average=100"
|
||||
- "traefik.http.middlewares.rate-limit.ratelimit.burst=50"
|
||||
```
|
||||
|
||||
### IP Whitelist
|
||||
|
||||
Restringir acceso solo desde IPs específicas:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# ... labels existentes ...
|
||||
- "traefik.http.routers.portainer.middlewares=ip-whitelist"
|
||||
- "traefik.http.middlewares.ip-whitelist.ipwhitelist.sourcerange=192.168.1.0/24,10.0.0.0/8"
|
||||
```
|
||||
|
||||
### Múltiples Dominios
|
||||
|
||||
Acceder a Portainer desde varios dominios:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`) || Host(`docker.tudominio.com`)"
|
||||
```
|
||||
|
||||
### Configuración con Subdirectorio
|
||||
|
||||
Acceder en `https://tudominio.com/portainer`:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.portainer.rule=Host(`tudominio.com`) && PathPrefix(`/portainer`)"
|
||||
- "traefik.http.routers.portainer.middlewares=portainer-stripprefix"
|
||||
- "traefik.http.middlewares.portainer-stripprefix.stripprefix.prefixes=/portainer"
|
||||
```
|
||||
|
||||
⚠️ **Nota**: Portainer puede tener problemas con subdirectorios. Recomendamos usar subdominios.
|
||||
|
||||
## Wildcard Certificates
|
||||
|
||||
Para certificados wildcard con DNS challenge:
|
||||
|
||||
```yaml
|
||||
# traefik.yml
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: admin@tudominio.com
|
||||
storage: /letsencrypt/acme.json
|
||||
dnsChallenge:
|
||||
provider: cloudflare # O tu proveedor DNS
|
||||
delayBeforeCheck: 30
|
||||
```
|
||||
|
||||
Variables de entorno para Cloudflare:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml de Traefik
|
||||
services:
|
||||
traefik:
|
||||
environment:
|
||||
- CF_API_EMAIL=tu@email.com
|
||||
- CF_API_KEY=tu_api_key
|
||||
```
|
||||
|
||||
Labels en Portainer:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.portainer.tls.domains[0].main=tudominio.com"
|
||||
- "traefik.http.routers.portainer.tls.domains[0].sans=*.tudominio.com"
|
||||
```
|
||||
|
||||
## Docker Compose Completo
|
||||
|
||||
### Portainer con Traefik
|
||||
|
||||
Archivo completo `docker-compose.override.yaml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
portainer:
|
||||
networks:
|
||||
- traefik_network
|
||||
labels:
|
||||
# Habilitar Traefik
|
||||
- "traefik.enable=true"
|
||||
|
||||
# Dominio
|
||||
- "traefik.http.routers.portainer.rule=Host(`portainer.tudominio.com`)"
|
||||
|
||||
# Entrypoints
|
||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||
|
||||
# TLS
|
||||
- "traefik.http.routers.portainer.tls=true"
|
||||
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||
|
||||
# Service backend
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
|
||||
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
|
||||
|
||||
# Middlewares (opcional)
|
||||
- "traefik.http.routers.portainer.middlewares=security-headers"
|
||||
- "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
|
||||
- "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.frameDeny=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
|
||||
- "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
|
||||
|
||||
networks:
|
||||
traefik_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Certificado No Se Genera
|
||||
|
||||
1. **Verificar logs de Traefik**:
|
||||
```bash
|
||||
docker logs traefik | grep -i error
|
||||
```
|
||||
|
||||
2. **Revisar permisos de acme.json**:
|
||||
```bash
|
||||
chmod 600 letsencrypt/acme.json
|
||||
```
|
||||
|
||||
3. **Verificar DNS**:
|
||||
```bash
|
||||
nslookup portainer.tudominio.com
|
||||
dig portainer.tudominio.com
|
||||
```
|
||||
|
||||
4. **Rate limits de Let's Encrypt**:
|
||||
- Máximo 5 certificados por semana por dominio
|
||||
- Usar staging durante pruebas:
|
||||
```yaml
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
```
|
||||
|
||||
### Error 502 Bad Gateway
|
||||
|
||||
1. **Verificar que Portainer está corriendo**:
|
||||
```bash
|
||||
docker ps | grep portainer
|
||||
```
|
||||
|
||||
2. **Verificar red compartida**:
|
||||
```bash
|
||||
docker network inspect traefik_network | grep portainer
|
||||
```
|
||||
|
||||
3. **Revisar puerto del servicio**:
|
||||
```yaml
|
||||
# Asegurarse de usar el puerto interno correcto
|
||||
- "traefik.http.services.portainer.loadbalancer.server.port=9443"
|
||||
```
|
||||
|
||||
4. **Verificar scheme HTTPS**:
|
||||
```yaml
|
||||
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
|
||||
```
|
||||
|
||||
### Redirección Infinita
|
||||
|
||||
Si hay loop de redirecciones:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# Remover redirección HTTP si Traefik ya lo maneja globalmente
|
||||
# Comentar estas líneas:
|
||||
# - "traefik.http.routers.portainer-http.rule=..."
|
||||
# - "traefik.http.routers.portainer-http.middlewares=redirect-to-https"
|
||||
```
|
||||
|
||||
### Certificado Autofirmado Aún Se Muestra
|
||||
|
||||
Portainer usa su propio certificado SSL. Traefik termina SSL antes de llegar a Portainer, por lo que:
|
||||
|
||||
1. **Es normal** que Portainer siga usando su cert autofirmado internamente
|
||||
2. El usuario final ve el certificado de Let's Encrypt de Traefik
|
||||
3. Traefik se comunica con Portainer por HTTPS (con cert autofirmado)
|
||||
|
||||
Si quieres evitar warnings en logs de Traefik:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.services.portainer.loadbalancer.server.scheme=https"
|
||||
- "traefik.http.services.portainer.loadbalancer.serversTransport=ignorecert"
|
||||
|
||||
# En traefik.yml:
|
||||
# http:
|
||||
# serversTransports:
|
||||
# ignorecert:
|
||||
# insecureSkipVerify: true
|
||||
```
|
||||
|
||||
## Monitorización
|
||||
|
||||
### Logs de Traefik
|
||||
|
||||
```bash
|
||||
# Ver requests a Portainer
|
||||
docker logs -f traefik | grep portainer
|
||||
|
||||
# Ver errores TLS
|
||||
docker logs traefik | grep -i "tls\|certificate"
|
||||
```
|
||||
|
||||
### Verificar Certificado SSL
|
||||
|
||||
```bash
|
||||
# Ver información del certificado
|
||||
echo | openssl s_client -servername portainer.tudominio.com -connect localhost:443 2>/dev/null | openssl x509 -noout -dates
|
||||
|
||||
# Verificar desde exterior
|
||||
curl -vI https://portainer.tudominio.com 2>&1 | grep -i "SSL\|certificate"
|
||||
```
|
||||
|
||||
## Seguridad Adicional
|
||||
|
||||
### 1. Fail2ban con Traefik
|
||||
|
||||
Proteger contra brute-force:
|
||||
|
||||
```bash
|
||||
# /etc/fail2ban/filter.d/traefik-auth.conf
|
||||
[Definition]
|
||||
failregex = ^<HOST> - - .* "(GET|POST|HEAD).*HTTP.*" 401 .*$
|
||||
ignoreregex =
|
||||
```
|
||||
|
||||
```ini
|
||||
# /etc/fail2ban/jail.local
|
||||
[traefik-auth]
|
||||
enabled = true
|
||||
port = http,https
|
||||
logpath = /var/log/traefik/access.log
|
||||
maxretry = 5
|
||||
bantime = 3600
|
||||
```
|
||||
|
||||
### 2. Autenticación de Dos Factores
|
||||
|
||||
Portainer tiene 2FA integrado (no depende de Traefik):
|
||||
|
||||
1. **Settings** → **Authentication**
|
||||
2. Habilitar **OAuth** o **LDAP** con 2FA
|
||||
3. O usar middleware de Traefik con OAuth2 Proxy
|
||||
|
||||
### 3. VPN como Alternativa
|
||||
|
||||
Para máxima seguridad, no exponer Portainer a Internet:
|
||||
|
||||
1. Acceso solo via VPN (WireGuard, OpenVPN)
|
||||
2. Traefik escucha solo en IP privada
|
||||
3. Usuarios conectan primero a VPN
|
||||
|
||||
---
|
||||
|
||||
**Recursos adicionales**:
|
||||
- [Documentación Traefik](https://doc.traefik.io/traefik/)
|
||||
- [Let's Encrypt Rate Limits](https://letsencrypt.org/docs/rate-limits/)
|
||||
- [Traefik Middlewares](https://doc.traefik.io/traefik/middlewares/overview/)
|
||||
|
||||
**Volver a**: [Página Principal](Home) | [Instalación Avanzada](Instalacion)
|
||||
Reference in New Issue
Block a user