Initial clean commit (history purged)

This commit is contained in:
Eduardo David Paredes Vara
2025-12-03 17:15:06 +00:00
commit 4ac3881958
28 changed files with 4250 additions and 0 deletions

30
.env Normal file
View File

@@ -0,0 +1,30 @@
##### Portainer #####
# Por defecto se usa Portainer CE (definido en el docker-compose)
# Si quieres usar Portainer EE, descomenta y ajusta esta línea:
# PORTAINER_IMAGE=portainer/portainer-ee:2.33.5
# Rutas (cámbialas si no quieres /opt/...)
# PORTAINER_SECRET_PATH=/opt/portainer/secrets/portainer
# PORTAINER_DATA_PATH=/opt/portainer/data
# PORTAINER_HTTP_PORT=9000
##### Traefik / dominios #####
# Nombre de la red de Docker que usa Traefik
# TRAEFIK_DOCKER_NETWORK=proxy
# Nombre del entrypoint HTTPS en Traefik
# TRAEFIK_ENTRYPOINT_SECURE=websecure
# Nombre del certresolver de Let's Encrypt
# TRAEFIK_CERTRESOLVER=letsencrypt
# Middleware de autenticación (SSO, etc.)
# TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
# Dominios de ejemplo (cámbialos por los tuyos)
# PORTAINER_DOMAIN=portainer.example.com
# PORTAINER_API_DOMAIN=portainer-api.example.com
# Rangos IP permitidos para la API directa (ej: red VPN + host)
# PORTAINER_API_IP_WHITELIST=10.8.0.0/24,172.18.0.1/32

368
README.md Normal file
View File

@@ -0,0 +1,368 @@
# Portainer Stacks Repository
Este repositorio contiene la configuración de Portainer y múltiples stacks de servicios Docker gestionados mediante Docker Compose.
## 📋 Tabla de Contenidos
- [Descripción](#descripción)
- [Arquitectura](#arquitectura)
- [Prerequisitos](#prerequisitos)
- [Instalación y Despliegue](#instalación-y-despliegue)
- [Stacks Disponibles](#stacks-disponibles)
- [Configuración](#configuración)
- [Uso](#uso)
## 📖 Descripción
Este proyecto proporciona una infraestructura completa de servicios containerizados utilizando:
- **Portainer** como gestor visual de contenedores Docker
- **Traefik** como reverse proxy con certificados SSL automáticos
- **Authentik** para autenticación SSO
- Múltiples servicios adicionales (Gitea, n8n, AdGuard, etc.)
## 🏗️ Arquitectura
La arquitectura sigue este orden de despliegue:
1. **Portainer** (gestor de contenedores) - acceso directo por puerto 9443
2. **Traefik** (reverse proxy) - desplegado desde Portainer
3. **Authentik** (SSO) - desplegado desde Portainer
4. **Resto de stacks** - desplegables desde Portainer
Todos los servicios se comunican a través de la red Docker `proxy` y están protegidos por Traefik con SSL.
> **⚠️ Importante**: Los registros DNS deben estar configurados ANTES de desplegar Traefik y Authentik para que los certificados SSL se generen correctamente.
## ✅ Prerequisitos
- Docker Engine (20.10+)
- Docker Compose (v2.0+)
- Dominio(s) configurado(s) apuntando a tu servidor
- Puertos 80 y 443 abiertos (o 9443 para modo directo)
## 🚀 Instalación y Despliegue
### Paso 1: Clonar el Repositorio
```bash
git clone <repository-url>
cd Portainer_repo
```
### Paso 2: Crear la Red de Docker
Todos los servicios comparten la red `proxy`:
```bash
docker network create proxy
```
### Paso 3: Preparar Secretos de Portainer
Crea el archivo de secreto para la clave de cifrado de Portainer:
```bash
# Crear directorio para secretos
sudo mkdir -p /opt/portainer/secrets
# Generar una clave aleatoria de 32 caracteres
openssl rand -base64 32 | sudo tee /opt/portainer/secrets/portainer
# Asegurar permisos correctos
sudo chmod 600 /opt/portainer/secrets/portainer
```
### Paso 4: Desplegar Portainer (PRIMERO)
Despliega Portainer con acceso directo por puerto 9443:
```bash
docker compose -f docker-compose.9443.yml up -d
```
Verifica que Portainer esté corriendo:
```bash
docker ps | grep portainer
```
Accede a: `https://tu-servidor:9443`
### Paso 5: Configuración Inicial de Portainer
1. Accede a Portainer mediante `https://tu-servidor:9443`
2. Crea el usuario administrador (primera vez - tienes 5 minutos)
3. Selecciona el entorno Docker local
4. Completa la configuración inicial
### Paso 6: Configurar Registros DNS
**Antes de desplegar Traefik y Authentik**, configura los registros DNS:
- Registro A para Traefik Dashboard (ej: `traefik.tudominio.com`)
- Registro A para Portainer UI (ej: `portainer.tudominio.com`)
- Registro A para Portainer API (ej: `portainer-api.tudominio.com`)
- Registro A para Authentik (ej: `auth.tudominio.com`)
- Cualquier otro dominio que vayas a usar
> **⏰ Espera** a que los registros DNS se propaguen antes de continuar (puede tardar de minutos a horas).
Verifica la propagación:
```bash
nslookup traefik.tudominio.com
nslookup portainer.tudominio.com
nslookup auth.tudominio.com
```
### Paso 7: Desplegar Traefik desde Portainer
1. En Portainer, ve a **Stacks****Add stack**
2. Nombre: `traefik`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `Traefik/docker-compose.yml`
5. Añade el archivo de variables de entorno: `Traefik/stack.env` (o configúralas manualmente)
6. Haz clic en **Deploy the stack**
Verifica que Traefik esté funcionando:
```bash
docker logs traefik
```
### Paso 8: Desplegar Authentik desde Portainer
1. En Portainer, ve a **Stacks****Add stack**
2. Nombre: `authentik`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `authentik/docker-compose.yml`
5. Añade las variables de entorno necesarias
6. Haz clic en **Deploy the stack**
#### Configuración de Authentik
Una vez desplegado Authentik, necesitarás configurar:
- **Applications** (aplicaciones a proteger)
- **Providers** de tipo Forward Auth
- **Authorization Flow** de tipo Implicit
- **Outposts** para ejecutar los providers
- **Middleware** en Traefik
Para instrucciones detalladas, consulta el [README de Authentik](authentik/README.md).
### Paso 9: Configurar Variables de Entorno para Portainer UI
Una vez Traefik y Authentik están funcionando, actualiza el archivo `.env` en la raíz del proyecto:
```bash
nano .env
```
Variables principales a configurar:
- `PORTAINER_DOMAIN`: Tu dominio para Portainer UI (ej: `portainer.tudominio.com`)
- `PORTAINER_API_DOMAIN`: Tu dominio para la API de Portainer (ej: `portainer-api.tudominio.com`)
- `PORTAINER_API_IP_WHITELIST`: IPs permitidas para acceso directo a la API
- `TRAEFIK_AUTH_MIDDLEWARE`: Middleware de autenticación (ej: `authentik@docker`)
### Paso 10: Actualizar Stack de Portainer (Opcional)
Si deseas acceder a Portainer mediante dominio con SSL (en lugar del puerto 9443):
1. En Portainer, ve a **Stacks****Add stack**
2. Nombre: `portainer`
3. Selecciona **Upload** y sube el archivo `docker-compose.yml` de la raíz
4. O usa **Repository** apuntando a la raíz del repositorio
5. Añade las variables de entorno del archivo `.env`
6. Haz clic en **Deploy the stack**
> **Nota**: Esto reemplazará el despliegue inicial por puerto 9443 con acceso mediante dominio.
### Paso 11: Desplegar Otros Stacks desde Portainer
Una vez la infraestructura base está funcionando, puedes desplegar el resto de stacks:
#### Método 1: Desde la UI de Portainer (Recomendado)
1. Ve a **Stacks****Add stack**
2. Selecciona **Repository**
3. Configura el repositorio Git:
- URL: `<tu-repositorio>`
- Reference: `main` (o tu rama)
- Compose path: `<stack-name>/docker-compose.yml`
4. Añade variables de entorno si es necesario
5. Haz clic en **Deploy the stack**
#### Método 2: Desde línea de comandos
```bash
# Ejemplo: Desplegar Authentik
cd authentik
docker compose up -d
cd ..
# Ejemplo: Desplegar Gitea
cd gitea
docker compose up -d
cd ..
```
## 📦 Stacks Disponibles
| Stack | Descripción | Carpeta | Documentación |
|-------|-------------|---------|---------------|
| **Traefik** | Reverse proxy con SSL automático | `Traefik/` | [README](Traefik/README.md) |
| **Portainer** | Gestor visual de Docker | Raíz (docker-compose.yml) | - |
| **Authentik** | Sistema de autenticación SSO (Forward Auth) | `authentik/` | [README](authentik/README.md) |
| **Gitea** | Servidor Git autoalojado con Actions | `gitea/` | [README](gitea/README.md) |
| **n8n** | Plataforma de automatización de workflows | `n8n/` | [README](n8n/README.md) |
| **AdGuard** | Bloqueador de anuncios DNS con DoT | `adguard/` | [README](adguard/README.md) |
| **Trilium** | Aplicación de notas jerárquicas | `trilium/` | [README](trilium/README.md) |
| **Wireguard** | VPN rápida y segura | `wireguard/` | [README](wireguard/README.md) |
| **Ruleta** | Aplicación Next.js personalizada | `ruleta/` | [README](ruleta/README.md) |
> **📖 Nota**: Cada stack tiene su propio README con instrucciones detalladas de configuración, uso y troubleshooting.
## ⚙️ Configuración
### Archivo .env Principal
El archivo `.env` en la raíz contiene las configuraciones globales:
```env
# Imagen de Portainer
PORTAINER_IMAGE=portainer/portainer-ce:latest
# Rutas de almacenamiento
PORTAINER_SECRET_PATH=/opt/portainer/secrets/portainer
PORTAINER_DATA_PATH=/opt/portainer/data
# Configuración de red y proxy
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
# Dominios
PORTAINER_DOMAIN=portainer.example.com
PORTAINER_API_DOMAIN=portainer-api.example.com
# Seguridad
PORTAINER_API_IP_WHITELIST=10.8.0.0/24,172.18.0.1/32
TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
```
### Configuraciones por Stack
Cada stack puede tener su propio archivo `stack.env` o `.env` en su carpeta correspondiente.
## 🎯 Uso
### Ver Logs de Portainer
```bash
docker logs -f portainer
```
### Ver Estado de Todos los Contenedores
```bash
docker ps -a
```
### Actualizar Portainer
```bash
docker compose pull
docker compose up -d
```
### Reiniciar un Stack
Desde Portainer UI o:
```bash
cd <stack-folder>
docker compose restart
```
### Eliminar un Stack
```bash
cd <stack-folder>
docker compose down
# Para eliminar también volúmenes:
docker compose down -v
```
## 🔒 Seguridad
### Acceso a Portainer UI
- **Protegido por SSO**: La UI principal está protegida mediante Authentik (configurable con `TRAEFIK_AUTH_MIDDLEWARE`)
- **Dominio**: Accesible solo mediante el dominio configurado con SSL
### Acceso a API de Portainer
- **Whitelist IP**: La API está restringida a IPs específicas (VPN, localhost)
- **Dominio separado**: Usa un dominio diferente sin SSO para apps móviles
- **SSL**: Todo el tráfico está cifrado
### Base de Datos Cifrada
Portainer utiliza una clave de cifrado para proteger su base de datos, montada en:
- `/run/secrets/portainer`
- `/run/portainer/portainer`
## 🛠️ Troubleshooting
### Portainer no arranca
1. Verifica que la red `proxy` existe: `docker network ls | grep proxy`
2. Revisa los logs: `docker logs portainer`
3. Verifica que el archivo de secreto existe y tiene permisos correctos
4. Verifica que el puerto 9443 no esté ocupado: `sudo netstat -tulpn | grep 9443`
### No puedo acceder mediante dominio
1. Verifica que el dominio apunta a tu servidor: `nslookup tudominio.com`
2. Verifica que los registros DNS están propagados
3. Verifica que Traefik esté corriendo: `docker ps | grep traefik`
4. Verifica la configuración de Traefik: `docker logs traefik`
5. Revisa las labels de Traefik en el docker-compose.yml
6. Verifica que los puertos 80 y 443 estén abiertos: `sudo netstat -tulpn | grep -E ':(80|443)'`
7. Como respaldo, siempre puedes acceder por `https://tu-servidor:9443`
### Error de permisos con volúmenes (SELinux)
Si usas SELinux, los volúmenes ya tienen la opción `:Z` configurada. Si persisten problemas:
```bash
sudo chcon -Rt svirt_sandbox_file_t /opt/portainer/data
```
### Authentik no protege los servicios
1. Verifica que el outpost esté corriendo y en estado **Healthy**
2. Revisa que las aplicaciones y providers estén correctamente configurados
3. Verifica que el authorization flow sea de tipo **Implicit**
4. Comprueba que el middleware de Traefik esté correctamente referenciado en las labels
5. Revisa los logs de Authentik: `docker logs authentik-server`
6. Verifica la conectividad entre Traefik y Authentik en la red `proxy`
## 📝 Notas Adicionales
- **Orden de despliegue**: Siempre desplegar Portainer (9443) → Traefik → Authentik → Resto de stacks
- **Registros DNS**: Configurar ANTES de desplegar Traefik para que Let's Encrypt funcione correctamente
- **Puerto 9443**: Mantén el acceso por puerto 9443 como respaldo en caso de problemas con Traefik
- **Backups**: Considera hacer backup regular de `/opt/portainer/data` y el archivo de secretos
- **Actualizaciones**: Actualiza las imágenes regularmente desde Portainer UI
- **Monitoreo**: Usa Portainer para monitorear recursos y logs de todos los contenedores
## 📄 Licencia
Consulta el archivo LICENSE en este repositorio.
## 🤝 Contribuciones
Las contribuciones son bienvenidas. Por favor, abre un issue o pull request para sugerencias o mejoras.

312
Traefik/README.md Normal file
View File

@@ -0,0 +1,312 @@
# Traefik - Reverse Proxy
Traefik es un reverse proxy moderno que gestiona automáticamente certificados SSL con Let's Encrypt y enruta el tráfico a tus servicios.
## 📋 Descripción
Este stack despliega Traefik configurado para:
- Redirección automática HTTP → HTTPS
- Certificados SSL automáticos con Let's Encrypt
- Integración con Docker para descubrimiento automático de servicios
- Dashboard web para monitoreo
- Soporte para configuración dinámica mediante archivos
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Crear la red `proxy`
```bash
docker network create proxy
```
2. **Registros DNS**: Configurar los registros A para todos tus dominios apuntando a tu servidor
3. **Directorios**: Crear los directorios necesarios
```bash
sudo mkdir -p /opt/traefik/dynamic
sudo mkdir -p /opt/traefik/letsencrypt
```
### Desde Portainer
1. Ve a **Stacks** → **Add stack**
2. Nombre: `traefik`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `Traefik/docker-compose.yml`
5. Carga el archivo de variables de entorno: `Traefik/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno
Edita el archivo `stack.env`:
```env
# Imagen de Traefik
TRAEFIK_IMAGE=traefik:v3.2
# Red Docker
TRAEFIK_DOCKER_NETWORK=proxy
# Puertos
TRAEFIK_HTTP_PORT=80
TRAEFIK_HTTPS_PORT=443
# Let's Encrypt
TRAEFIK_ACME_EMAIL=tu-email@ejemplo.com
TRAEFIK_ACME_STORAGE=/letsencrypt/acme.json
# Nivel de log (DEBUG, INFO, WARN, ERROR)
TRAEFIK_LOG_LEVEL=INFO
# Directorios
TRAEFIK_DYNAMIC_DIR=/opt/traefik/dynamic
TRAEFIK_LETSENCRYPT_DIR=/opt/traefik/letsencrypt
```
> **⚠️ Importante**: Cambia `TRAEFIK_ACME_EMAIL` con tu email real.
## ⚙️ Configuración
### Características Principales
- **Redirección automática**: Todo el tráfico HTTP (puerto 80) se redirige automáticamente a HTTPS (puerto 443)
- **Let's Encrypt**: Certificados SSL automáticos mediante HTTP Challenge
- **Docker Provider**: Detecta automáticamente servicios Docker con labels de Traefik
- **File Provider**: Permite configuración dinámica mediante archivos en `/opt/traefik/dynamic`
### Configuración Dinámica
Puedes añadir configuraciones adicionales en `/opt/traefik/dynamic/`. Ejemplo:
**Archivo: `/opt/traefik/dynamic/middlewares.yml`**
```yaml
http:
middlewares:
# Middleware de seguridad
security-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
contentTypeNosniff: true
frameDeny: true
# Middleware de compresión
compression:
compress: {}
# Rate limiting
rate-limit:
rateLimit:
average: 100
burst: 50
```
### Acceso al Dashboard
El dashboard está deshabilitado por defecto (`api.insecure=false`). Para habilitarlo de forma segura:
**Opción 1: Mediante Traefik con Authentik**
Añade las siguientes labels al servicio de Traefik:
```yaml
labels:
traefik.http.routers.dashboard.rule: "Host(`traefik.tudominio.com`)"
traefik.http.routers.dashboard.entrypoints: "websecure"
traefik.http.routers.dashboard.tls.certresolver: "letsencrypt"
traefik.http.routers.dashboard.service: "api@internal"
traefik.http.routers.dashboard.middlewares: "authentik@docker"
```
**Opción 2: Acceso local (inseguro - solo desarrollo)**
Cambia en el `docker-compose.yml`:
```yaml
- "--api.insecure=true"
```
Luego expón el puerto:
```yaml
ports:
- "8080:8080"
```
Accede a: `http://tu-servidor:8080/dashboard/`
## 🔧 Uso con Servicios
### Ejemplo: Proteger un servicio con Traefik
En el `docker-compose.yml` de tu servicio:
```yaml
services:
mi-servicio:
image: mi-imagen:latest
networks:
- proxy
labels:
# Habilitar Traefik
traefik.enable: "true"
traefik.docker.network: "proxy"
# Router
traefik.http.routers.mi-servicio.rule: "Host(`miservicio.tudominio.com`)"
traefik.http.routers.mi-servicio.entrypoints: "websecure"
traefik.http.routers.mi-servicio.tls.certresolver: "letsencrypt"
# Service (puerto interno del contenedor)
traefik.http.services.mi-servicio.loadbalancer.server.port: "80"
# Middleware (opcional)
traefik.http.routers.mi-servicio.middlewares: "authentik@docker"
networks:
proxy:
external: true
```
### Ejemplo: Servicio con múltiples rutas
```yaml
labels:
# UI protegida con SSO
traefik.http.routers.app-ui.rule: "Host(`app.tudominio.com`)"
traefik.http.routers.app-ui.entrypoints: "websecure"
traefik.http.routers.app-ui.tls.certresolver: "letsencrypt"
traefik.http.routers.app-ui.middlewares: "authentik@docker"
traefik.http.routers.app-ui.priority: "10"
# API pública sin protección
traefik.http.routers.app-api.rule: "Host(`app.tudominio.com`) && PathPrefix(`/api`)"
traefik.http.routers.app-api.entrypoints: "websecure"
traefik.http.routers.app-api.tls.certresolver: "letsencrypt"
traefik.http.routers.app-api.priority: "20"
```
> **Nota**: Mayor `priority` = mayor prioridad. Las rutas más específicas deben tener mayor prioridad.
## 🛠️ Troubleshooting
### Los certificados SSL no se generan
1. Verifica que los registros DNS están configurados correctamente:
```bash
nslookup tudominio.com
```
2. Verifica que los puertos 80 y 443 están abiertos:
```bash
sudo netstat -tulpn | grep -E ':(80|443)'
```
3. Revisa los logs de Traefik:
```bash
docker logs traefik
```
4. Verifica el archivo de almacenamiento ACME:
```bash
ls -lh /opt/traefik/letsencrypt/acme.json
# Debe tener permisos 600
sudo chmod 600 /opt/traefik/letsencrypt/acme.json
```
5. Comprueba los límites de Let's Encrypt:
- Let's Encrypt tiene límite de 5 certificados duplicados por semana
- Usa staging para pruebas: `--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory`
### Un servicio no es accesible
1. Verifica que el servicio está en la red `proxy`:
```bash
docker network inspect proxy
```
2. Revisa las labels de Traefik en el servicio:
```bash
docker inspect nombre-servicio | grep -A 20 Labels
```
3. Verifica los logs de Traefik:
```bash
docker logs traefik | grep nombre-servicio
```
4. Comprueba que `traefik.enable: "true"` está configurado
### Error "Gateway Timeout" o "Bad Gateway"
1. Verifica que el puerto del servicio es correcto:
```yaml
traefik.http.services.mi-servicio.loadbalancer.server.port: "PUERTO_CORRECTO"
```
2. Verifica que el servicio está corriendo:
```bash
docker ps | grep mi-servicio
```
3. Comprueba la conectividad desde Traefik al servicio:
```bash
docker exec traefik ping nombre-servicio
```
### Dashboard no accesible
1. Si habilitaste `api.insecure=true`, accede a: `http://IP:8080/dashboard/`
2. Si usas dominio, verifica las labels y que el DNS está configurado
3. Revisa los logs: `docker logs traefik`
## 📚 Recursos Adicionales
- [Documentación oficial de Traefik](https://doc.traefik.io/traefik/)
- [Traefik con Docker](https://doc.traefik.io/traefik/providers/docker/)
- [Let's Encrypt con Traefik](https://doc.traefik.io/traefik/https/acme/)
- [Middlewares de Traefik](https://doc.traefik.io/traefik/middlewares/overview/)
## 🔒 Seguridad
- **Dashboard**: Protege siempre el dashboard con autenticación (Authentik, BasicAuth, etc.)
- **Logs**: Considera cambiar el nivel de log a `WARN` o `ERROR` en producción
- **Rate Limiting**: Implementa rate limiting en servicios públicos
- **Headers de seguridad**: Usa middlewares para añadir headers de seguridad
## 💾 Backups
Realiza backups regulares de:
- `/opt/traefik/letsencrypt/acme.json` (certificados SSL)
- `/opt/traefik/dynamic/` (configuración dinámica)
```bash
# Backup
sudo tar -czf traefik-backup-$(date +%Y%m%d).tar.gz /opt/traefik/
# Restaurar
sudo tar -xzf traefik-backup-YYYYMMDD.tar.gz -C /
```
## 🔄 Actualizaciones
Para actualizar Traefik:
1. En Portainer, ve al stack de Traefik
2. Edita el archivo `stack.env` y cambia la versión:
```env
TRAEFIK_IMAGE=traefik:v3.3
```
3. Haz clic en **Update the stack**
4. O desde línea de comandos:
```bash
cd Traefik
docker compose pull
docker compose up -d
```
> **⚠️ Nota**: Revisa el [changelog de Traefik](https://github.com/traefik/traefik/releases) antes de actualizar versiones mayores.

View File

@@ -0,0 +1,55 @@
services:
traefik:
image: ${TRAEFIK_IMAGE}
container_name: traefik
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"
command:
# Logs
- "--log.level=${TRAEFIK_LOG_LEVEL}"
# Dashboard (por ahora solo interno)
- "--api.dashboard=true"
- "--api.insecure=false"
# Entrypoints
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# Redirección HTTP -> HTTPS
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
# Proveedor Docker
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=${TRAEFIK_DOCKER_NETWORK}"
# Proveedor de ficheros dinámicos
- "--providers.file.directory=/dynamic"
- "--providers.file.watch=true"
# ACME / Let's Encrypt (resolver "letsencrypt")
- "--certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=${TRAEFIK_ACME_STORAGE}"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
ports:
- "${TRAEFIK_HTTP_PORT}:80"
- "${TRAEFIK_HTTPS_PORT}:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro,Z
- ${TRAEFIK_DYNAMIC_DIR}:/dynamic:Z
- ${TRAEFIK_LETSENCRYPT_DIR}:/letsencrypt:Z
networks:
- proxy
networks:
proxy:
external: true

11
Traefik/stack.env Normal file
View File

@@ -0,0 +1,11 @@
##### Traefik #####
TRAEFIK_IMAGE=traefik:v3.1
TRAEFIK_LOG_LEVEL=INFO
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ACME_EMAIL=lets.encrypt@example.com
TRAEFIK_ACME_STORAGE=/letsencrypt/acme.json
TRAEFIK_HTTP_PORT=80
TRAEFIK_HTTPS_PORT=443
TRAEFIK_DYNAMIC_DIR=/opt/traefik/dynamic
TRAEFIK_LETSENCRYPT_DIR=/opt/traefik/letsencrypt

367
adguard/README.md Normal file
View File

@@ -0,0 +1,367 @@
# AdGuard Home - Bloqueador de Anuncios DNS
AdGuard Home es un servidor DNS que bloquea anuncios y rastreadores a nivel de red.
## 📋 Descripción
Este stack despliega AdGuard Home con:
- Bloqueo de anuncios y rastreadores
- DNS-over-TLS (DoT) para privacidad
- Panel web protegido con Authentik
- Integración con Traefik para HTTPS
- Configuración persistente
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Asegúrate de que la red `proxy` existe
2. **Registro DNS**: Configura el registro A para tu dominio AdGuard
3. **IP Fija**: AdGuard necesita una IP fija en la red Docker
4. **Certificados DoT**: Necesitarás certificados SSL para DoT
### Configurar IP Fija en la Red Proxy
Primero, verifica el rango de IPs de la red `proxy`:
```bash
docker network inspect proxy | grep Subnet
```
Luego, elige una IP fija dentro del rango (ej: `172.18.0.10`).
### Generar Certificados para DoT
```bash
# Crear directorio para certificados
sudo mkdir -p /opt/adguard/certs
# Copiar certificados de Let's Encrypt (después de que Traefik los genere)
sudo cp /opt/traefik/letsencrypt/certificates/adguard.tudominio.com.crt /opt/adguard/certs/adguard.crt
sudo cp /opt/traefik/letsencrypt/certificates/adguard.tudominio.com.key /opt/adguard/certs/adguard.key
# O genera certificados autofirmados para pruebas
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /opt/adguard/certs/adguard.key \
-out /opt/adguard/certs/adguard.crt \
-subj "/CN=adguard.tudominio.com"
```
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `adguard`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `adguard/docker-compose.yml`
5. Carga el archivo de variables de entorno: `adguard/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno
Edita el archivo `stack.env`:
```env
# Imagen
ADGUARD_IMAGE=adguard/adguardhome:latest
# Dominio
ADGUARD_DOMAIN=adguard.tudominio.com
# IP fija en la red proxy
ADGUARD_IPV4=172.18.0.10
# Puerto DoT (DNS-over-TLS)
ADGUARD_DOT_PORT=853
# Puerto HTTP del panel (interno)
ADGUARD_HTTP_PORT=80
# Rutas
ADGUARD_WORK_PATH=/opt/adguard/work
ADGUARD_CONF_PATH=/opt/adguard/conf
ADGUARD_CERT_CRT_PATH=/opt/adguard/certs/adguard.crt
ADGUARD_CERT_KEY_PATH=/opt/adguard/certs/adguard.key
# Traefik
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
```
## ⚙️ Configuración Post-Instalación
### 1. Configuración Inicial
La primera vez que accedas a `https://adguard.tudominio.com`, se iniciará el asistente:
1. **Puerto de escucha**: Deja 3000 (se cambiará automáticamente a 80)
2. **Usuario y contraseña**: Crea las credenciales de administrador
3. **Interfaces de red**: Escucha en todas las interfaces
4. **DNS upstream**: Configura servidores DNS (ej: `1.1.1.1`, `8.8.8.8`)
> **Nota**: Si el panel escucha en puerto 3000, actualiza `ADGUARD_HTTP_PORT=3000` en el `stack.env` temporalmente.
### 2. Configurar DNS-over-TLS (DoT)
1. En el panel de AdGuard, ve a **Settings****Encryption settings**
2. Habilita **DNS-over-TLS**
3. Configura:
- **Server name**: `adguard.tudominio.com`
- **Certificate**: `/certs/adguard.crt`
- **Private key**: `/certs/adguard.key`
4. **Puerto**: 853
5. Haz clic en **Save**
### 3. Configurar Listas de Filtros
AdGuard viene con listas por defecto, pero puedes añadir más:
1. Ve a **Filters****DNS blocklists**
2. Añade listas populares:
- **Steven Black's Hosts**: Bloquea malware y anuncios
- **OISD**: Lista curada de dominios maliciosos
- **Hagezi**: Listas agresivas de bloqueo
3. Haz clic en **Add blocklist** y pega la URL
Ejemplos:
```
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
https://big.oisd.nl/
https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/domains/pro.txt
```
### 4. Configurar DNS Upstream
Para mejor privacidad, usa DNS cifrados:
1. Ve a **Settings****DNS settings**
2. En **Upstream DNS servers**, añade:
```
https://dns.cloudflare.com/dns-query
https://dns.google/dns-query
tls://1.1.1.1
tls://8.8.8.8
```
3. En **Bootstrap DNS servers** (para resolver los DNS cifrados):
```
1.1.1.1
8.8.8.8
```
## 📱 Configurar Clientes
### Android - DNS Privado (DoT)
1. Ve a **Ajustes** → **Conexiones** → **Más ajustes de conexión**
2. Selecciona **DNS privado**
3. Elige **Nombre del host del proveedor de DNS privado**
4. Introduce: `adguard.tudominio.com`
5. Guarda
> Todo el tráfico DNS de tu móvil pasará por AdGuard, incluso fuera de casa.
### iOS - DNS-over-HTTPS
1. Descarga un perfil de configuración DoH
2. O usa apps como **AdGuard** o **DNSCloak**
### Windows
#### Opción 1: Cambiar DNS del Sistema
1. Panel de Control → Redes → Propiedades del adaptador
2. IPv4 → Propiedades
3. DNS preferido: `IP-de-tu-servidor`
4. DNS alternativo: `8.8.8.8`
#### Opción 2: DNS-over-HTTPS (Windows 11)
1. Ajustes → Red e Internet → Ethernet/Wi-Fi
2. Editar DNS
3. Añade servidor DNS-over-HTTPS: `https://adguard.tudominio.com/dns-query`
### Linux
Edita `/etc/resolv.conf`:
```bash
nameserver IP-de-tu-servidor
nameserver 8.8.8.8
```
O con systemd-resolved:
```bash
sudo nano /etc/systemd/resolved.conf
```
```ini
[Resolve]
DNS=IP-de-tu-servidor
FallbackDNS=8.8.8.8
```
```bash
sudo systemctl restart systemd-resolved
```
### Router
Configura AdGuard como DNS primario en tu router:
1. Accede al panel de tu router
2. Ve a configuración DHCP/DNS
3. DNS primario: `IP-de-tu-servidor`
4. DNS secundario: `8.8.8.8`
> **Ventaja**: Todos los dispositivos de tu red usarán AdGuard automáticamente.
## 🔧 Configuración Avanzada
### Listas Blancas (Whitelist)
Para permitir dominios bloqueados por error:
1. Ve a **Filters** → **Custom filtering rules**
2. Añade reglas:
```
@@||ejemplo-permitido.com^
@@||*.ejemplo.com^
```
### Bloquear Dominios Específicos
```
||dominio-bloqueado.com^
||ads.ejemplo.com^
```
### Reglas de Reescritura DNS
Para resolver dominios internos:
1. Ve a **Filters** → **DNS rewrites**
2. Añade entradas:
- **Domain**: `home.local`
- **Answer**: `192.168.1.10`
### Clientes Personalizados
Para aplicar configuraciones diferentes por cliente:
1. Ve a **Settings** → **Client settings**
2. Añade cliente por IP o ID
3. Configura filtros específicos, upstream DNS, etc.
### Estadísticas y Logs
- **Dashboard**: Ve estadísticas de consultas, clientes, dominios bloqueados
- **Query log**: Revisa todas las consultas DNS en tiempo real
- **Filtros por cliente**: Ve qué dispositivos hacen más consultas
## 🛠️ Troubleshooting
### No puedo acceder al panel web
1. Verifica que AdGuard está corriendo:
```bash
docker ps | grep adguard
```
2. Verifica los logs:
```bash
docker logs adguardhome
```
3. Si el panel está en puerto 3000, cambia `ADGUARD_HTTP_PORT=3000` temporalmente
### DNS no resuelve dominios
1. Verifica que AdGuard está escuchando:
```bash
docker exec adguardhome netstat -tulpn
```
2. Prueba DNS desde el servidor:
```bash
nslookup google.com 172.18.0.10
```
3. Verifica que los upstream DNS están configurados
### DoT no funciona en Android
1. Verifica que el puerto 853 está abierto:
```bash
sudo netstat -tulpn | grep 853
```
2. Verifica los certificados en AdGuard:
- Settings → Encryption → Verifica que están cargados correctamente
3. Prueba DoT desde el servidor:
```bash
kdig -d @adguard.tudominio.com +tls google.com
```
### Algunos sitios no cargan
1. Ve a **Query log** en AdGuard
2. Busca el dominio bloqueado
3. Añádelo a la whitelist si es necesario
### IP fija causa conflictos
Si la IP configurada está en uso:
1. Elige otra IP del rango de la red `proxy`
2. Actualiza `ADGUARD_IPV4` en `stack.env`
3. Actualiza el stack
## 📚 Recursos Adicionales
- [Documentación oficial de AdGuard Home](https://github.com/AdguardTeam/AdGuardHome/wiki)
- [Listas de filtros](https://filterlists.com/)
- [Comparativa con Pi-hole](https://github.com/AdguardTeam/AdGuardHome#comparison)
## 🔒 Seguridad
- **Panel web**: Siempre protegido con Authentik (SSO)
- **DoT**: Cifra las consultas DNS entre cliente y servidor
- **Upstream DNS**: Usa DNS cifrados (DoH/DoT) para privacidad total
- **Logs**: Revisa regularmente los logs para detectar anomalías
- **Actualizaciones**: Mantén AdGuard actualizado
## 💾 Backups
```bash
# Backup de configuración
sudo tar -czf adguard-backup-$(date +%Y%m%d).tar.gz /opt/adguard/
# Restaurar
sudo tar -xzf adguard-backup-YYYYMMDD.tar.gz -C /
```
## 🔄 Actualizaciones
1. Haz backup de la configuración
2. Actualiza en `stack.env`:
```env
ADGUARD_IMAGE=adguard/adguardhome:latest
```
3. Actualiza el stack en Portainer
4. Verifica los logs y el panel web
## 📊 Estadísticas
AdGuard ofrece estadísticas detalladas:
- **Consultas bloqueadas**: Porcentaje y cantidad
- **Top clientes**: Dispositivos que más consultas hacen
- **Top dominios**: Sitios más visitados
- **Top dominios bloqueados**: Anuncios y rastreadores más frecuentes
- **Upstream DNS**: Rendimiento de los servidores DNS configurados
Accede a estas estadísticas en el Dashboard de AdGuard.

View File

@@ -0,0 +1,43 @@
services:
adguardhome:
image: ${ADGUARD_IMAGE}
container_name: adguardhome
restart: unless-stopped
volumes:
- ${ADGUARD_WORK_PATH}:/opt/adguardhome/work:Z
- ${ADGUARD_CONF_PATH}:/opt/adguardhome/conf:Z
- ${ADGUARD_CERT_CRT_PATH}:/certs/adguard.crt:ro,Z
- ${ADGUARD_CERT_KEY_PATH}:/certs/adguard.key:ro,Z
# Solo DNS/DoT expuestos en el host
ports:
# - "53:53/tcp"
# - "53:53/udp"
- "${ADGUARD_DOT_PORT}:853/tcp" # DoT para Android (DNS privado)
# - "81:80/tcp"
networks:
proxy:
ipv4_address: ${ADGUARD_IPV4}
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
# Router HTTPS para el panel web
traefik.http.routers.adguard.rule: "Host(`${ADGUARD_DOMAIN}`)"
traefik.http.routers.adguard.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.adguard.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
# Panel interno de AdGuard (HTTP en el contenedor)
# OJO: si es la primera vez y el panel escucha en 3000, cambia a 3000
traefik.http.services.adguard.loadbalancer.server.port: "${ADGUARD_HTTP_PORT}"
# Proteger el panel con Authentik (middleware definido en authentik-server)
traefik.http.routers.adguard.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE}"
networks:
proxy:
external: true

17
adguard/stack.env Normal file
View File

@@ -0,0 +1,17 @@
##### AdGuard #####
ADGUARD_IMAGE=
ADGUARD_WORK_PATH=
ADGUARD_CONF_PATH=
ADGUARD_CERT_CRT_PATH=
ADGUARD_CERT_KEY_PATH=
ADGUARD_DOT_PORT=
ADGUARD_IPV4=
ADGUARD_HTTP_PORT=
##### Traefik / red #####
TRAEFIK_DOCKER_NETWORK=
ADGUARD_DOMAIN=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=
TRAEFIK_AUTH_MIDDLEWARE=

345
authentik/README.md Normal file
View File

@@ -0,0 +1,345 @@
# Authentik - Sistema de Autenticación SSO
Authentik es un sistema de autenticación y autorización de código abierto que proporciona Single Sign-On (SSO) para tus aplicaciones.
## 📋 Descripción
Este stack despliega Authentik configurado para funcionar con Traefik mediante **Forward Authentication**, protegiendo tus servicios con autenticación centralizada.
## 🚀 Despliegue
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `authentik`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `authentik/docker-compose.yml`
5. Carga el archivo de variables de entorno: `authentik/stack.env`
6. O añade manualmente las variables de entorno necesarias
7. Haz clic en **Deploy the stack**
### Variables de Entorno Importantes
Edita el archivo `stack.env` con tus valores:
```env
# Secretos (genera valores aleatorios seguros)
AUTHENTIK_SECRET_KEY=tu-clave-secreta-aleatoria
AUTHENTIK_POSTGRESQL_PASSWORD=tu-password-db-aleatorio
# Dominio de Authentik
AUTHENTIK_DOMAIN=auth.tudominio.com
# Email y SMTP (opcional pero recomendado)
AUTHENTIK_EMAIL__HOST=smtp.tudominio.com
AUTHENTIK_EMAIL__PORT=587
AUTHENTIK_EMAIL__USERNAME=noreply@tudominio.com
AUTHENTIK_EMAIL__PASSWORD=tu-password-email
AUTHENTIK_EMAIL__FROM=noreply@tudominio.com
```
## ⚙️ Configuración Post-Instalación
Una vez desplegado Authentik, accede a su interfaz web en `https://auth.tudominio.com` y completa la configuración inicial.
### 1. Acceso Inicial
- Usuario por defecto: `akadmin`
- Contraseña: La que configures en el primer acceso
- Cambia la contraseña inmediatamente
### 2. Crear Applications (Aplicaciones)
Para cada servicio que quieras proteger (ej: Portainer, Traefik Dashboard, Gitea, etc.):
1. Ve a **Applications****Create**
2. Completa el formulario:
- **Name**: `Portainer` (nombre descriptivo)
- **Slug**: `portainer` (identificador único en minúsculas)
- **Provider**: (lo crearás en el siguiente paso - déjalo vacío por ahora)
- **Policy engine mode**: `any` (permite acceso si alguna política coincide)
- **UI settings**: Configura el icono y apariencia (opcional)
3. Haz clic en **Create**
### 3. Crear Providers de tipo Forward Auth
Los providers conectan tus aplicaciones con Authentik. Para Forward Auth con Traefik:
1. Ve a **Applications** → Tu aplicación → **Provider****Create**
2. Selecciona tipo: **Proxy Provider**
3. Completa el formulario:
- **Name**: `Portainer Provider`
- **Authorization flow**: Selecciona `default-provider-authorization-implicit-consent` (créalo si no existe - ver paso 4)
- **Type**: **Forward auth (single application)**
- **External host**: `https://portainer.tudominio.com` (URL completa de tu servicio)
- **Internal host**: `http://portainer:9000` (opcional - URL interna si Authentik debe hacer reverse proxy)
- **Internal host SSL validation**: Desactivado (si usas HTTP interno)
4. **Advanced settings**:
- **Token validity**: `hours=24` (duración de la sesión)
- **Cookie domain**: `.tudominio.com` (permite SSO entre subdominios)
5. Haz clic en **Create**
6. Vuelve a la aplicación y selecciona el provider que acabas de crear
### 4. Crear Authorization Flow (Implicit)
El authorization flow de tipo **implicit** permite autorización sin pantalla de consentimiento explícita:
#### Opción A: Usar el flow por defecto
Authentik suele incluir un flow llamado `default-provider-authorization-implicit-consent`. Si existe, úsalo directamente en tus providers.
#### Opción B: Crear un flow personalizado
Si necesitas crear uno nuevo:
1. Ve a **Flows & Stages****Flows****Create**
2. Completa el formulario:
- **Name**: `Authorization Flow Implicit`
- **Title**: `Redirecting to application`
- **Slug**: `default-provider-authorization-implicit-consent`
- **Designation**: **Authorization**
- **Authentication**: `Require authentication` (el usuario debe estar autenticado)
- **Behavior settings**:
- **Layout**: `content_left` o el que prefieras
3. Haz clic en **Create**
#### Añadir Stages al Flow
1. Abre el flow que acabas de crear
2. Ve a la pestaña **Stage Bindings**
3. Añade el stage de consentimiento (opcional):
- Haz clic en **Bind existing stage**
- Selecciona `default-provider-authorization-consent` (o crea uno nuevo)
- **Order**: 10
- **Evaluate on plan**: Activado
- **Re-evaluate policies**: Activado
> **Nota**: Para implicit consent, puedes crear un flow sin stages de consentimiento, lo que permite autorización automática.
#### Crear Stage de Consent (si no existe)
Si necesitas crear el stage de consentimiento:
1. Ve a **Flows & Stages****Stages****Create**
2. Tipo: **Consent Stage**
3. Completa:
- **Name**: `default-provider-authorization-consent`
- **Mode**: `always_require` o `hidden` (para implicit)
- **Consent expire in**: `weeks=4` (duración del consentimiento)
4. Haz clic en **Create**
### 5. Configurar Outpost
Los **outposts** son los componentes que ejecutan los providers y procesan las peticiones de autenticación:
1. Ve a **Outposts****Outposts****Create**
2. Completa el formulario:
- **Name**: `authentik-embedded-outpost` (o el nombre que prefieras)
- **Type**: **Proxy**
- **Integration**: Déjalo vacío (el outpost embedded usa la integración por defecto)
3. **Applications**: Selecciona todas las aplicaciones que creaste (Portainer, Traefik, etc.)
4. **Configuration**:
```yaml
authentik_host: https://auth.tudominio.com
authentik_host_insecure: false
log_level: info
object_naming_template: ak-outpost-%(name)s
docker_network: proxy
docker_labels:
traefik.enable: "true"
```
5. Haz clic en **Create**
#### Verificar Estado del Outpost
1. Ve a **Outposts** → **Outposts**
2. Verifica que tu outpost aparece en estado **Healthy** (saludable)
3. Si aparece como **Unhealthy**:
- Verifica los logs: `docker logs authentik-worker`
- Asegúrate de que el contenedor puede comunicarse con el servidor de Authentik
- Verifica la red Docker `proxy`
### 6. Configurar Middleware en Traefik
Para que Traefik use Authentik como forward auth, necesitas configurar el middleware.
#### Opción A: Middleware en el stack de Authentik
Añade las siguientes labels al servicio `authentik-server` en el `docker-compose.yml`:
```yaml
labels:
# Middleware de Forward Auth
traefik.http.middlewares.authentik.forwardauth.address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
traefik.http.middlewares.authentik.forwardauth.trustForwardHeader: "true"
traefik.http.middlewares.authentik.forwardauth.authResponseHeaders: "X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"
```
#### Opción B: Middleware en archivo de configuración de Traefik
En el archivo de configuración dinámica de Traefik (`dynamic.yml`):
```yaml
http:
middlewares:
authentik:
forwardAuth:
address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true
authResponseHeaders:
- "X-authentik-username"
- "X-authentik-groups"
- "X-authentik-email"
- "X-authentik-name"
- "X-authentik-uid"
```
### 7. Proteger Servicios con Authentik
Una vez configurado el middleware, añade la label a los servicios que quieras proteger:
```yaml
labels:
traefik.http.routers.portainer.middlewares: "authentik@docker"
```
O si definiste el middleware en archivo:
```yaml
labels:
traefik.http.routers.portainer.middlewares: "authentik@file"
```
## 🔐 Gestión de Usuarios y Grupos
### Crear Usuarios
1. Ve a **Directory** → **Users** → **Create**
2. Completa los datos del usuario
3. Asigna grupos si es necesario
4. Haz clic en **Create**
### Crear Grupos
1. Ve a **Directory** → **Groups** → **Create**
2. Nombre del grupo (ej: `admins`, `users`)
3. Añade usuarios al grupo
4. Haz clic en **Create**
### Crear Políticas de Acceso
Para controlar quién puede acceder a cada aplicación:
1. Ve a **Applications** → Tu aplicación → **Policy / Group / User Bindings**
2. Haz clic en **Bind existing policy/group/user**
3. Selecciona un grupo (ej: `admins`)
4. **Order**: 0 (menor número = mayor prioridad)
5. Haz clic en **Create**
## 🔧 Configuración Avanzada
### Configurar Múltiples Dominios (SSO entre subdominios)
En la configuración del provider:
- **Cookie domain**: `.tudominio.com` (con el punto inicial)
- Esto permite que la sesión se comparta entre todos los subdominios
### Configurar Email (SMTP)
Para notificaciones y recuperación de contraseñas:
1. Ve a **System** → **Settings** → **Email**
2. Configura los parámetros SMTP (o usa las variables de entorno en `stack.env`)
### Configurar Autenticación de Dos Factores (2FA)
1. Ve a **Flows & Stages** → **Stages**
2. Crea stages de tipo **Authenticator Validation Stage** (TOTP, WebAuthn, etc.)
3. Añade estos stages a tu authentication flow
### Integración con Proveedores Externos (OAuth, SAML)
1. Ve a **System** → **Providers** → **Create**
2. Selecciona el tipo (OAuth2, SAML, etc.)
3. Configura según el proveedor externo (Google, GitHub, etc.)
## 🛠️ Troubleshooting
### El outpost aparece como Unhealthy
```bash
# Ver logs del worker
docker logs authentik-worker
# Ver logs del servidor
docker logs authentik-server
# Verificar conectividad de red
docker exec authentik-server ping authentik-postgresql
docker exec authentik-server ping authentik-redis
```
### Los servicios no están protegidos
1. Verifica que el middleware de Traefik esté correctamente configurado
2. Comprueba que las labels en el servicio están correctas
3. Verifica los logs de Traefik: `docker logs traefik`
4. Asegúrate de que el provider está asociado a la aplicación
5. Verifica que el outpost esté en estado **Healthy**
### Error "Invalid redirect_uri"
1. Verifica que el **External host** en el provider coincide exactamente con la URL del servicio
2. Asegúrate de incluir el protocolo (`https://`)
3. No incluyas barras finales
### Sesiones no persisten / Se desconecta constantemente
1. Verifica que el **Cookie domain** esté configurado correctamente (`.tudominio.com`)
2. Comprueba que Redis esté funcionando: `docker logs authentik-redis`
3. Aumenta el **Token validity** en el provider
### No puedo acceder al panel de Authentik
1. Accede directamente por IP: `http://IP-servidor:9000`
2. Verifica los logs: `docker logs authentik-server`
3. Comprueba que el dominio DNS está configurado correctamente
4. Verifica que Traefik está redirigiendo correctamente
## 📚 Recursos Adicionales
- [Documentación oficial de Authentik](https://goauthentik.io/docs/)
- [Authentik con Traefik](https://goauthentik.io/docs/providers/proxy/forward_auth)
- [Configuración de Flows](https://goauthentik.io/docs/flow/)
- [Configuración de Outposts](https://goauthentik.io/docs/outposts/)
## 🔒 Seguridad
- **Cambia inmediatamente** el password por defecto de `akadmin`
- Genera valores **aleatorios** para `AUTHENTIK_SECRET_KEY` y `AUTHENTIK_POSTGRESQL_PASSWORD`
- Habilita **2FA** para usuarios administradores
- Realiza **backups regulares** de la base de datos PostgreSQL
- Mantén Authentik **actualizado** a la última versión
## 💾 Backups
Para hacer backup de la configuración de Authentik:
```bash
# Backup de la base de datos PostgreSQL
docker exec authentik-postgresql pg_dump -U authentik authentik > authentik_backup.sql
# Backup de Redis (sesiones)
docker exec authentik-redis redis-cli --rdb /data/dump.rdb
```
## 🔄 Actualizaciones
1. En Portainer, ve a tu stack de Authentik
2. Haz clic en **Editor**
3. Actualiza las versiones de las imágenes si es necesario
4. Haz clic en **Update the stack**
5. O ejecuta: `docker compose pull && docker compose up -d`

View File

@@ -0,0 +1,104 @@
services:
authentik-postgres:
image: ${AUTHENTIK_POSTGRES_IMAGE}
container_name: authentik-postgres
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD}
POSTGRES_USER: ${AUTHENTIK_DB_USER}
POSTGRES_DB: ${AUTHENTIK_DB_NAME}
volumes:
- ${AUTHENTIK_POSTGRES_PATH}:/var/lib/postgresql/data:Z
networks:
- authentik_internal
authentik-redis:
image: ${AUTHENTIK_REDIS_IMAGE}
container_name: authentik-redis
restart: unless-stopped
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
volumes:
- ${AUTHENTIK_REDIS_PATH}:/data:Z
networks:
- authentik_internal
authentik-server:
image: ${AUTHENTIK_IMAGE}
container_name: authentik-server
restart: unless-stopped
command: ["server"]
environment:
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_POSTGRESQL__HOST: ${AUTHENTIK_DB_HOST}
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER}
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME}
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
AUTHENTIK_REDIS__HOST: ${AUTHENTIK_REDIS_HOST}
# Bootstrap inicial (primera vez)
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}
AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN}
depends_on:
- authentik-postgres
- authentik-redis
expose:
- "${AUTHENTIK_HTTP_PORT}"
networks:
- authentik_internal
- proxy
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
# Router del panel de Authentik
traefik.http.routers.authentik.rule: "Host(`${AUTHENTIK_DOMAIN}`)"
traefik.http.routers.authentik.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.authentik.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.services.authentik.loadbalancer.server.port: "${AUTHENTIK_HTTP_PORT}"
# Middleware de forwardAuth que usaremos en Portainer, Pi-hole, etc.
traefik.http.middlewares.authentik.forwardauth.address: "http://authentik-server:${AUTHENTIK_HTTP_PORT}/outpost.goauthentik.io/auth/traefik"
traefik.http.middlewares.authentik.forwardauth.trustForwardHeader: "true"
traefik.http.middlewares.authentik.forwardauth.authResponseHeaders: "X-Authentik-Username,X-Authentik-Groups,X-Authentik-Email,X-Authentik-Uid,X-Authentik-Jwt"
# Callback del outpost en gitea hacia Authentik
traefik.http.routers.authentik-outpost-gitea.rule: "Host(`${GITEA_DOMAIN}`) && PathPrefix(`/outpost.goauthentik.io/`)"
traefik.http.routers.authentik-outpost-gitea.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.authentik-outpost-gitea.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.authentik-outpost-gitea.service: "authentik"
traefik.http.routers.authentik-outpost-gitea.priority: "50"
authentik-worker:
image: ${AUTHENTIK_IMAGE}
container_name: authentik-worker
restart: unless-stopped
command: ["worker"]
environment:
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_POSTGRESQL__HOST: ${AUTHENTIK_DB_HOST}
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER}
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME}
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
AUTHENTIK_REDIS__HOST: ${AUTHENTIK_REDIS_HOST}
depends_on:
- authentik-postgres
- authentik-redis
networks:
- authentik_internal
networks:
proxy:
external: true
authentik_internal:
driver: bridge

30
authentik/stack.env Normal file
View File

@@ -0,0 +1,30 @@
##### Imágenes #####
AUTHENTIK_POSTGRES_IMAGE=
AUTHENTIK_REDIS_IMAGE=
AUTHENTIK_IMAGE=
##### Base de datos Authentik #####
AUTHENTIK_DB_PASSWORD=
AUTHENTIK_DB_USER=
AUTHENTIK_DB_NAME=
AUTHENTIK_DB_HOST=
AUTHENTIK_POSTGRES_PATH=
##### Redis #####
AUTHENTIK_REDIS_HOST=
AUTHENTIK_REDIS_PATH=
##### Authentik #####
AUTHENTIK_SECRET_KEY=
AUTHENTIK_BOOTSTRAP_EMAIL=
AUTHENTIK_BOOTSTRAP_PASSWORD=
AUTHENTIK_BOOTSTRAP_TOKEN=
AUTHENTIK_HTTP_PORT=
##### Traefik / dominios #####
TRAEFIK_DOCKER_NETWORK=
AUTHENTIK_DOMAIN=
GITEA_DOMAIN=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=

7
docker-compose.9443.yml Normal file
View File

@@ -0,0 +1,7 @@
services:
portainer:
ports:
- "9443:9443"
# Si quisieras también el edge:
# - "8000:8000"

55
docker-compose.yml Normal file
View File

@@ -0,0 +1,55 @@
services:
portainer:
image: ${PORTAINER_IMAGE:-portainer/portainer-ce:latest}
container_name: portainer
restart: unless-stopped
env_file:
- .env
volumes:
# Clave de cifrado: misma clave montada en las dos rutas
- ${PORTAINER_SECRET_PATH:-/opt/portainer/secrets/portainer}:/run/secrets/portainer:ro,Z
- ${PORTAINER_SECRET_PATH:-/opt/portainer/secrets/portainer}:/run/portainer/portainer:ro,Z
# Socket de Docker (NO usar :Z aquí)
- /var/run/docker.sock:/var/run/docker.sock:ro
# Datos de Portainer (DB cifrada incluida)
- ${PORTAINER_DATA_PATH:-/opt/portainer/data}:/data:Z
# SELinux: evita bloqueos con docker.sock
security_opt:
- label=disable
networks:
- proxy
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK:-proxy}"
############################
# 1) UI protegida (ej: SSO)
############################
traefik.http.routers.portainer.rule: "Host(`${PORTAINER_DOMAIN:-portainer.example.com}`)"
traefik.http.routers.portainer.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE:-websecure}"
traefik.http.routers.portainer.tls.certresolver: "${TRAEFIK_CERTRESOLVER:-letsencrypt}"
traefik.http.routers.portainer.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE:-authentik@docker}"
traefik.http.services.portainer.loadbalancer.server.port: "${PORTAINER_HTTP_PORT:-9000}"
#########################################################
# 2) API/App móvil SIN SSO, restringida por IP (ej: VPN)
#########################################################
traefik.http.middlewares.portainer-api-ip.ipwhitelist.sourcerange: "${PORTAINER_API_IP_WHITELIST:-10.8.0.0/24,172.18.0.1/32}"
traefik.http.routers.portainer-direct.rule: "Host(`${PORTAINER_API_DOMAIN:-portainer-api.example.com}`)"
traefik.http.routers.portainer-direct.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE:-websecure}"
traefik.http.routers.portainer-direct.tls.certresolver: "${TRAEFIK_CERTRESOLVER:-letsencrypt}"
traefik.http.routers.portainer-direct.middlewares: "portainer-api-ip"
traefik.http.routers.portainer-direct.service: "portainer"
traefik.http.routers.portainer-direct.priority: "100"
networks:
proxy:
external: true

379
gitea/README.md Normal file
View File

@@ -0,0 +1,379 @@
# Gitea - Servidor Git Autoalojado
Gitea es un servidor Git ligero y autoalojado, similar a GitHub o GitLab.
## 📋 Descripción
Este stack despliega Gitea con:
- Base de datos PostgreSQL
- Servidor SSH para operaciones Git
- Gitea Actions (CI/CD similar a GitHub Actions)
- Act Runner para ejecutar pipelines
- Integración con Traefik y Authentik
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Asegúrate de que la red `proxy` existe
2. **Registro DNS**: Configura el registro A para tu dominio Gitea
3. **Puerto SSH**: El puerto SSH debe estar disponible (por defecto 222)
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `gitea`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `gitea/docker-compose.yml`
5. Carga el archivo de variables de entorno: `gitea/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno Importantes
Edita el archivo `stack.env`:
```env
# Imágenes
GITEA_IMAGE=gitea/gitea:latest
GITEA_POSTGRES_IMAGE=postgres:16
GITEA_RUNNER_IMAGE=gitea/act_runner:latest
# Base de datos
GITEA_DB_PASSWORD=tu-password-seguro-aleatorio
# Dominios
GITEA_DOMAIN=git.tudominio.com
GITEA_ROOT_URL=https://git.tudominio.com
# SSH
GITEA_SSH_DOMAIN=git.tudominio.com
GITEA_SSH_PORT=222
# Gitea Actions Runner
GITEA_RUNNER_REGISTRATION_TOKEN=tu-token-de-registro
```
## ⚙️ Configuración Post-Instalación
### 1. Primer Acceso
1. Accede a `https://git.tudominio.com`
2. Completa la configuración inicial:
- Base de datos: Ya está configurada (PostgreSQL)
- Configuración del servidor: Usa los valores predefinidos
- **Importante**: Crea la cuenta de administrador en este paso
3. Haz clic en **Install Gitea**
### 2. Configurar Gitea Actions
Para habilitar CI/CD con Gitea Actions:
#### Paso 1: Generar Token de Registro
1. Accede a Gitea como administrador
2. Ve a **Site Administration****Actions****Runners**
3. Haz clic en **Create new Runner**
4. Copia el **Registration Token**
#### Paso 2: Actualizar el Stack
1. Edita el archivo `stack.env`
2. Añade el token:
```env
GITEA_RUNNER_REGISTRATION_TOKEN=tu-token-copiado
```
3. Actualiza el stack en Portainer
#### Paso 3: Verificar el Runner
1. En Gitea, ve a **Site Administration** → **Actions** → **Runners**
2. Deberías ver el runner registrado y activo
3. Nombre del runner: `act-runner-docker` (o el configurado en `GITEA_RUNNER_NAME`)
### 3. Configurar SSH
Para usar Git con SSH:
```bash
# Clonar repositorio con SSH
git clone ssh://git@git.tudominio.com:222/usuario/repositorio.git
# O configurar SSH en ~/.ssh/config
Host git.tudominio.com
HostName git.tudominio.com
Port 222
User git
IdentityFile ~/.ssh/id_ed25519
```
### 4. Integración con Authentik (SSO)
Este stack tiene una configuración especial para Authentik:
#### Rutas Protegidas
- `/user/login` - Página de login (protegida con SSO)
- `/explore` - Explorar repositorios públicos (protegida)
- `/TheHomelessSherlock` - Perfil de usuario específico (protegido)
#### Rutas Públicas
- Repositorios públicos accesibles sin autenticación
- API Git (clone, pull, push) funciona sin SSO
#### Configurar OAuth con Authentik
1. En Authentik, crea una aplicación para Gitea:
- Tipo: **OAuth2/OpenID Provider**
- Client type: **Confidential**
- Redirect URIs: `https://git.tudominio.com/user/oauth2/authentik/callback`
2. En Gitea, ve a **Site Administration** → **Authentication Sources** → **Add Authentication Source**
3. Tipo: **OAuth2**
4. Configura:
- Provider: **OpenID Connect**
- Client ID: (de Authentik)
- Client Secret: (de Authentik)
- OpenID Connect Auto Discovery URL: `https://auth.tudominio.com/application/o/gitea/.well-known/openid-configuration`
5. Actualiza las variables en `stack.env`:
```env
GITEA_ENABLE_OPENID_SIGNIN=true
GITEA_ENABLE_OPENID_SIGNUP=true
GITEA_DISABLE_LOGIN_FORM=false # Mantén false para permitir login local también
```
## 🔧 Configuración Avanzada
### Personalización de la UI
Las siguientes opciones están preconfiguradas:
- **Tema por defecto**: Oscuro (`gitea-dark`)
- **Registro deshabilitado**: Solo administradores pueden crear usuarios (o usar SSO)
- **Visibilidad por defecto**: Privada
- **Requiere login para ver**: Activado
Para cambiar estas opciones, edita `stack.env` y actualiza el stack.
### Limitar Acceso por Organización
```env
GITEA_DEFAULT_ALLOW_CREATE_ORGANIZATION=false
GITEA_DEFAULT_ORG_VISIBILITY=private
```
### Notificaciones por Email
Añade al archivo `stack.env`:
```env
GITEA__mailer__ENABLED=true
GITEA__mailer__FROM=gitea@tudominio.com
GITEA__mailer__PROTOCOL=smtp
GITEA__mailer__SMTP_ADDR=smtp.tudominio.com
GITEA__mailer__SMTP_PORT=587
GITEA__mailer__USER=gitea@tudominio.com
GITEA__mailer__PASSWD=tu-password-smtp
```
### Configurar Webhooks
Gitea soporta webhooks para integración con otros servicios:
1. Ve a tu repositorio → **Settings** → **Webhooks**
2. Añade un webhook con la URL de destino
3. Selecciona los eventos que quieres recibir
### Ejemplo de Workflow con Gitea Actions
Crea `.gitea/workflows/build.yml` en tu repositorio:
```yaml
name: Build and Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Test
run: npm test
```
## 🛠️ Troubleshooting
### No puedo hacer push/pull por SSH
1. Verifica que el puerto SSH está abierto:
```bash
telnet git.tudominio.com 222
```
2. Verifica tu clave SSH:
```bash
ssh -T git@git.tudominio.com -p 222
```
3. Añade tu clave SSH en Gitea:
- Ve a **Settings** → **SSH / GPG Keys** → **Add Key**
### El runner de Actions no se registra
1. Verifica los logs:
```bash
docker logs gitea-act-runner
```
2. Verifica que el token es correcto en `stack.env`
3. Regenera el token en Gitea si es necesario
4. Asegúrate de que el runner puede comunicarse con Gitea:
```bash
docker exec gitea-act-runner ping gitea
```
### Error de permisos con volúmenes
Si usas SELinux, los volúmenes ya tienen `:Z`:
```bash
# Si persisten problemas
sudo chcon -Rt svirt_sandbox_file_t /opt/gitea/data
sudo chcon -Rt svirt_sandbox_file_t /opt/gitea/postgres
```
### OAuth con Authentik no funciona
1. Verifica que la Redirect URI en Authentik es exacta
2. Comprueba que el Discovery URL es accesible desde el contenedor:
```bash
docker exec gitea curl https://auth.tudominio.com/application/o/gitea/.well-known/openid-configuration
```
3. Revisa los logs de Gitea: `docker logs gitea`
### La base de datos no inicia
1. Verifica los logs de PostgreSQL:
```bash
docker logs gitea-postgres
```
2. Verifica los permisos del directorio de datos:
```bash
ls -lh /opt/gitea/postgres
```
3. Si necesitas reiniciar desde cero:
```bash
docker compose down
sudo rm -rf /opt/gitea/postgres/*
docker compose up -d
```
## 📚 Recursos Adicionales
- [Documentación oficial de Gitea](https://docs.gitea.io/)
- [Gitea Actions](https://docs.gitea.io/en-us/usage/actions/overview/)
- [Act Runner](https://gitea.com/gitea/act_runner)
- [Migrar desde GitHub/GitLab](https://docs.gitea.io/en-us/usage/migrations/)
## 🔒 Seguridad
- **SSH**: Usa claves SSH en lugar de passwords para Git
- **2FA**: Habilita autenticación de dos factores en tu cuenta
- **Tokens**: Usa tokens de acceso con permisos limitados para CI/CD
- **Webhooks**: Verifica siempre las firmas de webhooks
- **Backups**: Realiza backups regulares de la base de datos y repositorios
## 💾 Backups
### Backup de la Base de Datos
```bash
# Backup completo
docker exec gitea-postgres pg_dump -U gitea gitea > gitea_backup_$(date +%Y%m%d).sql
# Restaurar
cat gitea_backup_YYYYMMDD.sql | docker exec -i gitea-postgres psql -U gitea gitea
```
### Backup de Repositorios y Datos
```bash
# Backup completo de datos
sudo tar -czf gitea-data-backup-$(date +%Y%m%d).tar.gz /opt/gitea/data
# Restaurar
sudo tar -xzf gitea-data-backup-YYYYMMDD.tar.gz -C /
```
### Backup Automático
Considera usar el comando nativo de Gitea:
```bash
docker exec -u git gitea gitea dump -c /data/gitea/conf/app.ini
```
Esto crea un archivo `gitea-dump-*.zip` con todo lo necesario para restaurar.
## 🔄 Actualizaciones
1. **Backup primero**: Siempre haz backup antes de actualizar
2. Actualiza la versión en `stack.env`:
```env
GITEA_IMAGE=gitea/gitea:1.21.0
```
3. Actualiza el stack en Portainer
4. Verifica los logs: `docker logs gitea`
5. Prueba que todo funciona correctamente
## 📊 Monitoreo
### Ver Estadísticas
- Accede a **Site Administration** → **Dashboard**
- Revisa usuarios, repositorios, organizaciones, etc.
### Logs
```bash
# Logs de Gitea
docker logs -f gitea
# Logs de PostgreSQL
docker logs -f gitea-postgres
# Logs del Runner
docker logs -f gitea-act-runner
```
### Métricas
Gitea soporta exportación de métricas para Prometheus:
1. Habilita métricas en `stack.env`:
```env
GITEA__metrics__ENABLED=true
GITEA__metrics__TOKEN=tu-token-secreto
```
2. Las métricas estarán disponibles en: `https://git.tudominio.com/metrics?token=tu-token-secreto`

126
gitea/docker-compose.yml Normal file
View File

@@ -0,0 +1,126 @@
services:
postgres:
image: ${GITEA_POSTGRES_IMAGE}
container_name: gitea-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${GITEA_DB_NAME}
POSTGRES_USER: ${GITEA_DB_USER}
POSTGRES_PASSWORD: ${GITEA_DB_PASSWORD}
TZ: ${TZ}
volumes:
- ${GITEA_POSTGRES_PATH}:/var/lib/postgresql/data:Z
networks:
- gitea
gitea:
image: ${GITEA_IMAGE}
container_name: gitea
restart: unless-stopped
depends_on:
- postgres
environment:
USER_UID: ${GITEA_USER_UID}
USER_GID: ${GITEA_USER_GID}
TZ: ${TZ}
# Base de datos
GITEA__database__DB_TYPE: ${GITEA_DB_TYPE}
GITEA__database__HOST: ${GITEA_DB_HOST}:${GITEA_DB_PORT}
GITEA__database__NAME: ${GITEA_DB_NAME}
GITEA__database__USER: ${GITEA_DB_USER}
GITEA__database__PASSWD: ${GITEA_DB_PASSWORD}
# URLs HTTP
GITEA__server__DOMAIN: ${GITEA_DOMAIN}
GITEA__server__ROOT_URL: ${GITEA_ROOT_URL}
GITEA__server__PROTOCOL: ${GITEA_SERVER_PROTOCOL}
GITEA__server__HTTP_PORT: ${GITEA_HTTP_PORT}
# SSH
GITEA__server__SSH_DOMAIN: ${GITEA_SSH_DOMAIN}
GITEA__server__SSH_PORT: ${GITEA_SSH_PORT}
GITEA__server__START_SSH_SERVER: ${GITEA_START_SSH_SERVER}
# Actions
GITEA__actions__ENABLED: ${GITEA_ACTIONS_ENABLED}
# Registro y visibilidad
GITEA__service__DISABLE_REGISTRATION: ${GITEA_DISABLE_REGISTRATION}
GITEA__service__REQUIRE_SIGNIN_VIEW: ${GITEA_REQUIRE_SIGNIN_VIEW}
GITEA__service__ENABLE_OPENID_SIGNUP: ${GITEA_ENABLE_OPENID_SIGNUP}
GITEA__service__ENABLE_OPENID_SIGNIN: ${GITEA_ENABLE_OPENID_SIGNIN}
GITEA__service__DISABLE_LOGIN_FORM: ${GITEA_DISABLE_LOGIN_FORM}
GITEA__service__HIDE_EMAIL_ADDRESS: ${GITEA_HIDE_EMAIL_ADDRESS}
GITEA__service__DEFAULT_ALLOW_CREATE_ORGANIZATION: ${GITEA_DEFAULT_ALLOW_CREATE_ORGANIZATION}
GITEA__service__DEFAULT_ORG_VISIBILITY: ${GITEA_DEFAULT_ORG_VISIBILITY}
GITEA__service__DEFAULT_VISIBILITY: ${GITEA_DEFAULT_VISIBILITY}
# UI Oscuro
GITEA__ui__DEFAULT_THEME: ${GITEA_DEFAULT_THEME}
GITEA__ui__THEMES: ${GITEA_UI_THEMES}
volumes:
- ${GITEA_DATA_PATH}:/data:Z
networks:
- gitea
- proxy
# Exponer SSH (contenedor y host mismo puerto)
ports:
- "${GITEA_SSH_PORT}:${GITEA_SSH_PORT}"
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
traefik.http.services.gitea.loadbalancer.server.port: "${GITEA_HTTP_PORT}"
# Router principal (sin Authentik)
traefik.http.routers.gitea-main.rule: "Host(`${GITEA_DOMAIN}`)"
traefik.http.routers.gitea-main.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.gitea-main.tls: "true"
traefik.http.routers.gitea-main.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.gitea-main.priority: "10"
# Router login + explore + perfil TheHomelessSherlock (con Authentik)
traefik.http.routers.gitea-login.rule: >-
Host(`${GITEA_DOMAIN}`) &&
(Path(`/user/login`) ||
PathPrefix(`/user/sign_up`) ||
PathPrefix(`/user/forgot_password`) ||
PathPrefix(`/user/two_factor`) ||
PathPrefix(`/login/oauth`) ||
PathPrefix(`/explore`) ||
PathPrefix(`/api`) ||
PathPrefix(`/api/swagger`) ||
PathRegexp(`^/TheHomelessSherlock/?$`))
traefik.http.routers.gitea-login.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.gitea-login.tls: "true"
traefik.http.routers.gitea-login.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.gitea-login.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE}"
traefik.http.routers.gitea-login.priority: "20"
gitea-runner:
image: ${GITEA_RUNNER_IMAGE}
container_name: gitea-act-runner
restart: unless-stopped
depends_on:
- gitea
environment:
GITEA_INSTANCE_URL: ${GITEA_INSTANCE_URL}
GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN}
GITEA_RUNNER_NAME: ${GITEA_RUNNER_NAME}
GITEA_RUNNER_LABELS: ${GITEA_RUNNER_LABELS}
volumes:
- ${GITEA_RUNNER_DATA_PATH}:/data:Z
- /var/run/docker.sock:/var/run/docker.sock:Z
networks:
- gitea
networks:
gitea:
driver: bridge
proxy:
external: true

56
gitea/stack.env Normal file
View File

@@ -0,0 +1,56 @@
##### Postgres Gitea #####
GITEA_POSTGRES_IMAGE=
GITEA_DB_NAME=
GITEA_DB_USER=
GITEA_DB_PASSWORD=
TZ=
GITEA_POSTGRES_PATH=
##### Gitea #####
GITEA_IMAGE=
GITEA_USER_UID=
GITEA_USER_GID=
GITEA_DB_TYPE=
GITEA_DB_HOST=
GITEA_DB_PORT=
GITEA_DOMAIN=
GITEA_ROOT_URL=
GITEA_SERVER_PROTOCOL=
GITEA_HTTP_PORT=
GITEA_SSH_DOMAIN=
GITEA_SSH_PORT=
GITEA_START_SSH_SERVER=
GITEA_ACTIONS_ENABLED=
GITEA_DISABLE_REGISTRATION=
GITEA_REQUIRE_SIGNIN_VIEW=
GITEA_ENABLE_OPENID_SIGNUP=
GITEA_ENABLE_OPENID_SIGNIN=
GITEA_DISABLE_LOGIN_FORM=
GITEA_HIDE_EMAIL_ADDRESS=
GITEA_DEFAULT_ALLOW_CREATE_ORGANIZATION=
GITEA_DEFAULT_ORG_VISIBILITY=
GITEA_DEFAULT_VISIBILITY=
GITEA_DEFAULT_THEME=
GITEA_UI_THEMES=
GITEA_DATA_PATH=
##### Traefik #####
TRAEFIK_DOCKER_NETWORK=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=
TRAEFIK_AUTH_MIDDLEWARE=
##### Runner #####
GITEA_RUNNER_IMAGE=
GITEA_INSTANCE_URL=
GITEA_RUNNER_REGISTRATION_TOKEN=
GITEA_RUNNER_NAME=
GITEA_RUNNER_LABELS=
GITEA_RUNNER_DATA_PATH=

370
n8n/README.md Normal file
View File

@@ -0,0 +1,370 @@
# n8n - Plataforma de Automatización
n8n es una plataforma de automatización de código abierto que permite conectar diferentes servicios y crear flujos de trabajo (workflows).
## 📋 Descripción
Este stack despliega n8n con:
- Base de datos PostgreSQL para persistencia
- Integración con Traefik para acceso HTTPS
- Webhooks públicos sin autenticación
- UI protegida con Authentik (SSO)
- Cifrado de credenciales
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Asegúrate de que la red `proxy` existe
2. **Registro DNS**: Configura el registro A para tu dominio n8n
3. **Clave de cifrado**: Genera una clave segura para cifrar credenciales
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `n8n`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `n8n/docker-compose.yml`
5. Carga el archivo de variables de entorno: `n8n/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno Importantes
Edita el archivo `stack.env`:
```env
# Base de datos PostgreSQL
POSTGRES_PASSWORD=tu-password-seguro-aleatorio
N8N_DB_PASSWORD=tu-password-seguro-aleatorio
# Dominio y URLs
N8N_DOMAIN=n8n.tudominio.com
N8N_HOST=n8n.tudominio.com
N8N_WEBHOOK_URL=https://n8n.tudominio.com/
# Cifrado de credenciales (IMPORTANTE: genera una clave única y guárdala)
N8N_ENCRYPTION_KEY=tu-clave-de-cifrado-aleatoria-muy-larga
# Zona horaria
N8N_TIMEZONE=Europe/Madrid
```
> **⚠️ CRÍTICO**: La `N8N_ENCRYPTION_KEY` es **fundamental**. Si la pierdes, perderás acceso a todas las credenciales guardadas. Haz backup de esta clave.
### Generar Clave de Cifrado
```bash
openssl rand -hex 32
```
## ⚙️ Configuración Post-Instalación
### 1. Primer Acceso
1. Accede a `https://n8n.tudominio.com`
2. Si Authentik está configurado, serás redirigido al login de SSO
3. Completa la configuración inicial de n8n:
- Email del propietario
- Nombre de la instancia (opcional)
- Preferencias de uso
### 2. Crear tu Primer Workflow
1. Haz clic en **Create new workflow**
2. Añade un nodo trigger (ej: **Webhook**, **Schedule**, **Manual**)
3. Añade nodos de acción (ej: **HTTP Request**, **Gmail**, **Slack**)
4. Conecta los nodos
5. Haz clic en **Execute workflow** para probar
6. Activa el workflow
### 3. Configurar Credenciales
Para servicios externos (Gmail, Slack, etc.):
1. Haz clic en un nodo que requiera credenciales
2. Haz clic en **Create New Credential**
3. Completa los datos de autenticación
4. Las credenciales se cifran automáticamente con `N8N_ENCRYPTION_KEY`
## 🔧 Uso de Webhooks
### Webhooks Públicos
Los webhooks NO están protegidos por Authentik, permitiendo que servicios externos los activen:
- URL de producción: `https://n8n.tudominio.com/webhook/tu-id-webhook`
- URL de test: `https://n8n.tudominio.com/webhook-test/tu-id-webhook`
### Ejemplo de Webhook
1. Crea un workflow con un nodo **Webhook**
2. Configura:
- **HTTP Method**: `POST` (o el que necesites)
- **Path**: `mi-webhook` (se generará automáticamente)
3. Activa el workflow
4. Copia la URL del webhook
5. Pruébalo:
```bash
curl -X POST https://n8n.tudominio.com/webhook/mi-webhook \
-H "Content-Type: application/json" \
-d '{"mensaje": "Hola desde webhook"}'
```
### Webhook con Autenticación
Para proteger webhooks, añade autenticación en el propio workflow:
1. Añade un nodo **IF** después del webhook
2. Verifica un token o firma en los headers:
```javascript
{{ $node["Webhook"].json.headers.authorization }} === "Bearer mi-token-secreto"
```
## 🔧 Configuración Avanzada
### Variables de Entorno
n8n soporta muchas variables de entorno. Algunas útiles:
```env
# Ejecución
N8N_DEFAULT_BINARY_DATA_MODE=filesystem
EXECUTIONS_DATA_SAVE_ON_ERROR=all
EXECUTIONS_DATA_SAVE_ON_SUCCESS=all
EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true
# Timeout
EXECUTIONS_TIMEOUT=300
EXECUTIONS_TIMEOUT_MAX=3600
# Comunidad
N8N_TEMPLATES_ENABLED=true
N8N_TEMPLATES_HOST=https://api.n8n.io/api/
# Logs
N8N_LOG_LEVEL=info
N8N_LOG_OUTPUT=console
```
### Integración con Servicios Externos
#### Gmail
1. Crea credenciales OAuth2 en Google Cloud Console
2. En n8n, añade credencial de tipo **Gmail OAuth2**
3. Completa Client ID y Client Secret
4. Autoriza la aplicación
#### Slack
1. Crea una Slack App en api.slack.com
2. Añade permisos necesarios (chat:write, etc.)
3. En n8n, añade credencial de tipo **Slack OAuth2**
4. Autoriza la aplicación
#### Webhooks de GitHub
1. En tu repositorio de GitHub, ve a **Settings** → **Webhooks**
2. Añade webhook URL: `https://n8n.tudominio.com/webhook/github`
3. Selecciona eventos (push, pull request, etc.)
4. En n8n, procesa los eventos con nodos **IF** y **Switch**
### Programar Ejecuciones
Usa el nodo **Schedule Trigger**:
```
# Cada hora
0 * * * *
# Cada día a las 9:00
0 9 * * *
# Cada lunes a las 8:30
30 8 * * 1
# Cada 5 minutos
*/5 * * * *
```
## 🛠️ Troubleshooting
### No puedo acceder a n8n
1. Verifica que el DNS apunta correctamente:
```bash
nslookup n8n.tudominio.com
```
2. Verifica los logs:
```bash
docker logs n8n
```
3. Verifica Traefik:
```bash
docker logs traefik | grep n8n
```
### Los webhooks no funcionan
1. Verifica que la URL del webhook es correcta
2. Asegúrate de que el workflow está **activado**
3. Revisa los logs de ejecución en n8n
4. Verifica que la configuración de Traefik permite webhooks sin autenticación
5. Prueba con curl:
```bash
curl -v https://n8n.tudominio.com/webhook/test
```
### Error al guardar credenciales
1. Verifica que `N8N_ENCRYPTION_KEY` está configurada
2. No cambies nunca esta clave después del primer uso
3. Revisa los logs: `docker logs n8n`
### La base de datos no conecta
1. Verifica que PostgreSQL está corriendo:
```bash
docker ps | grep n8n-pg
```
2. Verifica los logs de PostgreSQL:
```bash
docker logs n8n-pg
```
3. Verifica las credenciales en `stack.env`
### Workflows se ejecutan lentamente
1. Aumenta los recursos del contenedor
2. Verifica el timeout en variables de entorno
3. Optimiza el workflow (divide en workflows más pequeños)
4. Revisa los logs de ejecución
### Error "Execution timed out"
Aumenta el timeout en `stack.env`:
```env
EXECUTIONS_TIMEOUT=600
EXECUTIONS_TIMEOUT_MAX=7200
```
## 📚 Recursos Adicionales
- [Documentación oficial de n8n](https://docs.n8n.io/)
- [Workflows de ejemplo](https://n8n.io/workflows/)
- [Integrations](https://n8n.io/integrations/)
- [Forum de la comunidad](https://community.n8n.io/)
## 🎯 Casos de Uso
### Automatización de GitHub
- Notificar en Slack cuando hay un nuevo PR
- Ejecutar tests automáticos
- Crear issues desde emails
### Backup Automático
- Backup de bases de datos a Google Drive
- Notificaciones de éxito/error
- Programar backups diarios
### Monitoreo
- Verificar disponibilidad de sitios web
- Alertas por email/Slack si un servicio está caído
- Recopilar métricas y enviar a InfluxDB
### Integración con CRM
- Sincronizar contactos entre sistemas
- Automatizar seguimiento de leads
- Generar reportes automáticos
### Procesamiento de Datos
- Extraer datos de APIs
- Transformar y limpiar datos
- Cargar en bases de datos
## 🔒 Seguridad
- **Credenciales**: Todas las credenciales se cifran con `N8N_ENCRYPTION_KEY`
- **Webhooks**: Implementa autenticación personalizada en webhooks sensibles
- **UI**: Protegida con Authentik (SSO)
- **Backups**: Haz backup de la clave de cifrado y la base de datos
- **Variables**: No expongas secrets en los workflows; usa credenciales
## 💾 Backups
### Backup de la Base de Datos
```bash
# Backup
docker exec n8n-pg pg_dump -U n8n n8n > n8n_backup_$(date +%Y%m%d).sql
# Restaurar
cat n8n_backup_YYYYMMDD.sql | docker exec -i n8n-pg psql -U n8n n8n
```
### Backup de la Clave de Cifrado
Guarda `N8N_ENCRYPTION_KEY` en un lugar seguro:
```bash
# Extraer del stack.env
grep N8N_ENCRYPTION_KEY stack.env > encryption_key_backup.txt
# Guardar en un gestor de contraseñas o vault
```
### Backup de Workflows
n8n guarda workflows en la base de datos, por lo que el backup de PostgreSQL incluye los workflows.
También puedes exportar workflows manualmente:
1. En n8n, abre un workflow
2. Haz clic en los 3 puntos → **Download**
3. Guarda el archivo JSON
## 🔄 Actualizaciones
1. Haz **backup** de la base de datos y la clave de cifrado
2. Actualiza en `stack.env`:
```env
N8N_IMAGE=n8nio/n8n:latest
```
3. Actualiza el stack en Portainer
4. Verifica los logs: `docker logs n8n`
5. Prueba algunos workflows críticos
> **Nota**: n8n se actualiza frecuentemente. Revisa las [release notes](https://github.com/n8n-io/n8n/releases) antes de actualizar.
## 📊 Monitoreo
### Ver Ejecuciones
En n8n:
1. Ve a **Executions**
2. Filtra por estado (éxito, error, corriendo)
3. Revisa logs detallados de cada ejecución
### Logs del Contenedor
```bash
# Logs en tiempo real
docker logs -f n8n
# Últimas 100 líneas
docker logs --tail 100 n8n
# Logs con timestamps
docker logs -t n8n
```
### Métricas
n8n no tiene métricas Prometheus por defecto, pero puedes:
1. Crear un workflow que publique métricas
2. Usar el nodo HTTP Request para enviar a un collector
3. Monitorear logs con herramientas como Loki/Grafana

71
n8n/docker-compose.yml Normal file
View File

@@ -0,0 +1,71 @@
services:
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
container_name: n8n
environment:
- DB_TYPE=${N8N_DB_TYPE}
- DB_POSTGRESDB_HOST=${N8N_DB_HOST}
- DB_POSTGRESDB_PORT=${N8N_DB_PORT}
- DB_POSTGRESDB_DATABASE=${N8N_DB_NAME}
- DB_POSTGRESDB_USER=${N8N_DB_USER}
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD}
- N8N_HOST=${N8N_HOST}
- N8N_PORT=${N8N_PORT}
- N8N_PROTOCOL=${N8N_PROTOCOL}
- WEBHOOK_URL=${N8N_WEBHOOK_URL}
- GENERIC_TIMEZONE=${N8N_TIMEZONE}
# Clave para cifrar credenciales
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- NODE_ENV=${N8N_NODE_ENV}
- N8N_DIAGNOSTICS_ENABLED=${N8N_DIAGNOSTICS_ENABLED}
networks:
- proxy
- n8n
labels:
traefik.enable: "true"
traefik.docker.network: "proxy"
traefik.http.routers.n8n-ui.rule: "Host(`${N8N_DOMAIN}`)"
traefik.http.routers.n8n-ui.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.n8n-ui.tls: "true"
traefik.http.routers.n8n-ui.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.n8n-ui.service: "n8n"
traefik.http.routers.n8n-ui.priority: "10"
traefik.http.routers.n8n-ui.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE}"
traefik.http.routers.n8n-webhook.rule: "Host(`${N8N_DOMAIN}`) && (PathPrefix(`/webhook`) || PathPrefix(`/webhook-test`))"
traefik.http.routers.n8n-webhook.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.n8n-webhook.tls: "true"
traefik.http.routers.n8n-webhook.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.n8n-webhook.service: "n8n"
traefik.http.routers.n8n-webhook.priority: "20"
traefik.http.services.n8n.loadbalancer.server.port: "${N8N_PORT}"
n8n-db:
image: postgres:16
container_name: n8n-pg
restart: unless-stopped
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- ${N8N_DB_DATA_PATH}:/var/lib/postgresql/data:Z
networks:
- n8n
networks:
proxy:
external: true
n8n:
driver: bridge

36
n8n/stack.env Normal file
View File

@@ -0,0 +1,36 @@
##### n8n - Base de datos #####
N8N_DB_TYPE=
N8N_DB_HOST=
N8N_DB_PORT=
N8N_DB_NAME=
N8N_DB_USER=
N8N_DB_PASSWORD=
##### n8n - Servidor / dominio #####
N8N_HOST=
N8N_PORT=
N8N_PROTOCOL=
N8N_WEBHOOK_URL=
N8N_TIMEZONE=
# Genera una nueva con: openssl rand -hex 32
N8N_ENCRYPTION_KEY=
N8N_NODE_ENV=
N8N_DIAGNOSTICS_ENABLED=
##### PostgreSQL interno #####
POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=
# Ruta en el host para los datos de Postgres (relativa o absoluta)
N8N_DB_DATA_PATH=
##### Traefik #####
N8N_DOMAIN=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=
TRAEFIK_AUTH_MIDDLEWARE=

438
ruleta/README.md Normal file
View File

@@ -0,0 +1,438 @@
# Ruleta - Aplicación Next.js
Aplicación web personalizada construida con Next.js.
## 📋 Descripción
Este stack despliega una aplicación Next.js con:
- Dos rutas de acceso: subdominio y path
- Integración con Traefik para HTTPS
- Soporte para múltiples dominios
- Configuración opcional de Authentik (SSO)
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Asegúrate de que la red `proxy` existe
2. **Registros DNS**: Configura los registros A para tus dominios
3. **Imagen Docker**: La aplicación debe estar construida como imagen Docker
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `ruleta`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `ruleta/docker-compose.yml`
5. Carga el archivo de variables de entorno: `ruleta/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno
Edita el archivo `stack.env`:
```env
# Imagen de la aplicación (construida previamente)
RULETA_IMAGE=tu-usuario/ruleta:latest
# Entorno de Node.js
RULETA_NODE_ENV=production
RULETA_NEXT_TELEMETRY_DISABLED=1
# Puerto interno de Next.js
RULETA_APP_PORT=3000
# Dominios
# Opción 1: Subdominio dedicado
RULETA_SUBDOMAIN=ruleta.tudominio.com
# Opción 2: Path en dominio principal
RULETA_MAIN_DOMAIN=tudominio.com
# Traefik
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
# Si usas Supabase, descomenta y configura:
# NEXT_PUBLIC_SUPABASE_URL=https://tu-proyecto.supabase.co
# NEXT_PUBLIC_SUPABASE_ANON_KEY=tu-clave-publica
# SUPABASE_SERVICE_ROLE_KEY=tu-clave-privada
```
## ⚙️ Rutas de Acceso
Esta aplicación tiene dos formas de acceso configuradas:
### 1. Subdominio Dedicado
Accede mediante: `https://ruleta.tudominio.com`
- URL completa del subdominio
- Next.js recibe las peticiones en el path raíz `/`
- No requiere configuración especial en Next.js
### 2. Path en Dominio Principal
Accede mediante: `https://tudominio.com/ruleta`
- Path dentro del dominio principal
- Traefik elimina el prefijo `/ruleta` antes de enviar a Next.js
- Next.js recibe las peticiones como si estuvieran en `/`
> **Nota**: Puedes usar ambas rutas simultáneamente o deshabilitar una editando el `docker-compose.yml`.
## 🔧 Configuración de Next.js
### Configurar basePath (si usas path)
Si quieres que Next.js sea consciente del path `/ruleta`, edita `next.config.js`:
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: '/ruleta',
assetPrefix: '/ruleta',
// ... otras opciones
}
module.exports = nextConfig
```
> **Nota**: Con la configuración actual (middleware de stripprefix en Traefik), esto NO es necesario. Traefik se encarga de eliminar el prefijo.
### Variables de Entorno en Next.js
Para exponer variables al cliente (navegador):
```javascript
// next.config.js
module.exports = {
env: {
CUSTOM_VAR: process.env.CUSTOM_VAR,
},
// o usa NEXT_PUBLIC_ prefix
}
```
En `stack.env`:
```env
NEXT_PUBLIC_API_URL=https://api.tudominio.com
CUSTOM_VAR=valor-personalizado
```
## 🔒 Proteger con Authentik (Opcional)
Por defecto, la aplicación NO está protegida con SSO. Para protegerla:
### Opción 1: Proteger Todo
Edita el `docker-compose.yml` y descomenta:
```yaml
labels:
# Para subdominio
traefik.http.routers.ruleta-sub.middlewares: "authentik@docker"
# Para path (requiere cadena de middlewares)
traefik.http.routers.ruleta-path.middlewares: "authentik@docker,ruleta-strip@docker"
```
### Opción 2: Proteger Solo Ciertas Rutas
Crea routers adicionales en Traefik:
```yaml
# Router para rutas públicas
traefik.http.routers.ruleta-public.rule: "Host(`ruleta.tudominio.com`) && PathPrefix(`/api`, `/public`)"
traefik.http.routers.ruleta-public.priority: "20"
# Router para rutas protegidas
traefik.http.routers.ruleta-private.rule: "Host(`ruleta.tudominio.com`) && PathPrefix(`/admin`)"
traefik.http.routers.ruleta-private.middlewares: "authentik@docker"
traefik.http.routers.ruleta-private.priority: "30"
```
## 🏗️ Construir la Imagen Docker
### Dockerfile de Ejemplo
```dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copiar archivos necesarios
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
```
### next.config.js para Standalone
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
// ... otras opciones
}
module.exports = nextConfig
```
### Construir y Publicar
```bash
# Construir
docker build -t tu-usuario/ruleta:latest .
# Probar localmente
docker run -p 3000:3000 tu-usuario/ruleta:latest
# Publicar en Docker Hub
docker push tu-usuario/ruleta:latest
# O publicar en GitHub Container Registry
docker tag tu-usuario/ruleta:latest ghcr.io/tu-usuario/ruleta:latest
docker push ghcr.io/tu-usuario/ruleta:latest
```
## 🔧 Configuración Avanzada
### Integración con Supabase
Si tu aplicación usa Supabase:
1. Crea un proyecto en [supabase.com](https://supabase.com)
2. Obtén las credenciales:
- **URL del proyecto**: Settings → API → Project URL
- **Anon key**: Settings → API → anon public
- **Service role key**: Settings → API → service_role (secreto)
3. Añade a `stack.env`:
```env
NEXT_PUBLIC_SUPABASE_URL=https://tu-proyecto.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbG...
SUPABASE_SERVICE_ROLE_KEY=eyJhbG...
```
4. En tu código Next.js:
```javascript
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)
```
### Variables de Entorno Sensibles
Para secrets (API keys, tokens):
1. No las incluyas en `stack.env` si el repositorio es público
2. Configúralas manualmente en Portainer:
- Edita el stack
- Ve a la pestaña **Environment variables**
- Añade variables adicionales
3. O usa Docker secrets:
```yaml
services:
app:
secrets:
- api_key
secrets:
api_key:
external: true
```
### Volúmenes para Datos Persistentes
Si necesitas persistir datos (uploads, cache):
```yaml
services:
app:
volumes:
- ${RULETA_DATA_PATH}:/app/data:Z
- ${RULETA_UPLOADS_PATH}:/app/public/uploads:Z
```
Añade a `stack.env`:
```env
RULETA_DATA_PATH=/opt/ruleta/data
RULETA_UPLOADS_PATH=/opt/ruleta/uploads
```
## 🛠️ Troubleshooting
### La aplicación no inicia
1. Verifica los logs:
```bash
docker logs ruleta-app
```
2. Verifica que la imagen existe:
```bash
docker images | grep ruleta
```
3. Verifica variables de entorno:
```bash
docker inspect ruleta-app | grep -A 20 Env
```
### No puedo acceder por dominio
1. Verifica DNS:
```bash
nslookup ruleta.tudominio.com
```
2. Verifica Traefik:
```bash
docker logs traefik | grep ruleta
```
3. Verifica labels de Traefik:
```bash
docker inspect ruleta-app | grep -A 30 Labels
```
### Error 502 Bad Gateway
1. Verifica que el puerto interno es correcto:
- Next.js por defecto usa puerto 3000
- Verifica `RULETA_APP_PORT=3000`
2. Verifica que la aplicación está escuchando:
```bash
docker exec ruleta-app netstat -tulpn
```
3. Verifica conectividad desde Traefik:
```bash
docker exec traefik ping ruleta-app
```
### Las rutas no funcionan con basePath
Si configuraste `basePath` en Next.js:
1. **Opción A**: Elimina el middleware `stripprefix` de Traefik
2. **Opción B**: Elimina `basePath` de Next.js (Traefik se encarga)
### Recursos estáticos (CSS/JS) no cargan
Verifica:
1. El `assetPrefix` en `next.config.js` (debe coincidir con basePath)
2. Los logs del navegador (F12 → Console)
3. Las rutas en el inspector de red (F12 → Network)
### Variables de entorno no disponibles
Recuerda:
- Solo variables con prefijo `NEXT_PUBLIC_` están disponibles en el navegador
- Variables sin prefijo solo están disponibles en el servidor (API routes, getServerSideProps)
## 📚 Recursos Adicionales
- [Documentación de Next.js](https://nextjs.org/docs)
- [Deploying Next.js](https://nextjs.org/docs/deployment)
- [Next.js con Docker](https://github.com/vercel/next.js/tree/canary/examples/with-docker)
- [Traefik con Next.js](https://doc.traefik.io/traefik/routing/routers/)
## 🔄 Actualizaciones
### Actualizar la Aplicación
1. Construye una nueva versión de la imagen:
```bash
docker build -t tu-usuario/ruleta:v2.0 .
docker push tu-usuario/ruleta:v2.0
```
2. Actualiza en `stack.env`:
```env
RULETA_IMAGE=tu-usuario/ruleta:v2.0
```
3. Actualiza el stack en Portainer
### Rolling Updates
Para actualizaciones sin downtime, usa múltiples réplicas (requiere Docker Swarm o Kubernetes).
### Rollback
Si algo sale mal:
1. Vuelve a la versión anterior en `stack.env`
2. Actualiza el stack en Portainer
## 📊 Monitoreo
### Logs de la Aplicación
```bash
# Logs en tiempo real
docker logs -f ruleta-app
# Últimas 100 líneas
docker logs --tail 100 ruleta-app
# Logs con timestamps
docker logs -t ruleta-app
```
### Logs de Next.js
Next.js registra en stdout/stderr, accesibles con `docker logs`.
Para logs estructurados, considera usar:
- [Pino](https://github.com/pinojs/pino)
- [Winston](https://github.com/winstonjs/winston)
### Métricas
Para monitorear la aplicación:
1. Implementa un endpoint `/api/health`
2. Usa herramientas como Prometheus + Grafana
3. O servicios de APM como New Relic, Datadog
## 🎯 Casos de Uso
Este stack es ideal para:
- Aplicaciones Next.js personalizadas
- Landing pages
- Dashboards administrativos
- Aplicaciones full-stack con API routes
- JAMstack con SSR/SSG
## 💡 Tips
- Usa `output: 'standalone'` en Next.js para imágenes Docker más pequeñas
- Implementa caching con Redis para mejor rendimiento
- Usa ISR (Incremental Static Regeneration) para contenido dinámico
- Implementa rate limiting en API routes
- Usa CDN para assets estáticos (imágenes, CSS, JS)

57
ruleta/docker-compose.yml Normal file
View File

@@ -0,0 +1,57 @@
services:
# Aplicación Next.js
app:
image: ${RULETA_IMAGE}
container_name: ruleta-app
restart: unless-stopped
environment:
NODE_ENV: ${RULETA_NODE_ENV}
NEXT_TELEMETRY_DISABLED: ${RULETA_NEXT_TELEMETRY_DISABLED}
# Si usas Supabase, descomenta y configura:
# NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL}
# NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY}
# SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
networks:
- proxy
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
# ---------------------------
# 1) Router EXISTENTE (subdominio)
# https://ruleta.example.com
# ---------------------------
traefik.http.routers.ruleta-sub.rule: "Host(`${RULETA_SUBDOMAIN}`)"
traefik.http.routers.ruleta-sub.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.ruleta-sub.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.ruleta-sub.service: "ruleta"
# ---------------------------
# 2) Router NUEVO (.net + path)
# https://sherlockhomeless.net/ruleta
# ---------------------------
traefik.http.routers.ruleta-path.rule: "Host(`${RULETA_MAIN_DOMAIN}`) && PathPrefix(`/ruleta`)"
traefik.http.routers.ruleta-path.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.ruleta-path.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.ruleta-path.service: "ruleta"
traefik.http.routers.ruleta-path.middlewares: "ruleta-strip@docker"
# Quita /ruleta antes de llegar a Next.js
traefik.http.middlewares.ruleta-strip.stripprefix.prefixes: "/ruleta"
traefik.http.middlewares.ruleta-strip.stripprefix.forceSlash: "true"
# Servicio interno (Next.js escucha en 3000)
traefik.http.services.ruleta.loadbalancer.server.port: "${RULETA_APP_PORT}"
# Proteger con Authentik (si quieres habilitarlo)
# OJO: si lo activas, ponlo en ambos routers o usa una cadena.
# traefik.http.routers.ruleta-sub.middlewares: "authentik@docker"
# traefik.http.routers.ruleta-path.middlewares: "authentik@docker,ruleta-strip@docker"
networks:
proxy:
external: true

18
ruleta/stack.env Normal file
View File

@@ -0,0 +1,18 @@
##### Ruleta - App #####
RULETA_IMAGE=
RULETA_NODE_ENV=
RULETA_NEXT_TELEMETRY_DISABLED=
RULETA_APP_PORT=
# Supabase (opcional)
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
##### Traefik / dominios #####
TRAEFIK_DOCKER_NETWORK=
RULETA_SUBDOMAIN=
RULETA_MAIN_DOMAIN=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=

382
trilium/README.md Normal file
View File

@@ -0,0 +1,382 @@
# Trilium Notes - Aplicación de Notas Jerárquicas
Trilium Notes es una aplicación de toma de notas jerárquicas con editor WYSIWYG, soporte para scripts, y cifrado de notas.
## 📋 Descripción
Este stack despliega Trilium con:
- Almacenamiento persistente de notas
- Acceso mediante HTTPS con Traefik
- Sincronización entre dispositivos
- Sin protección SSO (Trilium tiene su propio sistema de autenticación)
- Headers de seguridad configurados
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Asegúrate de que la red `proxy` existe
2. **Registro DNS**: Configura los registros A para tus dominios Trilium
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `trilium`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `trilium/docker-compose.yml`
5. Carga el archivo de variables de entorno: `trilium/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno
Edita el archivo `stack.env`:
```env
# Imagen
TRILIUM_IMAGE=zadam/trilium:latest
# Hostname (para identificación interna)
TRILIUM_HOSTNAME=trilium-server
# Puerto HTTP interno
TRILIUM_HTTP_PORT=8080
# Dominios (puedes tener múltiples dominios apuntando a la misma instancia)
TRILIUM_DOMAIN_1=notes.tudominio.com
TRILIUM_DOMAIN_2=trilium.tudominio.com
# Ruta de datos
TRILIUM_DATA_PATH=/opt/trilium/data
# Zona horaria
TZ=Europe/Madrid
# Traefik
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
```
## ⚙️ Configuración Post-Instalación
### 1. Primer Acceso
1. Accede a `https://notes.tudominio.com`
2. En el primer acceso, Trilium te pedirá crear una contraseña
3. **Guarda bien esta contraseña**: Es la contraseña maestra que protege todas tus notas
### 2. Configuración Inicial
Trilium te guiará por un tutorial interactivo. Explora:
- **Crear notas**: Haz clic en el botón + o usa `Ctrl+P`
- **Jerarquía**: Organiza notas en árbol jerárquico
- **Atributos**: Añade etiquetas (#tag) y relaciones
- **Scripts**: Automatiza tareas con JavaScript
### 3. Cifrado de Notas
Para cifrar notas sensibles:
1. Haz clic derecho en una nota → **Note info**
2. Añade el atributo `#encrypted`
3. Trilium te pedirá una contraseña de cifrado
4. La nota se cifrará localmente
### 4. Sincronización entre Dispositivos
Trilium soporta sincronización servidor-cliente:
#### Configurar Servidor (ya está hecho)
Tu instancia de Trilium ya funciona como servidor.
#### Configurar Cliente Desktop
1. Descarga Trilium Desktop desde [GitHub](https://github.com/zadam/trilium/releases)
2. Instálalo en tu PC/Mac/Linux
3. En el primer inicio, selecciona **Sync from server**
4. Configura:
- **Server URL**: `https://notes.tudominio.com`
- **Username**: Crea un usuario de sincronización en el servidor
- **Password**: Password del usuario
#### Crear Usuario de Sincronización
1. En el servidor web, ve a **Options****Sync**
2. Haz clic en **Create sync user**
3. Usuario: `mi-desktop`
4. Password: (genera uno seguro)
5. Copia las credenciales para usarlas en el cliente
## 🔧 Características Principales
### Notas Jerárquicas
- Organiza notas en árbol (padres e hijos)
- Múltiples padres por nota (clones)
- Drag & drop para reorganizar
### Tipos de Notas
- **Text**: Notas de texto con editor WYSIWYG
- **Code**: Notas de código con syntax highlighting
- **Render**: Notas que ejecutan HTML/JavaScript
- **Book**: Agrupaciones de notas
- **Relation map**: Mapas de relaciones entre notas
- **Canvas**: Notas de dibujo libre
### Atributos y Relaciones
```
#etiqueta - Etiqueta simple
#etiqueta=valor - Etiqueta con valor
~relacion=@notaId - Relación a otra nota
#cssClass=mi-clase - Clase CSS personalizada
#hideChildrenOverview - Oculta hijos en overview
```
### Scripts
Trilium permite automatización con JavaScript:
1. Crea una nota de tipo **Code** (JavaScript)
2. Añade el atributo `#run=frontendStartup` o `#run=backendStartup`
3. El script se ejecutará automáticamente
Ejemplo - Script de búsqueda personalizada:
```javascript
api.addButtonToToolbar({
title: 'Buscar TODO',
icon: 'check',
action: () => {
const notes = api.searchForNotes('#todo !#done');
api.showMessage(`Encontradas ${notes.length} tareas pendientes`);
}
});
```
### Plantillas
Crea plantillas para notas recurrentes:
1. Crea una nota con la estructura deseada
2. Añade `#template`
3. Usa la plantilla: Clic derecho en padre → **Create note from template**
### Web Clipper
Captura contenido web directamente a Trilium:
1. Ve a **Options****Web clipper**
2. Sigue las instrucciones para instalar la extensión del navegador
3. Captura páginas web con un clic
## 🔧 Configuración Avanzada
### Backup Automático
Trilium hace backups automáticos diarios en `/opt/trilium/data/backup/`.
Para configurar backups externos:
```bash
# Script de backup
#!/bin/bash
BACKUP_DIR=/backups/trilium
DATE=$(date +%Y%m%d_%H%M%S)
# Backup de toda la data
tar -czf $BACKUP_DIR/trilium-$DATE.tar.gz /opt/trilium/data/
# Mantener solo últimos 30 días
find $BACKUP_DIR -name "trilium-*.tar.gz" -mtime +30 -delete
```
### API
Trilium tiene una API ETAPI para integración:
1. Ve a **Options****ETAPI**
2. Crea un token de API
3. Úsalo en tus scripts:
```bash
# Obtener nota
curl -H "Authorization: YOUR_ETAPI_TOKEN" \
https://notes.tudominio.com/etapi/notes/noteId
# Crear nota
curl -X POST https://notes.tudominio.com/etapi/notes \
-H "Authorization: YOUR_ETAPI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"noteId":"new-note","title":"Mi Nota","content":"Contenido"}'
```
### Temas y Estilos
Personaliza la apariencia:
1. Crea una nota de tipo **Code** (CSS)
2. Añade `#appTheme`
3. Escribe tu CSS personalizado:
```css
/* Tema oscuro personalizado */
body {
--main-background-color: #1e1e1e;
--main-text-color: #d4d4d4;
}
```
### Shortcuts Personalizados
1. Ve a **Options****Keyboard shortcuts**
2. Personaliza o añade nuevos shortcuts
## 🛠️ Troubleshooting
### No puedo acceder a Trilium
1. Verifica que está corriendo:
```bash
docker ps | grep trilium
```
2. Verifica los logs:
```bash
docker logs trilium
```
3. Verifica DNS:
```bash
nslookup notes.tudominio.com
```
### Olvidé la contraseña maestra
Si perdiste la contraseña maestra, NO HAY forma de recuperarla. Las notas están cifradas localmente.
**Prevención**:
- Guarda la contraseña en un gestor de contraseñas
- Haz backups regulares de `/opt/trilium/data/`
- Considera no usar cifrado para todas las notas
### Sincronización no funciona
1. Verifica las credenciales del usuario de sync
2. Revisa los logs del servidor:
```bash
docker logs trilium | grep sync
```
3. En el cliente, ve a **Options** → **Sync** → **Check for updates**
4. Fuerza sincronización: **Options** → **Sync** → **Force full sync**
### Notas no se guardan
1. Verifica espacio en disco:
```bash
df -h /opt/trilium/
```
2. Verifica permisos:
```bash
ls -lh /opt/trilium/data/
```
3. Revisa los logs para errores
### Performance lento
1. Verifica el tamaño de la base de datos:
```bash
du -sh /opt/trilium/data/document.db
```
2. Considera optimizar la base de datos:
- Ve a **Options** → **Advanced** → **Anonymize database**
- Esto elimina historial antiguo
3. Aumenta recursos del contenedor si es necesario
## 📚 Recursos Adicionales
- [Documentación oficial de Trilium](https://github.com/zadam/trilium/wiki)
- [Galería de plantillas](https://github.com/zadam/trilium/wiki/Gallery)
- [Scripts de ejemplo](https://github.com/zadam/trilium/wiki/Scripts)
- [Forum de la comunidad](https://github.com/zadam/trilium/discussions)
## 🔒 Seguridad
- **Contraseña maestra**: Protege todas tus notas
- **Cifrado opcional**: Usa `#encrypted` para notas sensibles
- **HTTPS**: Todo el tráfico está cifrado con SSL
- **Backups**: Haz backups regulares de tus notas
- **Sin SSO**: Trilium gestiona su propia autenticación (más seguro para notas personales)
## 💾 Backups
### Backup Manual
```bash
# Backup completo
sudo tar -czf trilium-backup-$(date +%Y%m%d).tar.gz /opt/trilium/data/
# Solo base de datos
sudo cp /opt/trilium/data/document.db trilium-db-backup-$(date +%Y%m%d).db
```
### Restaurar
```bash
# Detener Trilium
docker stop trilium
# Restaurar backup
sudo tar -xzf trilium-backup-YYYYMMDD.tar.gz -C /
# Reiniciar
docker start trilium
```
### Backup Automático (dentro de Trilium)
Trilium hace backups automáticos:
- **Ubicación**: `/opt/trilium/data/backup/`
- **Frecuencia**: Diaria
- **Retención**: Configurable en **Options** → **Other**
## 🔄 Actualizaciones
1. Haz **backup completo** antes de actualizar
2. Actualiza en `stack.env`:
```env
TRILIUM_IMAGE=zadam/trilium:0.63.7
```
3. Actualiza el stack en Portainer
4. Verifica los logs: `docker logs trilium`
5. Accede y verifica que todo funciona
> **Nota**: Revisa el [changelog](https://github.com/zadam/trilium/blob/master/CHANGELOG.md) antes de actualizar.
## 📊 Uso
### Casos de Uso
- **Notas personales**: Diario, ideas, recordatorios
- **Base de conocimiento**: Wiki personal, documentación
- **Gestión de proyectos**: Tareas, planificación
- **Investigación**: Organización de información
- **Snippets de código**: Biblioteca de código reutilizable
- **Journaling**: Diario personal cifrado
### Tips
- Usa `Ctrl+P` para búsqueda rápida
- Usa `Ctrl+S` para guardar (automático)
- Usa `Alt+Up/Down` para navegar por el árbol
- Usa `Ctrl+K` para crear links internos
- Usa `#` para etiquetas en el título
- Usa backlinks para ver referencias a una nota

View File

@@ -0,0 +1,45 @@
services:
trilium:
image: ${TRILIUM_IMAGE}
container_name: trilium
restart: unless-stopped
hostname: ${TRILIUM_HOSTNAME}
environment:
TZ: ${TZ}
volumes:
- ${TRILIUM_DATA_PATH}:/home/node/trilium-data:Z
expose:
- "${TRILIUM_HTTP_PORT}"
networks:
- proxy
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
# Router HTTPS (dos dominios válidos, usando OR)
traefik.http.routers.trilium.rule: "Host(`${TRILIUM_DOMAIN_1}`) || Host(`${TRILIUM_DOMAIN_2}`)"
traefik.http.routers.trilium.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.trilium.tls: "true"
traefik.http.routers.trilium.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
# Servicio interno
traefik.http.services.trilium.loadbalancer.server.port: "${TRILIUM_HTTP_PORT}"
# Middleware solo de headers (sin Authentik)
traefik.http.routers.trilium.middlewares: "trilium-sec@docker"
traefik.http.middlewares.trilium-sec.headers.stsSeconds: "31536000"
traefik.http.middlewares.trilium-sec.headers.stsIncludeSubdomains: "true"
traefik.http.middlewares.trilium-sec.headers.stsPreload: "true"
traefik.http.middlewares.trilium-sec.headers.contentTypeNosniff: "true"
traefik.http.middlewares.trilium-sec.headers.frameDeny: "true"
networks:
proxy:
external: true

14
trilium/stack.env Normal file
View File

@@ -0,0 +1,14 @@
##### Trilium Next #####
TRILIUM_IMAGE=
TRILIUM_HOSTNAME=
TZ=
TRILIUM_DATA_PATH=
TRILIUM_HTTP_PORT=
##### Traefik / dominios #####
TRAEFIK_DOCKER_NETWORK=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=
TRILIUM_DOMAIN_1=
TRILIUM_DOMAIN_2=

435
wireguard/README.md Normal file
View File

@@ -0,0 +1,435 @@
# WireGuard - VPN Rápida y Segura
WireGuard es una VPN moderna, rápida y segura. Este stack usa `wg-easy` para gestión simplificada de clientes.
## 📋 Descripción
Este stack despliega WireGuard con:
- Interfaz web para gestión de clientes (wg-easy)
- Generación automática de configuraciones de clientes
- Códigos QR para configuración móvil rápida
- Panel web protegido con Authentik
- Puerto UDP para el túnel VPN
## 🚀 Despliegue
### Prerequisitos
1. **Red Docker**: Asegúrate de que la red `proxy` existe
2. **Registro DNS**: Configura el registro A para tu dominio WireGuard
3. **Puerto UDP**: El puerto UDP debe estar abierto en el firewall (por defecto 51820)
4. **Kernel modules**: El servidor debe soportar WireGuard
### Verificar Soporte WireGuard
```bash
# Verificar módulo WireGuard
lsmod | grep wireguard
# O intentar cargarlo
sudo modprobe wireguard
# Si falla, instala wireguard-tools
sudo dnf install wireguard-tools # Fedora/RHEL
sudo apt install wireguard # Debian/Ubuntu
```
### Desde Portainer
1. Ve a **Stacks****Add stack**
2. Nombre: `wireguard`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `wireguard/docker-compose.yml`
5. Carga el archivo de variables de entorno: `wireguard/stack.env`
6. Haz clic en **Deploy the stack**
### Variables de Entorno
Edita el archivo `stack.env`:
```env
# Imagen
WG_EASY_IMAGE=ghcr.io/wg-easy/wg-easy:latest
# Dominio o IP pública del servidor
WG_HOST=vpn.tudominio.com
# Puerto UDP de WireGuard (debe estar abierto en el firewall)
WG_PORT=51820
WG_UDP_PORT=51820
# Puerto HTTP de la UI (interno)
WG_UI_PORT=51821
# Credenciales iniciales para la UI
INIT_ENABLED=true
INIT_USERNAME=admin
INIT_PASSWORD=tu-password-seguro
# Desactivar IPv6 (si el servidor no lo soporta)
DISABLE_IPV6=true
# Rutas
WG_DATA_PATH=/opt/wireguard/data
WG_MODULES_PATH=/lib/modules
# Dominio de la UI
WG_DOMAIN=vpn-admin.tudominio.com
# Traefik
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
```
> **⚠️ Importante**:
> - Cambia `INIT_PASSWORD` por una contraseña segura
> - Usa tu dominio o IP pública en `WG_HOST`
### Abrir Puerto UDP en el Firewall
```bash
# Firewalld (Fedora/RHEL)
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload
# UFW (Ubuntu/Debian)
sudo ufw allow 51820/udp
# iptables
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
sudo iptables-save > /etc/iptables/rules.v4
```
## ⚙️ Configuración Post-Instalación
### 1. Acceso al Panel Web
1. Accede a `https://vpn-admin.tudominio.com`
2. Si configuraste Authentik, serás redirigido al SSO
3. Inicia sesión con las credenciales configuradas en `INIT_USERNAME` y `INIT_PASSWORD`
### 2. Crear Cliente VPN
1. En el panel web, haz clic en **+ Add Client**
2. Nombre del cliente: `mi-laptop`, `mi-movil`, etc.
3. El cliente se crea automáticamente con:
- Par de claves pública/privada
- IP asignada dentro del túnel VPN
- Configuración completa
### 3. Configurar Cliente
#### Móvil (Android/iOS)
1. Instala la app **WireGuard** desde Play Store o App Store
2. En el panel web, haz clic en el icono **QR** del cliente
3. Escanea el código QR con la app
4. Activa el túnel VPN
#### Windows/Mac/Linux Desktop
##### Opción A: Escanear QR
1. Descarga WireGuard desde [wireguard.com](https://www.wireguard.com/install/)
2. Instala la aplicación
3. Haz clic en **Import tunnel(s) from QR code**
4. Escanea el QR del panel web con tu webcam
##### Opción B: Descargar archivo de configuración
1. En el panel web, haz clic en el icono **Download** del cliente
2. Guarda el archivo `.conf`
3. En WireGuard app, haz clic en **Import tunnel(s) from file**
4. Selecciona el archivo `.conf`
##### Opción C: Configuración manual
Copia la configuración del panel web:
```ini
[Interface]
PrivateKey = tu_clave_privada
Address = 10.8.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = clave_publica_servidor
PresharedKey = clave_compartida
Endpoint = vpn.tudominio.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
```
Guarda como `cliente.conf` y carga en WireGuard.
### 4. Verificar Conexión
Una vez activado el túnel:
```bash
# Verificar IP pública (debe ser la de tu servidor VPN)
curl ifconfig.me
# Ping al servidor VPN (IP interna)
ping 10.8.0.1
# Verificar DNS
nslookup google.com
```
## 🔧 Configuración Avanzada
### Rutear Solo Tráfico Específico (Split Tunneling)
Por defecto, WireGuard enruta TODO el tráfico (`AllowedIPs = 0.0.0.0/0`).
Para rutear solo ciertos rangos:
1. Descarga el archivo `.conf` del cliente
2. Edita `AllowedIPs`:
```ini
AllowedIPs = 10.8.0.0/24, 192.168.1.0/24
```
3. Importa el archivo modificado en el cliente
Ejemplos:
- Solo red VPN: `10.8.0.0/24`
- Red VPN + red local del servidor: `10.8.0.0/24, 192.168.1.0/24`
- Todo excepto red local del cliente: `0.0.0.0/1, 128.0.0.0/1`
### Cambiar Rango de IPs de la VPN
Por defecto usa `10.8.0.0/24`. Para cambiar:
1. Detén el stack
2. Edita `/opt/wireguard/data/wireguard.conf`
3. Cambia:
```ini
[Interface]
Address = 10.9.0.1/24
```
4. Actualiza también en cada cliente
5. Reinicia el stack
### Usar DNS Personalizado
Para que los clientes usen tu AdGuard Home:
1. En el panel web, ve a **Settings**
2. Cambia **DNS** a la IP de tu servidor (ej: `192.168.1.10`)
3. O edita manualmente en cada archivo `.conf`:
```ini
DNS = IP-de-tu-AdGuard
```
### Limitar Ancho de Banda
No soportado directamente por wg-easy, pero puedes usar `tc` en el servidor:
```bash
# Limitar a 10 Mbps
sudo tc qdisc add dev wg0 root tbf rate 10mbit burst 32kbit latency 400ms
```
### Configurar Post-Up/Post-Down Scripts
Para ejecutar scripts al iniciar/detener el túnel:
Edita `/opt/wireguard/data/wireguard.conf`:
```ini
[Interface]
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
```
## 🛠️ Troubleshooting
### No puedo conectar al VPN
1. Verifica que el puerto UDP está abierto:
```bash
sudo netstat -tulpn | grep 51820
nc -zuv vpn.tudominio.com 51820
```
2. Verifica que WireGuard está corriendo:
```bash
docker logs wg-easy
```
3. Verifica que el módulo WireGuard está cargado:
```bash
lsmod | grep wireguard
```
4. Verifica la configuración del cliente (especialmente `Endpoint`)
### Conecta pero no hay Internet
1. Verifica que el forwarding está habilitado en el servidor:
```bash
cat /proc/sys/net/ipv4/ip_forward # Debe ser 1
```
2. Verifica las reglas de iptables:
```bash
sudo iptables -L -v -n
```
3. Verifica la configuración de NAT en wg-easy
### Panel web no accesible
1. Verifica que está corriendo:
```bash
docker ps | grep wg-easy
```
2. Verifica los logs:
```bash
docker logs wg-easy
```
3. Verifica Traefik:
```bash
docker logs traefik | grep wg
```
### Error "Cannot find device wg0"
El módulo WireGuard no está cargado:
```bash
# Intentar cargar
sudo modprobe wireguard
# Si falla, instalar
sudo dnf install wireguard-tools # Fedora/RHEL
sudo apt install wireguard # Debian/Ubuntu
```
### Clientes se desconectan frecuentemente
1. Aumenta `PersistentKeepalive` en la configuración del cliente:
```ini
PersistentKeepalive = 25
```
2. Verifica el MTU (puede ser muy alto para tu red):
```ini
MTU = 1280
```
### IPv6 causa problemas
Desactiva IPv6 en `stack.env`:
```env
DISABLE_IPV6=true
```
Y reinicia el stack.
## 📚 Recursos Adicionales
- [Documentación oficial de WireGuard](https://www.wireguard.com/)
- [wg-easy en GitHub](https://github.com/wg-easy/wg-easy)
- [Guía de WireGuard](https://www.wireguard.com/quickstart/)
## 🔒 Seguridad
- **Cifrado**: WireGuard usa criptografía moderna (ChaCha20, Curve25519)
- **Panel web**: Protegido con Authentik (SSO)
- **Claves**: Cada cliente tiene su par de claves único
- **PresharedKey**: Capa adicional de seguridad cuántica
- **Firewall**: Solo el puerto UDP de WireGuard debe estar abierto
### Best Practices
1. **Cambia la contraseña** del panel web
2. **Usa Authentik** para proteger el panel
3. **Limita IPs** si solo necesitas acceso desde ciertos rangos
4. **Revoca clientes** cuando ya no los uses
5. **Haz backups** de `/opt/wireguard/data/`
## 💾 Backups
```bash
# Backup de configuraciones
sudo tar -czf wireguard-backup-$(date +%Y%m%d).tar.gz /opt/wireguard/data/
# Restaurar
sudo tar -xzf wireguard-backup-YYYYMMDD.tar.gz -C /
docker restart wg-easy
```
> **Importante**: Guarda los backups de forma segura. Contienen las claves privadas.
## 🔄 Actualizaciones
1. Haz backup de `/opt/wireguard/data/`
2. Actualiza en `stack.env`:
```env
WG_EASY_IMAGE=ghcr.io/wg-easy/wg-easy:latest
```
3. Actualiza el stack en Portainer
4. Verifica que los clientes siguen conectando
## 📊 Monitoreo
### Ver Clientes Conectados
En el panel web, verás:
- Clientes activos (verde)
- Última conexión
- Transferencia de datos
- IP asignada
### Ver Stats del Túnel
```bash
# Desde el servidor
docker exec wg-easy wg show
# Ver configuración
docker exec wg-easy cat /etc/wireguard/wg0.conf
# Ver logs
docker logs -f wg-easy
```
## 🎯 Casos de Uso
### Acceso Remoto Seguro
Accede a tu red doméstica desde cualquier lugar:
- Administra servidores
- Accede a servicios internos
- Usa impresoras de red
### Protección en Redes Públicas
Usa WireGuard en WiFi públicas para:
- Cifrar todo el tráfico
- Evitar ataques Man-in-the-Middle
- Proteger tus datos
### Bypass de Restricciones Geográficas
Usa la IP de tu servidor para:
- Acceder a contenido local
- Evitar censura
- Mantener tu IP original
### Combinar con AdGuard
Configura los clientes VPN para usar tu AdGuard Home:
- Bloqueo de anuncios en móvil
- Protección contra rastreadores
- DNS filtrado incluso fuera de casa

View File

@@ -0,0 +1,57 @@
services:
wg-easy:
image: ${WG_EASY_IMAGE}
container_name: wg-easy
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
net.ipv4.ip_forward: "1"
net.ipv4.conf.all.src_valid_mark: "1"
environment:
WG_HOST: ${WG_HOST}
WG_PORT: ${WG_PORT}
PORT: ${WG_UI_PORT}
# Arranque desatendido (solo si el volumen está vacío)
INIT_ENABLED: ${INIT_ENABLED}
INIT_USERNAME: ${INIT_USERNAME}
INIT_PASSWORD: ${INIT_PASSWORD}
# Evita reglas ip6tables (tabla nat inexistente en el host)
DISABLE_IPV6: ${DISABLE_IPV6}
volumes:
- ${WG_DATA_PATH}:/etc/wireguard:Z
- ${WG_MODULES_PATH}:/lib/modules:ro,Z
# Puerto UDP de WireGuard expuesto al mundo
ports:
- "${WG_UDP_PORT}:${WG_PORT}/udp"
networks:
- proxy
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
# Router HTTPS para la UI de wg-easy
traefik.http.routers.wg.rule: "Host(`${WG_DOMAIN}`)"
traefik.http.routers.wg.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.wg.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
# Servicio apuntando al puerto HTTP interno de la UI
traefik.http.services.wg.loadbalancer.server.port: "${WG_UI_PORT}"
# Proteger la UI con Authentik (middleware definido en authentik-server)
traefik.http.routers.wg.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE}"
networks:
proxy:
external: true

22
wireguard/stack.env Normal file
View File

@@ -0,0 +1,22 @@
##### wg-easy #####
WG_EASY_IMAGE=
WG_HOST=
WG_PORT=
WG_UI_PORT=
INIT_ENABLED=
INIT_USERNAME=
INIT_PASSWORD=
DISABLE_IPV6=
WG_DATA_PATH=
WG_MODULES_PATH=
WG_UDP_PORT=
##### Traefik / dominios #####
TRAEFIK_DOCKER_NETWORK=
WG_DOMAIN=
TRAEFIK_ENTRYPOINT_SECURE=
TRAEFIK_CERTRESOLVER=
TRAEFIK_AUTH_MIDDLEWARE=