Documentación completa de NGINX Proxy Manager en español
464
Backup.md
Normal file
464
Backup.md
Normal file
@@ -0,0 +1,464 @@
|
||||
# Backup y Restauración
|
||||
|
||||
## ¿Qué se Respalda?
|
||||
|
||||
NGINX Proxy Manager almacena datos en dos volúmenes Docker:
|
||||
|
||||
### `npm_data` (`/data`)
|
||||
- 📊 **Base de datos SQLite** (o configuración de DB externa)
|
||||
- ⚙️ **Configuración de proxy hosts, redirects, streams**
|
||||
- 🔑 **Access lists, usuarios, permisos**
|
||||
- 📝 **Logs de acceso y errores**
|
||||
- 🔧 **Configuraciones NGINX custom**
|
||||
|
||||
### `npm_letsencrypt` (`/etc/letsencrypt`)
|
||||
- 🔒 **Certificados SSL de Let's Encrypt**
|
||||
- 🔑 **Claves privadas**
|
||||
- 📜 **Configuración de renovación automática**
|
||||
|
||||
⚠️ **Crítico**: Ambos volúmenes contienen información sensible. Protege los backups adecuadamente.
|
||||
|
||||
## Backup Manual
|
||||
|
||||
### Método 1: Backup de Volúmenes (Recomendado)
|
||||
|
||||
```bash
|
||||
# Detener NPM (opcional, para consistencia)
|
||||
docker compose down
|
||||
|
||||
# Backup de npm_data
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/npm_data-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
|
||||
|
||||
# Backup de npm_letsencrypt
|
||||
docker run --rm \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/npm_letsencrypt-$(date +%Y%m%d-%H%M%S).tar.gz -C /letsencrypt .
|
||||
|
||||
# Reiniciar NPM
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Método 2: Backup en Caliente
|
||||
|
||||
Sin detener el servicio:
|
||||
|
||||
```bash
|
||||
# Backup de npm_data (servicio corriendo)
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/npm_data-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
|
||||
|
||||
# Backup de npm_letsencrypt
|
||||
docker run --rm \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/npm_letsencrypt-$(date +%Y%m%d-%H%M%S).tar.gz -C /letsencrypt .
|
||||
```
|
||||
|
||||
⚠️ **Nota**: Backups en caliente pueden tener inconsistencias en la base de datos si hay escrituras durante la copia.
|
||||
|
||||
### Método 3: Backup de Carpetas Locales
|
||||
|
||||
Si usas bind mounts en lugar de volúmenes:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yaml con bind mounts
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./letsencrypt:/etc/letsencrypt
|
||||
```
|
||||
|
||||
```bash
|
||||
# Backup simple
|
||||
tar czf npm-backup-$(date +%Y%m%d-%H%M%S).tar.gz data/ letsencrypt/
|
||||
|
||||
# O con rsync
|
||||
rsync -av data/ /ruta/backup/npm/data/
|
||||
rsync -av letsencrypt/ /ruta/backup/npm/letsencrypt/
|
||||
```
|
||||
|
||||
## Restauración
|
||||
|
||||
### Restaurar desde Backup
|
||||
|
||||
```bash
|
||||
# 1. Detener NPM si está corriendo
|
||||
docker compose down
|
||||
|
||||
# 2. Eliminar volúmenes existentes (⚠️ cuidado!)
|
||||
docker volume rm npm_data npm_letsencrypt
|
||||
|
||||
# 3. Crear volúmenes nuevos
|
||||
docker volume create npm_data
|
||||
docker volume create npm_letsencrypt
|
||||
|
||||
# 4. Restaurar npm_data
|
||||
docker run --rm \
|
||||
-v npm_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/npm_data-YYYYMMDD-HHMMSS.tar.gz -C /data
|
||||
|
||||
# 5. Restaurar npm_letsencrypt
|
||||
docker run --rm \
|
||||
-v npm_letsencrypt:/letsencrypt \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar xzf /backup/npm_letsencrypt-YYYYMMDD-HHMMSS.tar.gz -C /letsencrypt
|
||||
|
||||
# 6. Verificar permisos
|
||||
docker run --rm \
|
||||
-v npm_data:/data \
|
||||
alpine \
|
||||
chown -R root:root /data
|
||||
|
||||
# 7. Reiniciar NPM
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Verificar Restauración
|
||||
|
||||
```bash
|
||||
# Ver logs
|
||||
docker logs -f nginx-proxy-manager
|
||||
|
||||
# Debería ver:
|
||||
# [setup ] Starting backend
|
||||
# [nginx ] Starting nginx
|
||||
|
||||
# Acceder a UI
|
||||
# http://IP:81
|
||||
```
|
||||
|
||||
## Backup Automatizado
|
||||
|
||||
### Script de Backup
|
||||
|
||||
Crear `backup-npm.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Configuración
|
||||
BACKUP_DIR="/var/backups/nginx-proxy-manager"
|
||||
RETENTION_DAYS=30
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
# Crear directorio si no existe
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo "[$(date)] Iniciando backup de NGINX Proxy Manager..."
|
||||
|
||||
# Backup de volúmenes
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v "$BACKUP_DIR":/backup \
|
||||
alpine \
|
||||
tar czf "/backup/npm_data-$TIMESTAMP.tar.gz" -C /data .
|
||||
|
||||
docker run --rm \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v "$BACKUP_DIR":/backup \
|
||||
alpine \
|
||||
tar czf "/backup/npm_letsencrypt-$TIMESTAMP.tar.gz" -C /letsencrypt .
|
||||
|
||||
# Verificar backups
|
||||
if [ -f "$BACKUP_DIR/npm_data-$TIMESTAMP.tar.gz" ] && [ -f "$BACKUP_DIR/npm_letsencrypt-$TIMESTAMP.tar.gz" ]; then
|
||||
SIZE_DATA=$(du -h "$BACKUP_DIR/npm_data-$TIMESTAMP.tar.gz" | cut -f1)
|
||||
SIZE_LE=$(du -h "$BACKUP_DIR/npm_letsencrypt-$TIMESTAMP.tar.gz" | cut -f1)
|
||||
echo "[$(date)] Backup completado:"
|
||||
echo " - npm_data: $SIZE_DATA"
|
||||
echo " - npm_letsencrypt: $SIZE_LE"
|
||||
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 "npm_*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||||
|
||||
echo "[$(date)] Proceso completado"
|
||||
```
|
||||
|
||||
Hacer ejecutable:
|
||||
|
||||
```bash
|
||||
chmod +x backup-npm.sh
|
||||
./backup-npm.sh
|
||||
```
|
||||
|
||||
### Programar con Cron
|
||||
|
||||
Backup diario a las 3:00 AM:
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
|
||||
# Añadir línea:
|
||||
0 3 * * * /ruta/a/backup-npm.sh >> /var/log/npm-backup.log 2>&1
|
||||
```
|
||||
|
||||
Ver logs:
|
||||
|
||||
```bash
|
||||
tail -f /var/log/npm-backup.log
|
||||
```
|
||||
|
||||
## Backup a Almacenamiento Remoto
|
||||
|
||||
### rsync a Servidor Remoto
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
BACKUP_FILE="npm-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
# Crear backup local
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
sh -c "tar czf /backup/$BACKUP_FILE -C / data letsencrypt"
|
||||
|
||||
# Copiar a servidor remoto
|
||||
rsync -avz --progress "$BACKUP_FILE" usuario@servidor-backup:/backups/npm/
|
||||
|
||||
# Opcional: eliminar backup local
|
||||
rm "$BACKUP_FILE"
|
||||
```
|
||||
|
||||
### S3 / MinIO con rclone
|
||||
|
||||
```bash
|
||||
# Configurar rclone (una vez)
|
||||
rclone config
|
||||
|
||||
# Script de backup a S3
|
||||
BACKUP_FILE="npm-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
sh -c "tar czf /backup/$BACKUP_FILE -C / data letsencrypt"
|
||||
|
||||
rclone copy "$BACKUP_FILE" s3-remote:bucket-name/npm-backups/
|
||||
rm "$BACKUP_FILE"
|
||||
```
|
||||
|
||||
### Backup a NFS/CIFS
|
||||
|
||||
```bash
|
||||
# Montar share NFS
|
||||
mount -t nfs servidor.local:/backups /mnt/backups
|
||||
|
||||
# Backup directo a share
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v /mnt/backups:/backup \
|
||||
alpine \
|
||||
tar czf /backup/npm-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C / data letsencrypt
|
||||
```
|
||||
|
||||
## Migración a Nuevo Servidor
|
||||
|
||||
### En el Servidor Antiguo
|
||||
|
||||
```bash
|
||||
# Crear backup completo
|
||||
docker run --rm \
|
||||
-v npm_data:/data:ro \
|
||||
-v npm_letsencrypt:/letsencrypt:ro \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
tar czf /backup/npm-migration.tar.gz -C / data letsencrypt
|
||||
|
||||
# Copiar a nuevo servidor
|
||||
scp npm-migration.tar.gz usuario@nuevo-servidor:/tmp/
|
||||
```
|
||||
|
||||
### En el Servidor Nuevo
|
||||
|
||||
```bash
|
||||
# 1. Clonar repositorio
|
||||
git clone https://git.ictiberia.com/groales/npm
|
||||
cd npm
|
||||
|
||||
# 2. Crear volúmenes
|
||||
docker volume create npm_data
|
||||
docker volume create npm_letsencrypt
|
||||
|
||||
# 3. Restaurar backup
|
||||
docker run --rm \
|
||||
-v npm_data:/data \
|
||||
-v npm_letsencrypt:/letsencrypt \
|
||||
-v /tmp:/backup \
|
||||
alpine \
|
||||
tar xzf /backup/npm-migration.tar.gz -C /
|
||||
|
||||
# 4. Iniciar NPM
|
||||
docker compose up -d
|
||||
|
||||
# 5. Verificar
|
||||
docker logs -f nginx-proxy-manager
|
||||
```
|
||||
|
||||
## Exportar/Importar Configuración
|
||||
|
||||
### Solo Base de Datos (SQLite)
|
||||
|
||||
```bash
|
||||
# Exportar solo DB
|
||||
docker exec nginx-proxy-manager \
|
||||
sqlite3 /data/database.sqlite .dump > npm-database-$(date +%Y%m%d).sql
|
||||
|
||||
# Importar DB
|
||||
cat npm-database-YYYYMMDD.sql | docker exec -i nginx-proxy-manager \
|
||||
sqlite3 /data/database.sqlite
|
||||
```
|
||||
|
||||
## Reset de Contraseña Admin
|
||||
|
||||
Si olvidaste la contraseña:
|
||||
|
||||
```bash
|
||||
# Método 1: Resetear a credenciales por defecto
|
||||
docker compose down
|
||||
|
||||
# Ejecutar container temporal con script reset
|
||||
docker run --rm \
|
||||
-v npm_data:/data \
|
||||
jc21/nginx-proxy-manager:latest \
|
||||
npx knex migrate:latest --env production && npx knex seed:run --env production
|
||||
|
||||
docker compose up -d
|
||||
|
||||
# Login con:
|
||||
# Email: admin@example.com
|
||||
# Password: changeme
|
||||
```
|
||||
|
||||
Método 2: SQL directo (solo SQLite):
|
||||
|
||||
```bash
|
||||
docker exec -it nginx-proxy-manager /bin/bash
|
||||
|
||||
# Dentro del contenedor
|
||||
sqlite3 /data/database.sqlite
|
||||
|
||||
-- Resetear password a 'changeme'
|
||||
UPDATE auth SET secret = '$2a$10$YSwA4rB7M/xE8N1n8YCfCuYZ.9cNrwMr/L/PkZ.qXHfEqNkFN7XCy' WHERE id = 1;
|
||||
|
||||
.exit
|
||||
exit
|
||||
|
||||
# Reiniciar
|
||||
docker restart nginx-proxy-manager
|
||||
```
|
||||
|
||||
## Verificación de Integridad
|
||||
|
||||
### Test de Restauración
|
||||
|
||||
```bash
|
||||
# 1. Crear volúmenes de test
|
||||
docker volume create npm_data_test
|
||||
docker volume create npm_letsencrypt_test
|
||||
|
||||
# 2. Restaurar en volúmenes test
|
||||
docker run --rm \
|
||||
-v npm_data_test:/data \
|
||||
-v npm_letsencrypt_test:/letsencrypt \
|
||||
-v $(pwd):/backup \
|
||||
alpine \
|
||||
sh -c "tar xzf /backup/npm_data-BACKUP.tar.gz -C /data && tar xzf /backup/npm_letsencrypt-BACKUP.tar.gz -C /letsencrypt"
|
||||
|
||||
# 3. Iniciar NPM temporal
|
||||
docker run -d \
|
||||
-p 18081:81 \
|
||||
--name npm-test \
|
||||
-v npm_data_test:/data \
|
||||
-v npm_letsencrypt_test:/etc/letsencrypt \
|
||||
jc21/nginx-proxy-manager:latest
|
||||
|
||||
# 4. Verificar en http://localhost:18081
|
||||
|
||||
# 5. Limpiar
|
||||
docker stop npm-test
|
||||
docker rm npm-test
|
||||
docker volume rm npm_data_test npm_letsencrypt_test
|
||||
```
|
||||
|
||||
### Validar Tar
|
||||
|
||||
```bash
|
||||
# Verificar integridad
|
||||
tar tzf npm_data-YYYYMMDD-HHMMSS.tar.gz > /dev/null
|
||||
echo $? # Debe devolver 0
|
||||
|
||||
# Ver contenido
|
||||
tar tzf npm_data-YYYYMMDD-HHMMSS.tar.gz | head -20
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Estrategia 3-2-1
|
||||
|
||||
- ✅ **3 copias** de datos (original + 2 backups)
|
||||
- ✅ **2 tipos de medios** (local + remoto)
|
||||
- ✅ **1 copia offsite** (cloud, otro datacenter)
|
||||
|
||||
### Frecuencia Recomendada
|
||||
|
||||
| Uso | Frecuencia |
|
||||
|-----|------------|
|
||||
| Producción crítica | Cada 6 horas |
|
||||
| Producción | Diario |
|
||||
| Personal/Home | Semanal |
|
||||
|
||||
### Retención
|
||||
|
||||
Ejemplo:
|
||||
- Diarios: 7 días
|
||||
- Semanales: 4 semanas
|
||||
- Mensuales: 12 meses
|
||||
|
||||
### Encriptación
|
||||
|
||||
Para backups sensibles:
|
||||
|
||||
```bash
|
||||
# Backup encriptado con GPG
|
||||
BACKUP_FILE="npm-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
# Crear backup
|
||||
docker run --rm ... tar czf /backup/$BACKUP_FILE ...
|
||||
|
||||
# Encriptar
|
||||
gpg --symmetric --cipher-algo AES256 "$BACKUP_FILE"
|
||||
|
||||
# Resultado: npm-backup-YYYYMMDD-HHMMSS.tar.gz.gpg
|
||||
rm "$BACKUP_FILE"
|
||||
```
|
||||
|
||||
Desencriptar:
|
||||
|
||||
```bash
|
||||
gpg --decrypt npm-backup-YYYYMMDD-HHMMSS.tar.gz.gpg > npm-backup.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Volver a**: [Página Principal](Home) | [Configuración Avanzada](Configuracion)
|
||||
341
Configuracion.md
Normal file
341
Configuracion.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# Configuración Avanzada
|
||||
|
||||
## Base de Datos Externa
|
||||
|
||||
### MySQL / MariaDB
|
||||
|
||||
Para mayor rendimiento y escalabilidad, usa MySQL/MariaDB en lugar de SQLite:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: jc21/nginx-proxy-manager:latest
|
||||
environment:
|
||||
TZ: "Europe/Madrid"
|
||||
DB_MYSQL_HOST: "db"
|
||||
DB_MYSQL_PORT: 3306
|
||||
DB_MYSQL_USER: "npm"
|
||||
DB_MYSQL_PASSWORD: "npm_password"
|
||||
DB_MYSQL_NAME: "npm"
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: jc21/mariadb-aria:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "root_password"
|
||||
MYSQL_DATABASE: "npm"
|
||||
MYSQL_USER: "npm"
|
||||
MYSQL_PASSWORD: "npm_password"
|
||||
MARIADB_AUTO_UPGRADE: "1"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
|
||||
volumes:
|
||||
npm_data:
|
||||
npm_letsencrypt:
|
||||
mysql_data:
|
||||
```
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
DB_POSTGRES_HOST: "db"
|
||||
DB_POSTGRES_PORT: "5432"
|
||||
DB_POSTGRES_USER: "npm"
|
||||
DB_POSTGRES_PASSWORD: "npm_password"
|
||||
DB_POSTGRES_NAME: "npm"
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: postgres:17
|
||||
environment:
|
||||
POSTGRES_USER: "npm"
|
||||
POSTGRES_PASSWORD: "npm_password"
|
||||
POSTGRES_DB: "npm"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql
|
||||
|
||||
volumes:
|
||||
npm_data:
|
||||
npm_letsencrypt:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
## Docker Secrets
|
||||
|
||||
Para mayor seguridad, usa secrets en lugar de variables de entorno en texto plano:
|
||||
|
||||
```yaml
|
||||
secrets:
|
||||
mysql_pwd:
|
||||
file: ./secrets/mysql_password.txt
|
||||
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
DB_MYSQL_HOST: "db"
|
||||
DB_MYSQL_PORT: 3306
|
||||
DB_MYSQL_USER: "npm"
|
||||
DB_MYSQL_PASSWORD__FILE: /run/secrets/mysql_pwd
|
||||
DB_MYSQL_NAME: "npm"
|
||||
secrets:
|
||||
- mysql_pwd
|
||||
```
|
||||
|
||||
## Redes Docker
|
||||
|
||||
### Conectar NPM con Otros Servicios
|
||||
|
||||
Crear red compartida:
|
||||
|
||||
```bash
|
||||
docker network create proxy_network
|
||||
```
|
||||
|
||||
NPM:
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
networks:
|
||||
- proxy_network
|
||||
- npm_network
|
||||
|
||||
networks:
|
||||
npm_network:
|
||||
name: npm_network
|
||||
proxy_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
Otros servicios:
|
||||
```yaml
|
||||
services:
|
||||
mi_app:
|
||||
networks:
|
||||
- proxy_network
|
||||
|
||||
networks:
|
||||
proxy_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
Configurar Proxy Host:
|
||||
- **Forward Hostname**: `mi_app` (nombre del contenedor)
|
||||
- **Forward Port**: Puerto interno (no necesitas publicarlo con `-p`)
|
||||
|
||||
## Configuraciones NGINX Personalizadas
|
||||
|
||||
NPM permite insertar configuración NGINX personalizada en diferentes ubicaciones.
|
||||
|
||||
### Ubicaciones de Archivos Custom
|
||||
|
||||
Crear directorio: `./data/nginx/custom/` (se monta desde volumen `npm_data`)
|
||||
|
||||
Archivos disponibles:
|
||||
- `root_top.conf` - Top de nginx.conf
|
||||
- `root.conf` - Final de nginx.conf
|
||||
- `http_top.conf` - Top del bloque http
|
||||
- `http.conf` - Final del bloque http
|
||||
- `events.conf` - Final del bloque events
|
||||
- `stream.conf` - Final del bloque stream
|
||||
- `server_proxy.conf` - Final de cada servidor proxy
|
||||
- `server_redirect.conf` - Final de cada servidor de redirección
|
||||
- `server_stream.conf` - Final de cada stream
|
||||
- `server_dead.conf` - Final de cada servidor 404
|
||||
|
||||
### Ejemplo: Rate Limiting Global
|
||||
|
||||
```bash
|
||||
# Acceder al contenedor
|
||||
docker exec -it nginx-proxy-manager /bin/bash
|
||||
|
||||
# Crear archivo custom
|
||||
cat > /data/nginx/custom/http_top.conf << 'EOF'
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
|
||||
limit_req_status 429;
|
||||
EOF
|
||||
|
||||
# Salir y recargar NGINX
|
||||
exit
|
||||
docker exec nginx-proxy-manager nginx -s reload
|
||||
```
|
||||
|
||||
Aplicar en Proxy Host (pestaña Advanced):
|
||||
```nginx
|
||||
limit_req zone=general burst=20 nodelay;
|
||||
```
|
||||
|
||||
### Ejemplo: Módulo GeoIP2
|
||||
|
||||
Habilitar módulo:
|
||||
|
||||
```bash
|
||||
docker exec -it nginx-proxy-manager /bin/bash
|
||||
cat > /data/nginx/custom/root_top.conf << 'EOF'
|
||||
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
|
||||
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;
|
||||
EOF
|
||||
exit
|
||||
docker exec nginx-proxy-manager nginx -s reload
|
||||
```
|
||||
|
||||
## Variables de Entorno Avanzadas
|
||||
|
||||
### Ejecutar como Usuario No-Root
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
```
|
||||
|
||||
⚠️ Puede causar problemas con puertos < 1024. Solución: usar `--cap-add=NET_BIND_SERVICE`.
|
||||
|
||||
### Deshabilitar IPv6
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
DISABLE_IPV6: 'true'
|
||||
```
|
||||
|
||||
### Deshabilitar IP Ranges Fetch
|
||||
|
||||
Para entornos con acceso limitado a Internet:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
IP_RANGES_FETCH_ENABLED: 'false'
|
||||
```
|
||||
|
||||
### Header X-FRAME-OPTIONS
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
X_FRAME_OPTIONS: "sameorigin" # o "deny", "allow-from https://example.com"
|
||||
```
|
||||
|
||||
### Usuario Admin Automático
|
||||
|
||||
Saltarse el setup inicial:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
INITIAL_ADMIN_EMAIL: admin@tudominio.com
|
||||
INITIAL_ADMIN_PASSWORD: tu_password_segura
|
||||
```
|
||||
|
||||
⚠️ Cambiar la contraseña inmediatamente después del primer login.
|
||||
|
||||
## Healthcheck
|
||||
|
||||
Añadir healthcheck al servicio:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
healthcheck:
|
||||
test: ["CMD", "/usr/bin/check-health"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
## Logrotate Personalizado
|
||||
|
||||
Por defecto NPM rota logs semanalmente (access: 4 archivos, error: 10 archivos).
|
||||
|
||||
Personalizar:
|
||||
|
||||
```bash
|
||||
# logrotate.custom
|
||||
/data/logs/*.log {
|
||||
daily
|
||||
rotate 7
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
sharedscripts
|
||||
postrotate
|
||||
docker exec nginx-proxy-manager nginx -s reopen
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
Montar en compose:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- npm_data:/data
|
||||
- npm_letsencrypt:/etc/letsencrypt
|
||||
- ./logrotate.custom:/etc/logrotate.d/nginx-proxy-manager
|
||||
```
|
||||
|
||||
## Migración desde Otra Instancia
|
||||
|
||||
### Exportar desde origen
|
||||
|
||||
```bash
|
||||
# Backup volúmenes
|
||||
docker run --rm \
|
||||
-v npm_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar czf /backup/npm_data_backup.tar.gz -C /data .
|
||||
|
||||
docker run --rm \
|
||||
-v npm_letsencrypt:/letsencrypt \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar czf /backup/npm_letsencrypt_backup.tar.gz -C /letsencrypt .
|
||||
```
|
||||
|
||||
### Importar en destino
|
||||
|
||||
```bash
|
||||
# Crear volúmenes
|
||||
docker volume create npm_data
|
||||
docker volume create npm_letsencrypt
|
||||
|
||||
# Restaurar
|
||||
docker run --rm \
|
||||
-v npm_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar xzf /backup/npm_data_backup.tar.gz -C /data
|
||||
|
||||
docker run --rm \
|
||||
-v npm_letsencrypt:/letsencrypt \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar xzf /backup/npm_letsencrypt_backup.tar.gz -C /letsencrypt
|
||||
|
||||
# Levantar NPM
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Arquitecturas Soportadas
|
||||
|
||||
NPM soporta múltiples arquitecturas (manifest multi-arch):
|
||||
|
||||
- `amd64` - Intel/AMD 64-bit
|
||||
- `arm64` - ARM 64-bit (Raspberry Pi 4, Apple Silicon)
|
||||
- `armv7` - ARM 32-bit (Raspberry Pi 3)
|
||||
|
||||
No necesitas hacer nada especial, Docker pull descarga la imagen correcta automáticamente.
|
||||
|
||||
### Raspberry Pi Consideraciones
|
||||
|
||||
Para MariaDB en ARM, usar imagen alternativa:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
image: yobasystems/alpine-mariadb:latest # en lugar de jc21/mariadb-aria
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Volver a**: [Página Principal](Home) | [Certificados SSL](SSL)
|
||||
244
Home.md
Normal file
244
Home.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# NGINX Proxy Manager - Documentación
|
||||
|
||||
Bienvenido a la documentación del despliegue de **NGINX Proxy Manager** usando Docker Compose.
|
||||
|
||||
## ¿Qué es NGINX Proxy Manager?
|
||||
|
||||
NGINX Proxy Manager (NPM) es una interfaz de gestión intuitiva para configurar y administrar proxy inversos NGINX sin necesidad de conocimientos profundos de NGINX. Ideal para:
|
||||
|
||||
- 🏠 **Self-hosting casero** - Exponer servicios locales a Internet de forma segura
|
||||
- 🔒 **Certificados SSL automáticos** - Let's Encrypt integrado con renovación automática
|
||||
- 🌐 **Múltiples dominios** - Gestionar decenas o cientos de proxy hosts desde una UI
|
||||
- 📱 **Interfaz moderna** - Administración web responsive y fácil de usar
|
||||
- 🔐 **Control de acceso** - Listas de acceso y autenticación básica HTTP
|
||||
|
||||
## Características Principales
|
||||
|
||||
### Gestión de Proxy Hosts
|
||||
|
||||
- **Proxy Hosts**: Redirigir dominios a servicios backend (HTTP/HTTPS)
|
||||
- **Redirection Hosts**: Redirecciones 301/302 permanentes o temporales
|
||||
- **404 Hosts**: Páginas personalizadas para dominios no configurados
|
||||
- **Streams**: Proxy TCP/UDP para servicios no-HTTP (SSH, bases de datos, etc.)
|
||||
|
||||
### SSL/TLS
|
||||
|
||||
- ✅ **Let's Encrypt gratuito** con renovación automática
|
||||
- ✅ **Certificados personalizados** (upload de cert + key)
|
||||
- ✅ **Wildcard certificates** vía DNS challenge
|
||||
- ✅ **HTTP/2 y HTTP/3** (QUIC) support
|
||||
- ✅ **Force SSL** (redirección automática HTTP → HTTPS)
|
||||
- ✅ **HSTS** (HTTP Strict Transport Security)
|
||||
|
||||
### Seguridad
|
||||
|
||||
- 🔐 **Access Lists** - Restricción por IP, username/password
|
||||
- 🛡️ **Headers personalizados** - X-Frame-Options, CSP, CORS
|
||||
- 🚫 **Bloqueo de exploits comunes** - Configuración NGINX hardening
|
||||
- 🔑 **Gestión de usuarios** - Multi-usuario con roles y permisos
|
||||
|
||||
## Componentes del Stack
|
||||
|
||||
Este repositorio despliega NPM con la siguiente configuración:
|
||||
|
||||
### Servicio Principal
|
||||
- **Imagen**: `jc21/nginx-proxy-manager:latest`
|
||||
- **Contenedor**: `nginx-proxy-manager`
|
||||
- **Reinicio**: `unless-stopped`
|
||||
|
||||
### Puertos Expuestos
|
||||
- **80**: HTTP público (redirige automáticamente a HTTPS)
|
||||
- **81**: Interfaz web de administración
|
||||
- **443**: HTTPS público
|
||||
|
||||
### Volúmenes
|
||||
- `npm_data` → `/data` - Base de datos SQLite, configuraciones, logs
|
||||
- `npm_letsencrypt` → `/etc/letsencrypt` - Certificados SSL de Let's Encrypt
|
||||
|
||||
### Red
|
||||
- `npm_network` - Red dedicada para el stack
|
||||
|
||||
## Requisitos Previos
|
||||
|
||||
Antes de desplegar NPM, asegúrate de tener:
|
||||
|
||||
- ✅ Docker Engine y Docker Compose instalados
|
||||
- ✅ Puertos 80, 443 y 81 disponibles (o configurar puertos alternativos)
|
||||
- ✅ Dominio(s) apuntando al servidor (para certificados SSL)
|
||||
- ✅ Acceso a Internet (para validación de Let's Encrypt)
|
||||
- ✅ Firewall configurado para permitir tráfico en puertos 80/443
|
||||
|
||||
## Despliegue Rápido
|
||||
|
||||
### 1. Clonar el Repositorio
|
||||
|
||||
```bash
|
||||
git clone https://git.ictiberia.com/groales/npm
|
||||
cd npm
|
||||
```
|
||||
|
||||
### 2. Levantar el Stack
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 3. Verificar el Estado
|
||||
|
||||
```bash
|
||||
docker ps --filter name=nginx-proxy-manager
|
||||
docker logs nginx-proxy-manager
|
||||
```
|
||||
|
||||
### 4. Acceder a la Interfaz Web
|
||||
|
||||
Abre tu navegador en: **http://IP-del-servidor:81**
|
||||
|
||||
⏱️ **Primera vez**: El inicio puede tardar 1-2 minutos. Espera a ver en los logs:
|
||||
```
|
||||
[setup ] Starting backend
|
||||
```
|
||||
|
||||
### 5. Login Inicial
|
||||
|
||||
**Credenciales por defecto**:
|
||||
```
|
||||
Email: admin@example.com
|
||||
Password: changeme
|
||||
```
|
||||
|
||||
🔒 **Obligatorio**: Al primer login, se te pedirá:
|
||||
1. Cambiar el email
|
||||
2. Cambiar el nombre de usuario
|
||||
3. Establecer una nueva contraseña
|
||||
|
||||
## Primer Proxy Host (Guía Rápida)
|
||||
|
||||
### Ejemplo: Exponer Portainer con SSL
|
||||
|
||||
Supongamos que tienes Portainer corriendo en `192.168.1.100:9443` y quieres acceder via `https://portainer.tudominio.com`.
|
||||
|
||||
1. **Ir a "Hosts" → "Proxy Hosts" → "Add Proxy Host"**
|
||||
|
||||
2. **Pestaña "Details"**:
|
||||
- **Domain Names**: `portainer.tudominio.com`
|
||||
- **Scheme**: `https` (Portainer usa HTTPS)
|
||||
- **Forward Hostname / IP**: `192.168.1.100`
|
||||
- **Forward Port**: `9443`
|
||||
- **Cache Assets**: ✅ (opcional)
|
||||
- **Block Common Exploits**: ✅
|
||||
- **Websockets Support**: ✅ (necesario para Portainer)
|
||||
|
||||
3. **Pestaña "SSL"**:
|
||||
- ✅ **Request a new SSL Certificate with Let's Encrypt**
|
||||
- ✅ **Force SSL** (redirigir HTTP → HTTPS)
|
||||
- ✅ **HTTP/2 Support**
|
||||
- ✅ **HSTS Enabled** (opcional, recomendado)
|
||||
- Email: `tu@email.com` (para notificaciones de Let's Encrypt)
|
||||
- ✅ **I Agree to the Let's Encrypt Terms of Service**
|
||||
|
||||
4. **Save**
|
||||
|
||||
✅ En 10-30 segundos, el certificado SSL se generará y el proxy estará activo.
|
||||
|
||||
Accede a: `https://portainer.tudominio.com` 🎉
|
||||
|
||||
## Casos de Uso Comunes
|
||||
|
||||
### 1. Proxy a Contenedores Docker en la Misma Red
|
||||
|
||||
Si tienes servicios corriendo en Docker en el mismo host:
|
||||
|
||||
```yaml
|
||||
# En el docker-compose.yaml de tu servicio
|
||||
networks:
|
||||
- npm_network
|
||||
|
||||
networks:
|
||||
npm_network:
|
||||
external: true
|
||||
```
|
||||
|
||||
Luego en NPM:
|
||||
- **Forward Hostname**: Nombre del contenedor (ej: `portainer`)
|
||||
- **Forward Port**: Puerto interno del contenedor (no el publicado)
|
||||
|
||||
### 2. Redirección Permanente
|
||||
|
||||
**Ejemplo**: Redirigir `www.tudominio.com` → `tudominio.com`
|
||||
|
||||
1. **"Hosts" → "Redirection Hosts" → "Add Redirection Host"**
|
||||
2. **Domain Names**: `www.tudominio.com`
|
||||
3. **Scheme**: `https`
|
||||
4. **Forward Domain Name**: `tudominio.com`
|
||||
5. **Preserve Path**: ✅
|
||||
6. **HTTP Code**: `301` (permanente)
|
||||
7. **SSL**: Solicitar certificado para `www.tudominio.com`
|
||||
|
||||
### 3. Stream TCP (Ejemplo: SSH)
|
||||
|
||||
**Objetivo**: Acceder a SSH del servidor via puerto 2222 externo.
|
||||
|
||||
1. **"Streams" → "Add Stream"**
|
||||
2. **Incoming Port**: `2222`
|
||||
3. **Forwarding Host**: `127.0.0.1` (localhost)
|
||||
4. **Forwarding Port**: `22` (SSH)
|
||||
5. **TCP Forwarding**: ✅
|
||||
6. **Save**
|
||||
|
||||
Añadir puerto al `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "80:80"
|
||||
- "81:81"
|
||||
- "443:443"
|
||||
- "2222:2222" # Stream SSH
|
||||
```
|
||||
|
||||
Reiniciar: `docker compose up -d`
|
||||
|
||||
Conectar: `ssh usuario@IP-servidor -p 2222`
|
||||
|
||||
### 4. Access List (Restringir por IP)
|
||||
|
||||
1. **"Access Lists" → "Add Access List"**
|
||||
2. **Name**: `Solo oficina`
|
||||
3. **Pass Auth**: ✅ (si quieres autenticación adicional)
|
||||
4. **Authorization** → **Add** → **Username**: `admin`, **Password**: `***`
|
||||
5. **Access** → **Allow** → `192.168.1.0/24` (red local)
|
||||
6. **Access** → **Deny** → `0.0.0.0/0` (todo lo demás)
|
||||
7. **Save**
|
||||
|
||||
Aplicar a Proxy Host:
|
||||
- Editar Proxy Host → **Access List**: Seleccionar "Solo oficina"
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
- 📖 [Configuración Avanzada](Configuracion) - MySQL, secrets, custom NGINX configs
|
||||
- 🔒 [Certificados SSL/TLS](SSL) - Wildcard, DNS challenge, certificados propios
|
||||
- 💾 [Backup y Restauración](Backup) - Cómo respaldar y restaurar NPM
|
||||
- ⚙️ [Configuración Avanzada de NGINX](Avanzado) - Custom configs, geoIP, rate limiting
|
||||
|
||||
## Troubleshooting Rápido
|
||||
|
||||
| Problema | Solución |
|
||||
|----------|----------|
|
||||
| Puerto 80/443 ocupado | Ver proceso: `sudo netstat -tulpn \| grep :80`, cambiar puertos en compose |
|
||||
| No se genera certificado SSL | Verificar DNS apunta al servidor, puertos 80/443 abiertos en firewall |
|
||||
| Olvido de contraseña | Ver [Backup](Backup#reset-password) para resetear |
|
||||
| Error "Address family not supported" | Añadir `DISABLE_IPV6: 'true'` en environment |
|
||||
| 502 Bad Gateway | Verificar que el backend esté corriendo y el puerto correcto |
|
||||
|
||||
## Recursos Oficiales
|
||||
|
||||
- 📘 [Documentación Oficial](https://nginxproxymanager.com/)
|
||||
- 🐛 [GitHub Issues](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
|
||||
- 💬 [Reddit r/nginxproxymanager](https://reddit.com/r/nginxproxymanager)
|
||||
- 🐳 [Docker Hub](https://hub.docker.com/r/jc21/nginx-proxy-manager)
|
||||
- 📺 [Video Tutoriales](https://www.youtube.com/results?search_query=nginx+proxy+manager)
|
||||
|
||||
---
|
||||
|
||||
**Versión**: Latest (rolling release)
|
||||
**Última actualización**: Noviembre 2025
|
||||
344
SSL.md
Normal file
344
SSL.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# Certificados SSL/TLS
|
||||
|
||||
## Let's Encrypt (Recomendado)
|
||||
|
||||
NPM integra Let's Encrypt para certificados SSL gratuitos y automáticos.
|
||||
|
||||
### Requisitos
|
||||
|
||||
- ✅ Dominio apuntando al servidor (registro A/AAAA en DNS)
|
||||
- ✅ Puertos 80 y 443 accesibles desde Internet
|
||||
- ✅ Firewall configurado para permitir tráfico entrante
|
||||
|
||||
### Solicitar Certificado (HTTP Challenge)
|
||||
|
||||
1. **Crear/Editar Proxy Host**
|
||||
2. **Pestaña SSL**:
|
||||
- ✅ **Request a new SSL Certificate with Let's Encrypt**
|
||||
- Email: `tu@email.com` (para notificaciones de expiración)
|
||||
- ✅ **Force SSL** (redirigir HTTP → HTTPS automáticamente)
|
||||
- ✅ **HTTP/2 Support**
|
||||
- ✅ **HSTS Enabled** (opcional, recomendado para seguridad)
|
||||
- ✅ **I Agree to the Let's Encrypt Terms of Service**
|
||||
3. **Save**
|
||||
|
||||
✅ El certificado se generará en 10-30 segundos.
|
||||
|
||||
### Renovación Automática
|
||||
|
||||
NPM verifica certificados diariamente y renueva automáticamente los que están por expirar (< 30 días).
|
||||
|
||||
No requiere configuración adicional.
|
||||
|
||||
### Certificados Wildcard (DNS Challenge)
|
||||
|
||||
Para certificados wildcard (`*.tudominio.com`) se requiere DNS challenge.
|
||||
|
||||
#### Proveedores DNS Soportados
|
||||
|
||||
NPM soporta +100 proveedores via Certbot plugins. Los más comunes:
|
||||
|
||||
- Cloudflare
|
||||
- Amazon Route53
|
||||
- Google Cloud DNS
|
||||
- DigitalOcean
|
||||
- OVH
|
||||
- Namecheap
|
||||
- GoDaddy
|
||||
- etc.
|
||||
|
||||
#### Configurar DNS Challenge
|
||||
|
||||
**Ejemplo: Cloudflare**
|
||||
|
||||
1. **Obtener API Token de Cloudflare**:
|
||||
- Login en Cloudflare Dashboard
|
||||
- Profile → API Tokens → Create Token
|
||||
- Template: "Edit zone DNS"
|
||||
- Zone Resources: Include → Specific zone → `tudominio.com`
|
||||
- Continue → Create Token
|
||||
- Copiar token
|
||||
|
||||
2. **En NPM: SSL Certificates → Add SSL Certificate**:
|
||||
- **Domain Names**: `*.tudominio.com`, `tudominio.com` (ambos)
|
||||
- ✅ **Use a DNS Challenge**
|
||||
- **DNS Provider**: `Cloudflare`
|
||||
- **Credentials File Content**:
|
||||
```
|
||||
dns_cloudflare_api_token = TU_TOKEN_AQUI
|
||||
```
|
||||
- Email: `tu@email.com`
|
||||
- ✅ **I Agree to the Let's Encrypt Terms of Service**
|
||||
- **Save**
|
||||
|
||||
3. **Usar el certificado**:
|
||||
- Al crear Proxy Hosts, en pestaña SSL:
|
||||
- Seleccionar certificado wildcard existente
|
||||
- No marcar "Request a new SSL Certificate"
|
||||
|
||||
#### Otros Proveedores DNS
|
||||
|
||||
**Amazon Route53**:
|
||||
```
|
||||
dns_route53_access_key_id = YOUR_ACCESS_KEY
|
||||
dns_route53_secret_access_key = YOUR_SECRET_KEY
|
||||
```
|
||||
|
||||
**Google Cloud DNS**:
|
||||
```
|
||||
dns_google_credentials = /path/to/credentials.json
|
||||
```
|
||||
|
||||
**DigitalOcean**:
|
||||
```
|
||||
dns_digitalocean_token = YOUR_TOKEN
|
||||
```
|
||||
|
||||
**OVH**:
|
||||
```
|
||||
dns_ovh_endpoint = ovh-eu
|
||||
dns_ovh_application_key = YOUR_APP_KEY
|
||||
dns_ovh_application_secret = YOUR_APP_SECRET
|
||||
dns_ovh_consumer_key = YOUR_CONSUMER_KEY
|
||||
```
|
||||
|
||||
Consulta [Certbot DNS plugins](https://eff-certbot.readthedocs.io/en/stable/using.html#dns-plugins) para más proveedores.
|
||||
|
||||
## Certificados Propios
|
||||
|
||||
### Subir Certificado y Clave Privada
|
||||
|
||||
1. **SSL Certificates → Add SSL Certificate**
|
||||
2. **Custom**:
|
||||
- **Name**: Nombre descriptivo (ej: "MiEmpresa Wildcard")
|
||||
- **Certificate Key**: Pegar contenido del archivo `.key`
|
||||
- **Certificate**: Pegar contenido del archivo `.crt` o `.pem`
|
||||
- **Intermediate Certificate**: (opcional) Cadena de certificados intermedios
|
||||
- **Save**
|
||||
|
||||
3. **Usar en Proxy Host**:
|
||||
- Pestaña SSL → Seleccionar certificado custom
|
||||
- ✅ **Force SSL**
|
||||
- ✅ **HTTP/2 Support**
|
||||
|
||||
### Formato de Certificados
|
||||
|
||||
#### Certificado (Certificate)
|
||||
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFXzCCBEegAwIBAgISBGP...
|
||||
... (contenido base64) ...
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
#### Clave Privada (Certificate Key)
|
||||
|
||||
```
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQ...
|
||||
... (contenido base64) ...
|
||||
-----END PRIVATE KEY-----
|
||||
```
|
||||
|
||||
#### Certificado Intermedio (Intermediate Certificate)
|
||||
|
||||
Si tu CA proporciona cadena de certificados:
|
||||
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
(Certificado Intermedio 1)
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
(Certificado Intermedio 2)
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
### Convertir Formatos
|
||||
|
||||
**PFX/P12 a PEM**:
|
||||
```bash
|
||||
# Extraer clave privada
|
||||
openssl pkcs12 -in certificate.pfx -nocerts -out key.pem -nodes
|
||||
|
||||
# Extraer certificado
|
||||
openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out cert.pem
|
||||
```
|
||||
|
||||
**DER a PEM**:
|
||||
```bash
|
||||
openssl x509 -inform der -in certificate.cer -out certificate.pem
|
||||
```
|
||||
|
||||
## HTTP/2 y HTTP/3
|
||||
|
||||
### HTTP/2
|
||||
|
||||
Habilitado por defecto al activar SSL en Proxy Host.
|
||||
|
||||
✅ **HTTP/2 Support** en pestaña SSL.
|
||||
|
||||
### HTTP/3 (QUIC)
|
||||
|
||||
NPM soporta HTTP/3 pero requiere configuración adicional:
|
||||
|
||||
```bash
|
||||
docker exec -it nginx-proxy-manager /bin/bash
|
||||
|
||||
cat > /data/nginx/custom/server_proxy.conf << 'EOF'
|
||||
# HTTP/3
|
||||
listen 443 quic reuseport;
|
||||
add_header Alt-Svc 'h3=":443"; ma=86400';
|
||||
EOF
|
||||
|
||||
exit
|
||||
docker exec nginx-proxy-manager nginx -s reload
|
||||
```
|
||||
|
||||
Abrir puerto UDP 443:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "80:80"
|
||||
- "81:81"
|
||||
- "443:443"
|
||||
- "443:443/udp" # HTTP/3
|
||||
```
|
||||
|
||||
## HSTS (HTTP Strict Transport Security)
|
||||
|
||||
HSTS fuerza a los navegadores a usar HTTPS siempre.
|
||||
|
||||
### Habilitar en Proxy Host
|
||||
|
||||
Pestaña SSL:
|
||||
- ✅ **HSTS Enabled**
|
||||
- **HSTS Subdomains** (opcional, incluye subdominios)
|
||||
|
||||
Esto añade el header:
|
||||
```
|
||||
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
||||
```
|
||||
|
||||
### HSTS Preload
|
||||
|
||||
Para máxima seguridad, añadir tu dominio al [HSTS Preload List](https://hstspreload.org/).
|
||||
|
||||
Configuración custom:
|
||||
|
||||
```nginx
|
||||
# En Proxy Host → Advanced → Custom Nginx Configuration
|
||||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
|
||||
```
|
||||
|
||||
Luego enviar dominio a hstspreload.org.
|
||||
|
||||
## Configuración Avanzada de SSL
|
||||
|
||||
### Cipher Suites Personalizados
|
||||
|
||||
Para mayor compatibilidad o seguridad:
|
||||
|
||||
```nginx
|
||||
# En /data/nginx/custom/server_proxy.conf
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_prefer_server_ciphers off;
|
||||
```
|
||||
|
||||
### OCSP Stapling
|
||||
|
||||
Mejora rendimiento SSL:
|
||||
|
||||
```nginx
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/tudominio.com/chain.pem;
|
||||
resolver 1.1.1.1 8.8.8.8 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
```
|
||||
|
||||
### Session Cache
|
||||
|
||||
Reducir overhead de handshakes SSL:
|
||||
|
||||
```nginx
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: DNS Challenge Failed
|
||||
|
||||
**Síntomas**: Certificado wildcard no se genera.
|
||||
|
||||
**Causas**:
|
||||
- API token/credenciales incorrectas
|
||||
- Permisos insuficientes del token
|
||||
- Propagación DNS lenta
|
||||
|
||||
**Soluciones**:
|
||||
```bash
|
||||
# Ver logs detallados
|
||||
docker logs nginx-proxy-manager | grep certbot
|
||||
|
||||
# Verificar permisos de token (Cloudflare)
|
||||
# Token debe tener: Zone:DNS:Edit
|
||||
|
||||
# Esperar propagación DNS (puede tardar minutos)
|
||||
```
|
||||
|
||||
### Error: Rate Limit Exceeded
|
||||
|
||||
Let's Encrypt tiene límites:
|
||||
- **5 certificados por dominio/semana**
|
||||
- **50 certificados por cuenta/semana**
|
||||
|
||||
**Solución**:
|
||||
- Esperar 7 días para reset
|
||||
- Usar certificados wildcard (cubre múltiples subdominios con 1 cert)
|
||||
- Durante desarrollo, usar [staging environment](https://letsencrypt.org/docs/staging-environment/)
|
||||
|
||||
### Certificado No Se Renueva
|
||||
|
||||
**Verificar**:
|
||||
```bash
|
||||
# Ver logs de renovación
|
||||
docker logs nginx-proxy-manager | grep renew
|
||||
|
||||
# Listar certificados
|
||||
docker exec nginx-proxy-manager certbot certificates
|
||||
```
|
||||
|
||||
**Forzar renovación manual**:
|
||||
```bash
|
||||
docker exec nginx-proxy-manager certbot renew --force-renewal
|
||||
docker exec nginx-proxy-manager nginx -s reload
|
||||
```
|
||||
|
||||
### Error: Port 80 Not Available
|
||||
|
||||
Let's Encrypt HTTP challenge requiere puerto 80.
|
||||
|
||||
**Si puerto 80 no está disponible**:
|
||||
1. Usa DNS challenge (wildcard)
|
||||
2. O libera puerto 80 temporalmente
|
||||
|
||||
### Verificar Certificado SSL
|
||||
|
||||
**Desde línea de comandos**:
|
||||
```bash
|
||||
# Ver detalles del certificado
|
||||
echo | openssl s_client -servername tudominio.com -connect tudominio.com:443 2>/dev/null | openssl x509 -noout -dates
|
||||
|
||||
# Test desde exterior
|
||||
curl -vI https://tudominio.com 2>&1 | grep -i ssl
|
||||
|
||||
# SSL Labs test (rating A-F)
|
||||
# https://www.ssllabs.com/ssltest/analyze.html?d=tudominio.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Volver a**: [Página Principal](Home) | [Configuración Avanzada](Configuracion)
|
||||
Reference in New Issue
Block a user