Compare commits
13 Commits
backup-ori
...
list
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1698de3738 | ||
|
|
f22842052a | ||
|
|
f29208cfa2 | ||
|
|
f8cd4c2df1 | ||
|
|
db807dcf6f | ||
|
|
02b9685804 | ||
| 8246bff8a1 | |||
|
|
43c24b4b86 | ||
|
|
43d10ea7cf | ||
|
|
becce96ede | ||
|
|
a97c88454f | ||
|
|
d05d783244 | ||
|
|
35bb14028f |
2
.env
2
.env
@@ -19,7 +19,7 @@
|
|||||||
# TRAEFIK_CERTRESOLVER=letsencrypt
|
# TRAEFIK_CERTRESOLVER=letsencrypt
|
||||||
|
|
||||||
# Middleware de autenticación (SSO, etc.)
|
# Middleware de autenticación (SSO, etc.)
|
||||||
# TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
|
# TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker
|
||||||
|
|
||||||
# Dominios de ejemplo (cámbialos por los tuyos)
|
# Dominios de ejemplo (cámbialos por los tuyos)
|
||||||
# PORTAINER_DOMAIN=portainer.example.com
|
# PORTAINER_DOMAIN=portainer.example.com
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ Variables principales a configurar:
|
|||||||
- `PORTAINER_DOMAIN`: Tu dominio para Portainer UI (ej: `portainer.tudominio.com`)
|
- `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_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
|
- `PORTAINER_API_IP_WHITELIST`: IPs permitidas para acceso directo a la API
|
||||||
- `TRAEFIK_AUTH_MIDDLEWARE`: Middleware de autenticación (ej: `authentik@docker`)
|
- `TRAEFIK_AUTH_MIDDLEWARE`: Middleware de autenticación (ej: `ths-authentik@docker`)
|
||||||
|
|
||||||
### Paso 10: Actualizar Stack de Portainer (Opcional)
|
### Paso 10: Actualizar Stack de Portainer (Opcional)
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ PORTAINER_API_DOMAIN=portainer-api.example.com
|
|||||||
|
|
||||||
# Seguridad
|
# Seguridad
|
||||||
PORTAINER_API_IP_WHITELIST=10.8.0.0/24,172.18.0.1/32
|
PORTAINER_API_IP_WHITELIST=10.8.0.0/24,172.18.0.1/32
|
||||||
TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
|
TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuraciones por Stack
|
### Configuraciones por Stack
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ labels:
|
|||||||
traefik.http.routers.dashboard.entrypoints: "websecure"
|
traefik.http.routers.dashboard.entrypoints: "websecure"
|
||||||
traefik.http.routers.dashboard.tls.certresolver: "letsencrypt"
|
traefik.http.routers.dashboard.tls.certresolver: "letsencrypt"
|
||||||
traefik.http.routers.dashboard.service: "api@internal"
|
traefik.http.routers.dashboard.service: "api@internal"
|
||||||
traefik.http.routers.dashboard.middlewares: "authentik@docker"
|
traefik.http.routers.dashboard.middlewares: "ths-authentik@docker"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Opción 2: Acceso local (inseguro - solo desarrollo)**
|
**Opción 2: Acceso local (inseguro - solo desarrollo)**
|
||||||
@@ -165,7 +165,7 @@ services:
|
|||||||
traefik.http.services.mi-servicio.loadbalancer.server.port: "80"
|
traefik.http.services.mi-servicio.loadbalancer.server.port: "80"
|
||||||
|
|
||||||
# Middleware (opcional)
|
# Middleware (opcional)
|
||||||
traefik.http.routers.mi-servicio.middlewares: "authentik@docker"
|
traefik.http.routers.mi-servicio.middlewares: "ths-authentik@docker"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
@@ -180,7 +180,7 @@ labels:
|
|||||||
traefik.http.routers.app-ui.rule: "Host(`app.tudominio.com`)"
|
traefik.http.routers.app-ui.rule: "Host(`app.tudominio.com`)"
|
||||||
traefik.http.routers.app-ui.entrypoints: "websecure"
|
traefik.http.routers.app-ui.entrypoints: "websecure"
|
||||||
traefik.http.routers.app-ui.tls.certresolver: "letsencrypt"
|
traefik.http.routers.app-ui.tls.certresolver: "letsencrypt"
|
||||||
traefik.http.routers.app-ui.middlewares: "authentik@docker"
|
traefik.http.routers.app-ui.middlewares: "ths-authentik@docker"
|
||||||
traefik.http.routers.app-ui.priority: "10"
|
traefik.http.routers.app-ui.priority: "10"
|
||||||
|
|
||||||
# API pública sin protección
|
# API pública sin protección
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ ADGUARD_CERT_KEY_PATH=/opt/adguard/certs/adguard.key
|
|||||||
TRAEFIK_DOCKER_NETWORK=proxy
|
TRAEFIK_DOCKER_NETWORK=proxy
|
||||||
TRAEFIK_ENTRYPOINT_SECURE=websecure
|
TRAEFIK_ENTRYPOINT_SECURE=websecure
|
||||||
TRAEFIK_CERTRESOLVER=letsencrypt
|
TRAEFIK_CERTRESOLVER=letsencrypt
|
||||||
TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
|
TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker
|
||||||
```
|
```
|
||||||
|
|
||||||
## ⚙️ Configuración Post-Instalación
|
## ⚙️ Configuración Post-Instalación
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ Una vez configurado el middleware, añade la label a los servicios que quieras p
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
labels:
|
labels:
|
||||||
traefik.http.routers.portainer.middlewares: "authentik@docker"
|
traefik.http.routers.portainer.middlewares: "ths-authentik@docker"
|
||||||
```
|
```
|
||||||
|
|
||||||
O si definiste el middleware en archivo:
|
O si definiste el middleware en archivo:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
authentik-postgres:
|
ths-authentik-postgres:
|
||||||
image: ${AUTHENTIK_POSTGRES_IMAGE}
|
image: ${AUTHENTIK_POSTGRES_IMAGE}
|
||||||
container_name: authentik-postgres
|
container_name: ths-authentik-postgres
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
||||||
@@ -10,95 +10,103 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${AUTHENTIK_POSTGRES_PATH}:/var/lib/postgresql/data:Z
|
- ${AUTHENTIK_POSTGRES_PATH}:/var/lib/postgresql/data:Z
|
||||||
networks:
|
networks:
|
||||||
- authentik_internal
|
- ths_authentik_internal
|
||||||
|
|
||||||
authentik-redis:
|
ths-authentik-redis:
|
||||||
image: ${AUTHENTIK_REDIS_IMAGE}
|
image: ${AUTHENTIK_REDIS_IMAGE}
|
||||||
container_name: authentik-redis
|
container_name: ths-authentik-redis
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
|
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"]
|
||||||
volumes:
|
volumes:
|
||||||
- ${AUTHENTIK_REDIS_PATH}:/data:Z
|
- ${AUTHENTIK_REDIS_PATH}:/data:Z
|
||||||
networks:
|
networks:
|
||||||
- authentik_internal
|
- ths_authentik_internal
|
||||||
|
|
||||||
authentik-server:
|
ths-authentik-server:
|
||||||
image: ${AUTHENTIK_IMAGE}
|
image: ${AUTHENTIK_IMAGE}
|
||||||
container_name: authentik-server
|
container_name: ths-authentik-server
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: ["server"]
|
command: ["server"]
|
||||||
environment:
|
environment:
|
||||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
||||||
|
|
||||||
AUTHENTIK_POSTGRESQL__HOST: ${AUTHENTIK_DB_HOST}
|
# OJO: forzamos hosts internos para evitar colisiones y depender del .env
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: ths-authentik-postgres
|
||||||
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER}
|
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER}
|
||||||
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME}
|
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME}
|
||||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
||||||
|
|
||||||
AUTHENTIK_REDIS__HOST: ${AUTHENTIK_REDIS_HOST}
|
AUTHENTIK_REDIS__HOST: ths-authentik-redis
|
||||||
|
|
||||||
# Bootstrap inicial (primera vez)
|
|
||||||
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
|
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
|
||||||
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}
|
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}
|
||||||
AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN}
|
AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN}
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- authentik-postgres
|
- ths-authentik-postgres
|
||||||
- authentik-redis
|
- ths-authentik-redis
|
||||||
|
|
||||||
expose:
|
expose:
|
||||||
- "${AUTHENTIK_HTTP_PORT}"
|
- "${AUTHENTIK_HTTP_PORT}"
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- authentik_internal
|
- ths_authentik_internal
|
||||||
- proxy
|
- proxy
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
traefik.enable: "true"
|
traefik.enable: "true"
|
||||||
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
|
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
|
||||||
|
|
||||||
# Router del panel de Authentik
|
# Service Authentik (panel + endpoints)
|
||||||
traefik.http.routers.authentik.rule: "Host(`${AUTHENTIK_DOMAIN}`)"
|
traefik.http.services.ths-authentik.loadbalancer.server.port: "${AUTHENTIK_HTTP_PORT}"
|
||||||
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.
|
# Panel Authentik (auth.thehomelesssherlock.com)
|
||||||
traefik.http.middlewares.authentik.forwardauth.address: "http://authentik-server:${AUTHENTIK_HTTP_PORT}/outpost.goauthentik.io/auth/traefik"
|
traefik.http.routers.ths-authentik.rule: "Host(`${AUTHENTIK_DOMAIN}`)"
|
||||||
traefik.http.middlewares.authentik.forwardauth.trustForwardHeader: "true"
|
traefik.http.routers.ths-authentik.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
||||||
traefik.http.middlewares.authentik.forwardauth.authResponseHeaders: "X-Authentik-Username,X-Authentik-Groups,X-Authentik-Email,X-Authentik-Uid,X-Authentik-Jwt"
|
traefik.http.routers.ths-authentik.tls: "true"
|
||||||
|
traefik.http.routers.ths-authentik.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
|
||||||
|
traefik.http.routers.ths-authentik.service: "ths-authentik"
|
||||||
|
|
||||||
# Callback del outpost en gitea hacia Authentik
|
# Middleware forwardAuth (para proteger otros servicios) -> usar ths-ths-authentik@docker en tus stacks THS
|
||||||
traefik.http.routers.authentik-outpost-gitea.rule: "Host(`${GITEA_DOMAIN}`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
traefik.http.middlewares.ths-authentik.forwardauth.address: "http://ths-authentik-server:${AUTHENTIK_HTTP_PORT}/outpost.goauthentik.io/auth/traefik"
|
||||||
traefik.http.routers.authentik-outpost-gitea.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
traefik.http.middlewares.ths-authentik.forwardauth.trustForwardHeader: "true"
|
||||||
traefik.http.routers.authentik-outpost-gitea.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
|
traefik.http.middlewares.ths-authentik.forwardauth.authResponseHeaders: "X-Authentik-Username,X-Authentik-Groups,X-Authentik-Email,X-Authentik-Uid,X-Authentik-Jwt"
|
||||||
traefik.http.routers.authentik-outpost-gitea.service: "authentik"
|
|
||||||
traefik.http.routers.authentik-outpost-gitea.priority: "50"
|
|
||||||
|
|
||||||
authentik-worker:
|
# OUTPOST genérico para TODO el dominio THS (subdominios + apex + www)
|
||||||
|
# ✅ Sin comas dentro de Host()
|
||||||
|
traefik.http.routers.ths-authentik-outpost.rule: "(HostRegexp(`{subdomain:[a-z0-9-]+}.thehomelesssherlock.com`) || Host(`thehomelesssherlock.com`) || Host(`www.thehomelesssherlock.com`)) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||||
|
traefik.http.routers.ths-authentik-outpost.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
||||||
|
traefik.http.routers.ths-authentik-outpost.tls: "true"
|
||||||
|
traefik.http.routers.ths-authentik-outpost.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
|
||||||
|
traefik.http.routers.ths-authentik-outpost.service: "ths-authentik"
|
||||||
|
traefik.http.routers.ths-authentik-outpost.priority: "1000"
|
||||||
|
|
||||||
|
ths-authentik-worker:
|
||||||
image: ${AUTHENTIK_IMAGE}
|
image: ${AUTHENTIK_IMAGE}
|
||||||
container_name: authentik-worker
|
container_name: ths-authentik-worker
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: ["worker"]
|
command: ["worker"]
|
||||||
environment:
|
environment:
|
||||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
||||||
|
|
||||||
AUTHENTIK_POSTGRESQL__HOST: ${AUTHENTIK_DB_HOST}
|
# OJO: forzamos hosts internos igual que en server
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: ths-authentik-postgres
|
||||||
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER}
|
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER}
|
||||||
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME}
|
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME}
|
||||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
||||||
|
|
||||||
AUTHENTIK_REDIS__HOST: ${AUTHENTIK_REDIS_HOST}
|
AUTHENTIK_REDIS__HOST: ths-authentik-redis
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- authentik-postgres
|
- ths-authentik-postgres
|
||||||
- authentik-redis
|
- ths-authentik-redis
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- authentik_internal
|
- ths_authentik_internal
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
authentik_internal:
|
ths_authentik_internal:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,15 @@
|
|||||||
services:
|
services:
|
||||||
portainer:
|
portainer:
|
||||||
image: ${PORTAINER_IMAGE:-portainer/portainer-ce:latest}
|
image: portainer/portainer-ee:2.33.7
|
||||||
container_name: portainer
|
container_name: portainer
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# Clave de cifrado: misma clave montada en las dos rutas
|
- /opt/portainer/secrets/portainer:/run/secrets/portainer:ro,Z
|
||||||
- ${PORTAINER_SECRET_PATH:-/opt/portainer/secrets/portainer}:/run/secrets/portainer:ro,Z
|
- /opt/portainer/secrets/portainer:/run/portainer/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
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- /opt/portainer/data:/data:Z
|
||||||
|
|
||||||
# Datos de Portainer (DB cifrada incluida)
|
|
||||||
- ${PORTAINER_DATA_PATH:-/opt/portainer/data}:/data:Z
|
|
||||||
|
|
||||||
# SELinux: evita bloqueos con docker.sock
|
|
||||||
security_opt:
|
security_opt:
|
||||||
- label=disable
|
- label=disable
|
||||||
|
|
||||||
@@ -26,28 +17,24 @@ services:
|
|||||||
- proxy
|
- proxy
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
traefik.enable: "true"
|
- "traefik.enable=true"
|
||||||
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK:-proxy}"
|
- "traefik.docker.network=proxy"
|
||||||
|
|
||||||
############################
|
# 1) UI protegida Authentik
|
||||||
# 1) UI protegida (ej: SSO)
|
- "traefik.http.routers.portainer.rule=Host(`portainer.thehomelesssherlock.com`)"
|
||||||
############################
|
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||||
traefik.http.routers.portainer.rule: "Host(`${PORTAINER_DOMAIN:-portainer.example.com}`)"
|
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||||
traefik.http.routers.portainer.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE:-websecure}"
|
- "traefik.http.routers.portainer.middlewares=ths-authentik@docker"
|
||||||
traefik.http.routers.portainer.tls.certresolver: "${TRAEFIK_CERTRESOLVER:-letsencrypt}"
|
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
|
||||||
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 Authentik, SOLO por VPN (WireGuard)
|
||||||
# 2) API/App móvil SIN SSO, restringida por IP (ej: VPN)
|
- "traefik.http.middlewares.portainer-api-ip.ipallowlist.sourcerange=10.8.0.0/24,172.18.0.1/32"
|
||||||
#########################################################
|
- "traefik.http.routers.portainer-direct.rule=Host(`portainer-api.thehomelesssherlock.com`)"
|
||||||
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.entrypoints=websecure"
|
||||||
traefik.http.routers.portainer-direct.rule: "Host(`${PORTAINER_API_DOMAIN:-portainer-api.example.com}`)"
|
- "traefik.http.routers.portainer-direct.tls.certresolver=letsencrypt"
|
||||||
traefik.http.routers.portainer-direct.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE:-websecure}"
|
- "traefik.http.routers.portainer-direct.middlewares=portainer-api-ip"
|
||||||
traefik.http.routers.portainer-direct.tls.certresolver: "${TRAEFIK_CERTRESOLVER:-letsencrypt}"
|
- "traefik.http.routers.portainer-direct.service=portainer"
|
||||||
traefik.http.routers.portainer-direct.middlewares: "portainer-api-ip"
|
- "traefik.http.routers.portainer-direct.priority=100"
|
||||||
traefik.http.routers.portainer-direct.service: "portainer"
|
|
||||||
traefik.http.routers.portainer-direct.priority: "100"
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
|
|||||||
593
media-server/README.md
Normal file
593
media-server/README.md
Normal file
@@ -0,0 +1,593 @@
|
|||||||
|
# Media Server - Stack Completo de Gestión de Medios
|
||||||
|
|
||||||
|
Stack completo para gestión y streaming de contenido multimedia con automatización de descargas.
|
||||||
|
|
||||||
|
## 🎯 Flujo de Trabajo
|
||||||
|
|
||||||
|
1. **Usuario solicita contenido** → Jellyseerr
|
||||||
|
2. **Jellyseerr envía solicitud** → Sonarr (series) o Radarr (películas)
|
||||||
|
3. **Sonarr/Radarr busca contenido** → Prowlarr/Jackett
|
||||||
|
4. **Prowlarr consulta trackers** → Indexers configurados
|
||||||
|
5. **Se descarga el contenido** → Cliente de descargas
|
||||||
|
6. **Sonarr/Radarr organiza archivos** → Directorios de medios
|
||||||
|
7. **Jellyfin detecta nuevo contenido** → Disponible para streaming
|
||||||
|
|
||||||
|
## 📋 Descripción
|
||||||
|
|
||||||
|
Este stack despliega un servidor multimedia completo con:
|
||||||
|
|
||||||
|
| Servicio | Descripción | Puerto | Propósito |
|
||||||
|
|----------|-------------|--------|-----------|
|
||||||
|
| **Jellyfin** | Servidor de streaming de medios | 8096 | Reproducir contenido multimedia |
|
||||||
|
| **Jellyseerr** | Sistema de solicitudes | 5055 | Permitir solicitudes de usuarios |
|
||||||
|
| **Sonarr** | Gestor de series TV | 8989 | Automatizar descargas de series |
|
||||||
|
| **Radarr** | Gestor de películas | 7878 | Automatizar descargas de películas |
|
||||||
|
| **Prowlarr** | Gestor de indexers | 9696 | Centralizar trackers |
|
||||||
|
| **Jackett** | Proxy de trackers | 9117 | Alternativa a Prowlarr |
|
||||||
|
| **FlareSolverr** | Resolver Cloudflare | 8191 | Bypasear protecciones |
|
||||||
|
|
||||||
|
**Características**:
|
||||||
|
- ✅ Automatización completa de descargas
|
||||||
|
- ✅ Gestión de calidad y formatos
|
||||||
|
- ✅ Sistema de solicitudes para usuarios
|
||||||
|
- ✅ Protección con SSO (Authentik)
|
||||||
|
- ✅ Certificados SSL automáticos (Let's Encrypt)
|
||||||
|
- ✅ Red aislada para servicios internos
|
||||||
|
|
||||||
|
## 🚀 Despliegue
|
||||||
|
|
||||||
|
### Prerequisitos
|
||||||
|
|
||||||
|
1. **Red Docker**: Asegúrate de que la red `proxy` existe
|
||||||
|
2. **Registros DNS**: Configura los registros A para tus dominios de servicios
|
||||||
|
3. **Almacenamiento**: Prepara los directorios para medios y configuraciones
|
||||||
|
|
||||||
|
### Desde Portainer
|
||||||
|
|
||||||
|
1. Ve a **Stacks** → **Add stack**
|
||||||
|
2. Nombre: `media-server`
|
||||||
|
3. Selecciona **Repository** o **Git repository**
|
||||||
|
4. Configura:
|
||||||
|
- Repository URL: `<tu-repositorio>`
|
||||||
|
- Repository reference: `main`
|
||||||
|
- Compose path: `media-server/docker-compose.yml`
|
||||||
|
5. Carga el archivo de variables de entorno: `media-server/stack.env`
|
||||||
|
6. Haz clic en **Deploy the stack**
|
||||||
|
|
||||||
|
### Variables de Entorno Importantes
|
||||||
|
|
||||||
|
Edita el archivo `stack.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Global
|
||||||
|
TZ=Europe/Madrid
|
||||||
|
PUID=0
|
||||||
|
PGID=0
|
||||||
|
|
||||||
|
# Paths - Directorio base para configuraciones
|
||||||
|
COMMON_PATH=/opt/media-server
|
||||||
|
|
||||||
|
# Media mounts - Rutas del servidor donde están los archivos de medios
|
||||||
|
MEDIA_TV=/mnt/media/tv
|
||||||
|
MEDIA_MOVIES=/mnt/media/movies
|
||||||
|
MEDIA_DOWNLOADS=/mnt/media/downloads
|
||||||
|
|
||||||
|
# Networks
|
||||||
|
TRAEFIK_DOCKER_NETWORK=proxy
|
||||||
|
MEDIA_NETWORK_NAME=media
|
||||||
|
|
||||||
|
# Traefik & SSL
|
||||||
|
TRAEFIK_ENABLE=true
|
||||||
|
TRAEFIK_ENTRYPOINTS=websecure
|
||||||
|
TRAEFIK_TLS=true
|
||||||
|
TRAEFIK_CERTRESOLVER=letsencrypt
|
||||||
|
AUTH_MIDDLEWARE=ths-authentik@docker
|
||||||
|
|
||||||
|
# Dominios - Personaliza según tu dominio
|
||||||
|
DOMAIN=tudominio.com
|
||||||
|
PROWLARR_HOST=prowlarr.tudominio.com
|
||||||
|
JACKETT_HOST=jackett.tudominio.com
|
||||||
|
SONARR_HOST=sonarr.tudominio.com
|
||||||
|
RADARR_HOST=radarr.tudominio.com
|
||||||
|
JELLYSEERR_HOST=requests.tudominio.com
|
||||||
|
JELLYFIN_HOST=media.tudominio.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚙️ Configuración Post-Instalación
|
||||||
|
|
||||||
|
### 1. Preparar Directorios
|
||||||
|
|
||||||
|
Antes de desplegar, crea las estructuras de directorios necesarias:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Directorio base de configuraciones
|
||||||
|
sudo mkdir -p /opt/media-server/configs/{prowlarr,jackett,sonarr,radarr,jellyseerr,jellyfin-vps}
|
||||||
|
sudo mkdir -p /opt/media-server/jellyfin/cache-vps
|
||||||
|
|
||||||
|
# Directorios de medios
|
||||||
|
sudo mkdir -p /mnt/media/{tv,movies,downloads}
|
||||||
|
|
||||||
|
# Ajustar permisos
|
||||||
|
sudo chown -R $USER:$USER /opt/media-server
|
||||||
|
sudo chown -R $USER:$USER /mnt/media
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configurar Prowlarr (Indexers)
|
||||||
|
|
||||||
|
**Prowlarr** es el gestor centralizado de indexers/trackers:
|
||||||
|
|
||||||
|
1. Accede a `https://prowlarr.tudominio.com`
|
||||||
|
2. Completa el asistente de configuración inicial
|
||||||
|
3. Ve a **Settings** → **Indexers** → **Add Indexer**
|
||||||
|
4. Añade tus trackers preferidos (públicos o privados)
|
||||||
|
5. Si algún tracker requiere FlareSolverr para Cloudflare:
|
||||||
|
- Ve a **Settings** → **Indexers** → **FlareSolverr**
|
||||||
|
- URL: `http://flaresolverr:8191`
|
||||||
|
|
||||||
|
### 3. Conectar Sonarr y Radarr con Prowlarr
|
||||||
|
|
||||||
|
En **Prowlarr**, añade las aplicaciones:
|
||||||
|
|
||||||
|
1. Ve a **Settings** → **Apps** → **Add Application**
|
||||||
|
2. Selecciona **Sonarr** o **Radarr**
|
||||||
|
3. Configura:
|
||||||
|
- **Prowlarr Server**: `http://prowlarr:9696`
|
||||||
|
- **Sonarr Server**: `http://sonarr:8989`
|
||||||
|
- **Radarr Server**: `http://radarr:7878`
|
||||||
|
- API Key: Cópiala desde Settings → General en cada aplicación
|
||||||
|
4. Haz clic en **Test** y luego **Save**
|
||||||
|
5. Sincroniza los indexers automáticamente
|
||||||
|
|
||||||
|
### 4. Configurar Clientes de Descarga
|
||||||
|
|
||||||
|
En **Sonarr** y **Radarr**, configura tu cliente de descargas (qBittorrent, Transmission, etc.):
|
||||||
|
|
||||||
|
1. Ve a **Settings** → **Download Clients** → **Add**
|
||||||
|
2. Selecciona tu cliente
|
||||||
|
3. Configura la conexión (host, puerto, usuario, contraseña)
|
||||||
|
4. Establece las categorías (tv para Sonarr, movies para Radarr)
|
||||||
|
|
||||||
|
### 5. Configurar Perfiles de Calidad
|
||||||
|
|
||||||
|
En **Sonarr** y **Radarr**:
|
||||||
|
|
||||||
|
1. Ve a **Settings** → **Profiles**
|
||||||
|
2. Configura los perfiles de calidad según tus preferencias
|
||||||
|
3. Ajusta el idioma preferido
|
||||||
|
4. Configura el formato preferido (1080p, 4K, etc.)
|
||||||
|
|
||||||
|
### 6. Configurar Jellyfin
|
||||||
|
|
||||||
|
**Jellyfin** es tu servidor de streaming:
|
||||||
|
|
||||||
|
1. Accede a `https://media.tudominio.com`
|
||||||
|
2. Completa el asistente de configuración:
|
||||||
|
- Crea el usuario administrador
|
||||||
|
- Configura las bibliotecas:
|
||||||
|
- **Series**: `/data/tvshows`
|
||||||
|
- **Películas**: `/data/movies`
|
||||||
|
3. Escanea las bibliotecas para detectar contenido
|
||||||
|
4. Configura metadatos (TMDb, TVDb, etc.)
|
||||||
|
|
||||||
|
### 7. Configurar Jellyseerr
|
||||||
|
|
||||||
|
**Jellyseerr** permite a los usuarios solicitar contenido:
|
||||||
|
|
||||||
|
1. Accede a `https://requests.tudominio.com`
|
||||||
|
2. Conecta con Jellyfin:
|
||||||
|
- URL: `http://jellyfin:8096`
|
||||||
|
- API Key: Desde Jellyfin Dashboard → API Keys
|
||||||
|
3. Conecta con Sonarr:
|
||||||
|
- URL: `http://sonarr:8989`
|
||||||
|
- API Key: Desde Sonarr Settings → General
|
||||||
|
4. Conecta con Radarr:
|
||||||
|
- URL: `http://radarr:7878`
|
||||||
|
- API Key: Desde Radarr Settings → General
|
||||||
|
5. Configura permisos de usuario
|
||||||
|
6. Activa notificaciones (opcional)
|
||||||
|
|
||||||
|
### 8. Integración con Authentik (SSO)
|
||||||
|
|
||||||
|
Todos los servicios están protegidos con Authentik por defecto mediante el middleware `ths-authentik@docker`.
|
||||||
|
|
||||||
|
Para personalizar el acceso:
|
||||||
|
|
||||||
|
1. En Authentik, crea aplicaciones para cada servicio
|
||||||
|
2. Configura grupos y permisos según tus necesidades
|
||||||
|
3. Los usuarios autenticados tendrán acceso automático
|
||||||
|
|
||||||
|
Si necesitas acceso público a Jellyfin:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# En stack.env, para Jellyfin
|
||||||
|
AUTH_MIDDLEWARE= # Deja vacío para acceso público
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 Configuración Avanzada
|
||||||
|
|
||||||
|
### Personalizar Puertos de Servicios
|
||||||
|
|
||||||
|
Por defecto los servicios usan sus puertos estándar:
|
||||||
|
|
||||||
|
```env
|
||||||
|
PROWLARR_PORT=9696
|
||||||
|
JACKETT_PORT=9117
|
||||||
|
SONARR_PORT=8989
|
||||||
|
RADARR_PORT=7878
|
||||||
|
JELLYSEERR_PORT=5055
|
||||||
|
JELLYFIN_PORT=8096
|
||||||
|
```
|
||||||
|
|
||||||
|
### Personalizar Nombres de Contenedores
|
||||||
|
|
||||||
|
```env
|
||||||
|
PROWLARR_CONTAINER_NAME=prowlarr-prod
|
||||||
|
SONARR_CONTAINER_NAME=sonarr-prod
|
||||||
|
# etc...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usar Imágenes Específicas
|
||||||
|
|
||||||
|
```env
|
||||||
|
JELLYFIN_IMAGE=lscr.io/linuxserver/jellyfin:10.8.13
|
||||||
|
SONARR_IMAGE=lscr.io/linuxserver/sonarr:4.0
|
||||||
|
RADARR_IMAGE=lscr.io/linuxserver/radarr:5.2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configurar FlareSolverr para Trackers Protegidos
|
||||||
|
|
||||||
|
FlareSolverr ayuda a resolver protecciones de Cloudflare:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Recursos de memoria
|
||||||
|
FLARESOLVERR_SHM_SIZE=1gb
|
||||||
|
|
||||||
|
# Nivel de logs
|
||||||
|
LOG_LEVEL=info
|
||||||
|
LOG_HTML=false
|
||||||
|
|
||||||
|
# Solucionador de captchas (none, hcaptcha-solver)
|
||||||
|
CAPTCHA_SOLVER=none
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configurar PUID/PGID Personalizado
|
||||||
|
|
||||||
|
Para evitar problemas de permisos, usa tu usuario del sistema:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
id $USER
|
||||||
|
# uid=1000(usuario) gid=1000(usuario)
|
||||||
|
```
|
||||||
|
|
||||||
|
```env
|
||||||
|
PUID=1000
|
||||||
|
PGID=1000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notificaciones Personalizadas
|
||||||
|
|
||||||
|
Configura notificaciones en cada aplicación:
|
||||||
|
|
||||||
|
**Sonarr/Radarr**:
|
||||||
|
- Ve a **Settings** → **Connect** → **Add Notification**
|
||||||
|
- Opciones: Discord, Telegram, Email, Slack, etc.
|
||||||
|
|
||||||
|
**Jellyseerr**:
|
||||||
|
- Ve a **Settings** → **Notifications**
|
||||||
|
- Configura Discord, Email, Telegram, etc.
|
||||||
|
|
||||||
|
## 🛠️ Troubleshooting
|
||||||
|
|
||||||
|
### Sonarr/Radarr no encuentra series/películas
|
||||||
|
|
||||||
|
1. Verifica que Prowlarr está conectado correctamente
|
||||||
|
2. Comprueba que los indexers están funcionando en Prowlarr
|
||||||
|
3. Revisa los logs:
|
||||||
|
```bash
|
||||||
|
docker logs sonarr
|
||||||
|
docker logs radarr
|
||||||
|
```
|
||||||
|
|
||||||
|
### FlareSolverr no resuelve captchas
|
||||||
|
|
||||||
|
1. Verifica los logs:
|
||||||
|
```bash
|
||||||
|
docker logs flaresolverr
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Aumenta la memoria compartida si es necesario:
|
||||||
|
```env
|
||||||
|
FLARESOLVERR_SHM_SIZE=2gb
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Prueba la conectividad:
|
||||||
|
```bash
|
||||||
|
docker exec prowlarr curl http://flaresolverr:8191/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error de permisos en directorios de medios
|
||||||
|
|
||||||
|
Si usas SELinux, los volúmenes ya tienen `:Z`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Si persisten problemas
|
||||||
|
sudo chcon -Rt svirt_sandbox_file_t /opt/media-server
|
||||||
|
sudo chcon -Rt svirt_sandbox_file_t /mnt/media
|
||||||
|
```
|
||||||
|
|
||||||
|
Si usas PUID/PGID personalizado:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ajustar permisos
|
||||||
|
sudo chown -R 1000:1000 /opt/media-server
|
||||||
|
sudo chown -R 1000:1000 /mnt/media
|
||||||
|
```
|
||||||
|
|
||||||
|
### Jellyfin no detecta el contenido
|
||||||
|
|
||||||
|
1. Verifica las rutas de las bibliotecas en Jellyfin:
|
||||||
|
- Series: `/data/tvshows`
|
||||||
|
- Películas: `/data/movies`
|
||||||
|
|
||||||
|
2. Escanea manualmente las bibliotecas:
|
||||||
|
- Dashboard → Libraries → Scan All Libraries
|
||||||
|
|
||||||
|
3. Verifica permisos de lectura:
|
||||||
|
```bash
|
||||||
|
docker exec jellyfin-vps ls -la /data/tvshows
|
||||||
|
docker exec jellyfin-vps ls -la /data/movies
|
||||||
|
```
|
||||||
|
|
||||||
|
### Jellyseerr no se conecta con Sonarr/Radarr
|
||||||
|
|
||||||
|
1. Verifica las API Keys en cada servicio
|
||||||
|
2. Usa las URLs internas del contenedor:
|
||||||
|
- Sonarr: `http://sonarr:8989`
|
||||||
|
- Radarr: `http://radarr:7878`
|
||||||
|
- Jellyfin: `http://jellyfin:8096`
|
||||||
|
|
||||||
|
3. Revisa los logs:
|
||||||
|
```bash
|
||||||
|
docker logs jellyseerr
|
||||||
|
```
|
||||||
|
|
||||||
|
### Los servicios no son accesibles vía web
|
||||||
|
|
||||||
|
1. Verifica que Traefik está corriendo
|
||||||
|
2. Comprueba las etiquetas de Traefik en los contenedores:
|
||||||
|
```bash
|
||||||
|
docker inspect prowlarr | grep traefik
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Verifica los certificados SSL:
|
||||||
|
```bash
|
||||||
|
docker logs traefik | grep letsencrypt
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Comprueba los registros DNS:
|
||||||
|
```bash
|
||||||
|
nslookup prowlarr.tudominio.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 Recursos Adicionales
|
||||||
|
|
||||||
|
- [Documentación oficial de Jellyfin](https://jellyfin.org/docs/)
|
||||||
|
- [Wiki de Sonarr](https://wiki.servarr.com/sonarr)
|
||||||
|
- [Wiki de Radarr](https://wiki.servarr.com/radarr)
|
||||||
|
- [Documentación de Prowlarr](https://wiki.servarr.com/prowlarr)
|
||||||
|
- [Documentación de Jellyseerr](https://docs.jellyseerr.dev/)
|
||||||
|
- [FlareSolverr GitHub](https://github.com/FlareSolverr/FlareSolverr)
|
||||||
|
|
||||||
|
## 🔒 Seguridad
|
||||||
|
|
||||||
|
- **SSO con Authentik**: Todos los servicios protegidos por defecto
|
||||||
|
- **API Keys**: Protege las API keys de cada servicio
|
||||||
|
- **VPN**: Considera usar VPN para clientes de descarga
|
||||||
|
- **Trackers Privados**: Usa credenciales seguras para trackers privados
|
||||||
|
- **Certificados SSL**: Let's Encrypt mediante Traefik
|
||||||
|
- **Backups**: Realiza backups regulares de configuraciones y bases de datos
|
||||||
|
|
||||||
|
## 💾 Backups
|
||||||
|
|
||||||
|
### Backup de Configuraciones
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup de todas las configuraciones
|
||||||
|
sudo tar -czf media-server-configs-$(date +%Y%m%d).tar.gz /opt/media-server/configs
|
||||||
|
|
||||||
|
# Restaurar
|
||||||
|
sudo tar -xzf media-server-configs-YYYYMMDD.tar.gz -C /
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup de Bases de Datos Internas
|
||||||
|
|
||||||
|
Cada servicio *arr tiene su propia base de datos SQLite:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sonarr
|
||||||
|
docker exec sonarr cp /config/sonarr.db /config/sonarr.db.backup
|
||||||
|
|
||||||
|
# Radarr
|
||||||
|
docker exec radarr cp /config/radarr.db /config/radarr.db.backup
|
||||||
|
|
||||||
|
# Prowlarr
|
||||||
|
docker exec prowlarr cp /config/prowlarr.db /config/prowlarr.db.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup Completo del Stack
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Script de backup completo
|
||||||
|
#!/bin/bash
|
||||||
|
BACKUP_DIR=/backups/media-server
|
||||||
|
DATE=$(date +%Y%m%d)
|
||||||
|
|
||||||
|
mkdir -p $BACKUP_DIR
|
||||||
|
|
||||||
|
# Configuraciones
|
||||||
|
sudo tar -czf $BACKUP_DIR/configs-$DATE.tar.gz /opt/media-server/configs
|
||||||
|
|
||||||
|
# Lista de contenido (opcional)
|
||||||
|
sudo tar -czf $BACKUP_DIR/media-structure-$DATE.tar.gz \
|
||||||
|
--exclude='*' \
|
||||||
|
--include='*/' \
|
||||||
|
/mnt/media
|
||||||
|
|
||||||
|
echo "Backup completado: $BACKUP_DIR"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 Actualizaciones
|
||||||
|
|
||||||
|
1. **Backup primero**: Siempre haz backup antes de actualizar
|
||||||
|
2. Actualiza las versiones de imágenes en `stack.env`:
|
||||||
|
```env
|
||||||
|
JELLYFIN_IMAGE=lscr.io/linuxserver/jellyfin:10.9.0
|
||||||
|
SONARR_IMAGE=lscr.io/linuxserver/sonarr:latest
|
||||||
|
RADARR_IMAGE=lscr.io/linuxserver/radarr:latest
|
||||||
|
```
|
||||||
|
3. Actualiza el stack en Portainer o con Docker Compose:
|
||||||
|
```bash
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
4. Verifica los logs de cada servicio
|
||||||
|
5. Comprueba que todo funciona correctamente
|
||||||
|
|
||||||
|
### Actualizaciones Recomendadas
|
||||||
|
|
||||||
|
- **Jellyfin**: Revisa changelog antes de actualizar versiones mayores
|
||||||
|
- **Sonarr/Radarr**: Usa `latest` para recibir actualizaciones automáticas
|
||||||
|
- **Prowlarr**: Mantén sincronizado con Sonarr/Radarr
|
||||||
|
- **FlareSolverr**: Actualiza cuando haya cambios en Cloudflare
|
||||||
|
|
||||||
|
## 📊 Monitoreo
|
||||||
|
|
||||||
|
### Ver Estadísticas de Uso
|
||||||
|
|
||||||
|
**Jellyfin**:
|
||||||
|
- Dashboard → Activity → Ver reproducciones activas
|
||||||
|
- Dashboard → Users → Estadísticas por usuario
|
||||||
|
|
||||||
|
**Sonarr/Radarr**:
|
||||||
|
- System → Status → Ver actividad de descargas
|
||||||
|
- Queue → Ver cola de descargas
|
||||||
|
|
||||||
|
**Prowlarr**:
|
||||||
|
- System → Status → Estadísticas de indexers
|
||||||
|
|
||||||
|
### Logs de Servicios
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ver logs en tiempo real
|
||||||
|
docker logs -f prowlarr
|
||||||
|
docker logs -f jackett
|
||||||
|
docker logs -f sonarr
|
||||||
|
docker logs -f radarr
|
||||||
|
docker logs -f jellyseerr
|
||||||
|
docker logs -f jellyfin-vps
|
||||||
|
docker logs -f flaresolverr
|
||||||
|
|
||||||
|
# Ver últimas 100 líneas
|
||||||
|
docker logs --tail 100 sonarr
|
||||||
|
```
|
||||||
|
|
||||||
|
### Salud del Sistema
|
||||||
|
|
||||||
|
Cada servicio *arr tiene una página de salud:
|
||||||
|
|
||||||
|
- **Sonarr**: Settings → General → System Status
|
||||||
|
- **Radarr**: Settings → General → System Status
|
||||||
|
- **Prowlarr**: System → Status
|
||||||
|
|
||||||
|
### Monitoreo de Recursos
|
||||||
|
|
||||||
|
Usa `docker stats` para ver uso de recursos:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stats prowlarr sonarr radarr jellyfin-vps jellyseerr
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notificaciones de Estado
|
||||||
|
|
||||||
|
Configura notificaciones en Sonarr/Radarr para:
|
||||||
|
- Descargas completadas
|
||||||
|
- Fallos en descargas
|
||||||
|
- Problemas con indexers
|
||||||
|
- Actualizaciones de aplicaciones
|
||||||
|
|
||||||
|
## 📝 Referencia Rápida
|
||||||
|
|
||||||
|
### URLs de Servicios (Por Defecto)
|
||||||
|
|
||||||
|
```
|
||||||
|
Prowlarr: https://prowlarr.tudominio.com
|
||||||
|
Jackett: https://jackett.tudominio.com
|
||||||
|
Sonarr: https://sonarr.tudominio.com
|
||||||
|
Radarr: https://radarr.tudominio.com
|
||||||
|
Jellyseerr: https://requests.tudominio.com
|
||||||
|
Jellyfin: https://media.tudominio.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### URLs Internas (Entre Contenedores)
|
||||||
|
|
||||||
|
```
|
||||||
|
Prowlarr: http://prowlarr:9696
|
||||||
|
Jackett: http://jackett:9117
|
||||||
|
Sonarr: http://sonarr:8989
|
||||||
|
Radarr: http://radarr:7878
|
||||||
|
Jellyseerr: http://jellyseerr:5055
|
||||||
|
Jellyfin: http://jellyfin:8096
|
||||||
|
FlareSolverr: http://flaresolverr:8191
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rutas de Montaje en Contenedores
|
||||||
|
|
||||||
|
```
|
||||||
|
Configuraciones: /config
|
||||||
|
Series TV: /tv (Sonarr), /data/tvshows (Jellyfin)
|
||||||
|
Películas: /movies (Radarr), /data/movies (Jellyfin)
|
||||||
|
Descargas: /downloads
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comandos Útiles
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ver todos los contenedores del stack
|
||||||
|
docker ps --filter "name=prowlarr|sonarr|radarr|jellyfin|jellyseerr|jackett|flaresolverr"
|
||||||
|
|
||||||
|
# Reiniciar un servicio específico
|
||||||
|
docker restart sonarr
|
||||||
|
|
||||||
|
# Ver uso de recursos
|
||||||
|
docker stats --no-stream prowlarr sonarr radarr jellyfin-vps
|
||||||
|
|
||||||
|
# Backup rápido de configuración
|
||||||
|
docker exec sonarr tar czf /config/backup-$(date +%Y%m%d).tar.gz /config/*.db
|
||||||
|
|
||||||
|
# Limpiar logs antiguos
|
||||||
|
docker exec sonarr find /config/logs -type f -mtime +30 -delete
|
||||||
|
```
|
||||||
|
|
||||||
|
### Orden de Configuración Recomendado
|
||||||
|
|
||||||
|
1. ✅ FlareSolverr (si es necesario)
|
||||||
|
2. ✅ Prowlarr → Añadir indexers
|
||||||
|
3. ✅ Sonarr/Radarr → Configurar cliente de descargas
|
||||||
|
4. ✅ Prowlarr → Conectar con Sonarr/Radarr
|
||||||
|
5. ✅ Jellyfin → Añadir bibliotecas
|
||||||
|
6. ✅ Jellyseerr → Conectar todo
|
||||||
|
|
||||||
|
## 🤝 Soporte y Contribuciones
|
||||||
|
|
||||||
|
Para problemas o sugerencias:
|
||||||
|
1. Revisa la sección de Troubleshooting
|
||||||
|
2. Consulta la documentación oficial de cada servicio
|
||||||
|
3. Verifica los logs del contenedor específico
|
||||||
|
|
||||||
|
## 📄 Licencia
|
||||||
|
|
||||||
|
Este stack utiliza software de código abierto. Consulta las licencias individuales de cada proyecto.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Nota**: Este stack está diseñado para uso personal. Asegúrate de cumplir con las leyes de copyright de tu región al descargar contenido.
|
||||||
166
media-server/docker-compose.yml
Normal file
166
media-server/docker-compose.yml
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
media:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
services:
|
||||||
|
flaresolverr:
|
||||||
|
image: ghcr.io/flaresolverr/flaresolverr:latest
|
||||||
|
container_name: flaresolverr
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=${LOG_LEVEL:-info}
|
||||||
|
- LOG_HTML=${LOG_HTML:-false}
|
||||||
|
- CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
shm_size: "1gb"
|
||||||
|
|
||||||
|
prowlarr:
|
||||||
|
image: lscr.io/linuxserver/prowlarr:latest
|
||||||
|
container_name: prowlarr
|
||||||
|
environment:
|
||||||
|
- PUID=0
|
||||||
|
- PGID=0
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
volumes:
|
||||||
|
- ${COMMON_PATH}/configs/prowlarr:/config:Z
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.prowlarr.rule=Host(`${PROWLARR_HOST}`)
|
||||||
|
- traefik.http.routers.prowlarr.entrypoints=websecure
|
||||||
|
- traefik.http.routers.prowlarr.tls=true
|
||||||
|
- traefik.http.routers.prowlarr.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.prowlarr.middlewares=ths-authentik@docker
|
||||||
|
- traefik.http.services.prowlarr.loadbalancer.server.port=9696
|
||||||
|
|
||||||
|
jackett:
|
||||||
|
image: lscr.io/linuxserver/jackett:latest
|
||||||
|
container_name: jackett
|
||||||
|
environment:
|
||||||
|
- PUID=0
|
||||||
|
- PGID=0
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
volumes:
|
||||||
|
- ${COMMON_PATH}/configs/jackett:/config:Z
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.jackett.rule=Host(`${JACKETT_HOST}`)
|
||||||
|
- traefik.http.routers.jackett.entrypoints=websecure
|
||||||
|
- traefik.http.routers.jackett.tls=true
|
||||||
|
- traefik.http.routers.jackett.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.jackett.middlewares=ths-authentik@docker
|
||||||
|
- traefik.http.services.jackett.loadbalancer.server.port=9117
|
||||||
|
|
||||||
|
sonarr:
|
||||||
|
image: lscr.io/linuxserver/sonarr:latest
|
||||||
|
container_name: sonarr
|
||||||
|
environment:
|
||||||
|
- PUID=0
|
||||||
|
- PGID=0
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
volumes:
|
||||||
|
- ${COMMON_PATH}/configs/sonarr:/config:Z
|
||||||
|
- /mnt/media/tv:/tv
|
||||||
|
- /mnt/media/downloads:/downloads
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.sonarr.rule=Host(`${SONARR_HOST}`)
|
||||||
|
- traefik.http.routers.sonarr.entrypoints=websecure
|
||||||
|
- traefik.http.routers.sonarr.tls=true
|
||||||
|
- traefik.http.routers.sonarr.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.sonarr.middlewares=ths-authentik@docker
|
||||||
|
- traefik.http.services.sonarr.loadbalancer.server.port=8989
|
||||||
|
|
||||||
|
radarr:
|
||||||
|
image: lscr.io/linuxserver/radarr:latest
|
||||||
|
container_name: radarr
|
||||||
|
environment:
|
||||||
|
- PUID=0
|
||||||
|
- PGID=0
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
volumes:
|
||||||
|
- ${COMMON_PATH}/configs/radarr:/config:Z
|
||||||
|
- /mnt/media/movies:/movies
|
||||||
|
- /mnt/media/downloads:/downloads
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.radarr.rule=Host(`${RADARR_HOST}`)
|
||||||
|
- traefik.http.routers.radarr.entrypoints=websecure
|
||||||
|
- traefik.http.routers.radarr.tls=true
|
||||||
|
- traefik.http.routers.radarr.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.radarr.middlewares=ths-authentik@docker
|
||||||
|
- traefik.http.services.radarr.loadbalancer.server.port=7878
|
||||||
|
|
||||||
|
jellyseerr:
|
||||||
|
image: fallenbagel/jellyseerr:latest
|
||||||
|
container_name: jellyseerr
|
||||||
|
environment:
|
||||||
|
- LOG_LEVEL=debug
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
volumes:
|
||||||
|
- ${COMMON_PATH}/configs/jellyseerr:/app/config:Z
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.jellyseerr.rule=Host(`${JELLYSEERR_HOST}`)
|
||||||
|
- traefik.http.routers.jellyseerr.entrypoints=websecure
|
||||||
|
- traefik.http.routers.jellyseerr.tls=true
|
||||||
|
- traefik.http.routers.jellyseerr.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.jellyseerr.middlewares=ths-authentik@docker
|
||||||
|
- traefik.http.services.jellyseerr.loadbalancer.server.port=5055
|
||||||
|
|
||||||
|
# Opcional: Jellyfin en VPS (sin GPU)
|
||||||
|
jellyfin:
|
||||||
|
image: lscr.io/linuxserver/jellyfin:latest
|
||||||
|
container_name: jellyfin-vps
|
||||||
|
environment:
|
||||||
|
- PUID=0
|
||||||
|
- PGID=0
|
||||||
|
- TZ=${TZ:-Europe/Madrid}
|
||||||
|
volumes:
|
||||||
|
- ${COMMON_PATH}/configs/jellyfin-vps:/config:Z
|
||||||
|
- ${COMMON_PATH}/jellyfin/cache-vps:/cache:Z
|
||||||
|
- /mnt/media/tv:/data/tvshows
|
||||||
|
- /mnt/media/movies:/data/movies
|
||||||
|
- /mnt/media/downloads:/data/media_downloads
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- media
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.jellyfin.rule=Host(`${JELLYFIN_HOST}`)
|
||||||
|
- traefik.http.routers.jellyfin.entrypoints=websecure
|
||||||
|
- traefik.http.routers.jellyfin.tls=true
|
||||||
|
- traefik.http.routers.jellyfin.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.jellyfin.middlewares=ths-authentik@docker
|
||||||
|
- traefik.http.services.jellyfin.loadbalancer.server.port=8096
|
||||||
|
|
||||||
96
media-server/stack.env
Normal file
96
media-server/stack.env
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# =========================
|
||||||
|
# Global
|
||||||
|
# =========================
|
||||||
|
TZ=
|
||||||
|
LOG_LEVEL=
|
||||||
|
LOG_HTML=
|
||||||
|
CAPTCHA_SOLVER=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Paths (VPS)
|
||||||
|
# =========================
|
||||||
|
COMMON_PATH=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Media mounts (HOST VPS)
|
||||||
|
# =========================
|
||||||
|
MEDIA_MOUNT_BASE=
|
||||||
|
MEDIA_TV=
|
||||||
|
MEDIA_MOVIES=
|
||||||
|
MEDIA_DOWNLOADS=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# PUID/PGID
|
||||||
|
# =========================
|
||||||
|
PUID=
|
||||||
|
PGID=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Networks
|
||||||
|
# =========================
|
||||||
|
TRAEFIK_DOCKER_NETWORK=
|
||||||
|
MEDIA_NETWORK_NAME=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Traefik common
|
||||||
|
# =========================
|
||||||
|
TRAEFIK_ENABLE=
|
||||||
|
TRAEFIK_ENTRYPOINTS=
|
||||||
|
TRAEFIK_TLS=
|
||||||
|
TRAEFIK_CERTRESOLVER=
|
||||||
|
AUTH_MIDDLEWARE=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Images (optional override)
|
||||||
|
# =========================
|
||||||
|
FLARESOLVERR_IMAGE=
|
||||||
|
PROWLARR_IMAGE=
|
||||||
|
JACKETT_IMAGE=
|
||||||
|
SONARR_IMAGE=
|
||||||
|
RADARR_IMAGE=
|
||||||
|
JELLYSEERR_IMAGE=
|
||||||
|
JELLYFIN_IMAGE=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Container names (optional override)
|
||||||
|
# =========================
|
||||||
|
FLARESOLVERR_CONTAINER_NAME=
|
||||||
|
PROWLARR_CONTAINER_NAME=
|
||||||
|
JACKETT_CONTAINER_NAME=
|
||||||
|
SONARR_CONTAINER_NAME=
|
||||||
|
RADARR_CONTAINER_NAME=
|
||||||
|
JELLYSEERR_CONTAINER_NAME=
|
||||||
|
JELLYFIN_CONTAINER_NAME=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Service ports (optional override)
|
||||||
|
# =========================
|
||||||
|
PROWLARR_PORT=
|
||||||
|
JACKETT_PORT=
|
||||||
|
SONARR_PORT=
|
||||||
|
RADARR_PORT=
|
||||||
|
JELLYSEERR_PORT=
|
||||||
|
JELLYFIN_PORT=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Jellyseerr extra
|
||||||
|
# =========================
|
||||||
|
JELLYSEERR_LOG_LEVEL=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# FlareSolverr resources
|
||||||
|
# =========================
|
||||||
|
FLARESOLVERR_SHM_SIZE=
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Domains
|
||||||
|
# =========================
|
||||||
|
DOMAIN=
|
||||||
|
PROWLARR_HOST=
|
||||||
|
JACKETT_HOST=
|
||||||
|
SONARR_HOST=
|
||||||
|
RADARR_HOST=
|
||||||
|
JELLYSEERR_HOST=
|
||||||
|
JELLYFIN_HOST=
|
||||||
|
|
||||||
|
|
||||||
@@ -1,28 +1,26 @@
|
|||||||
services:
|
services:
|
||||||
n8n:
|
n8n:
|
||||||
image: n8nio/n8n:latest
|
image: n8nio/n8n:latest
|
||||||
restart: unless-stopped
|
|
||||||
container_name: n8n
|
container_name: n8n
|
||||||
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- DB_TYPE=${N8N_DB_TYPE}
|
DB_TYPE: ${N8N_DB_TYPE}
|
||||||
- DB_POSTGRESDB_HOST=${N8N_DB_HOST}
|
DB_POSTGRESDB_HOST: ${N8N_DB_HOST}
|
||||||
- DB_POSTGRESDB_PORT=${N8N_DB_PORT}
|
DB_POSTGRESDB_PORT: ${N8N_DB_PORT}
|
||||||
- DB_POSTGRESDB_DATABASE=${N8N_DB_NAME}
|
DB_POSTGRESDB_DATABASE: ${N8N_DB_NAME}
|
||||||
- DB_POSTGRESDB_USER=${N8N_DB_USER}
|
DB_POSTGRESDB_USER: ${N8N_DB_USER}
|
||||||
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD}
|
DB_POSTGRESDB_PASSWORD: ${N8N_DB_PASSWORD}
|
||||||
|
|
||||||
- N8N_HOST=${N8N_HOST}
|
N8N_HOST: ${N8N_HOST}
|
||||||
- N8N_PORT=${N8N_PORT}
|
N8N_PORT: ${N8N_PORT}
|
||||||
- N8N_PROTOCOL=${N8N_PROTOCOL}
|
N8N_PROTOCOL: ${N8N_PROTOCOL}
|
||||||
- WEBHOOK_URL=${N8N_WEBHOOK_URL}
|
WEBHOOK_URL: ${N8N_WEBHOOK_URL}
|
||||||
|
|
||||||
- GENERIC_TIMEZONE=${N8N_TIMEZONE}
|
GENERIC_TIMEZONE: ${N8N_TIMEZONE}
|
||||||
|
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
|
||||||
|
|
||||||
# Clave para cifrar credenciales
|
NODE_ENV: ${N8N_NODE_ENV}
|
||||||
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
|
N8N_DIAGNOSTICS_ENABLED: ${N8N_DIAGNOSTICS_ENABLED}
|
||||||
|
|
||||||
- NODE_ENV=${N8N_NODE_ENV}
|
|
||||||
- N8N_DIAGNOSTICS_ENABLED=${N8N_DIAGNOSTICS_ENABLED}
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
- proxy
|
||||||
@@ -32,6 +30,7 @@ services:
|
|||||||
traefik.enable: "true"
|
traefik.enable: "true"
|
||||||
traefik.docker.network: "proxy"
|
traefik.docker.network: "proxy"
|
||||||
|
|
||||||
|
# UI (protegida por Authentik)
|
||||||
traefik.http.routers.n8n-ui.rule: "Host(`${N8N_DOMAIN}`)"
|
traefik.http.routers.n8n-ui.rule: "Host(`${N8N_DOMAIN}`)"
|
||||||
traefik.http.routers.n8n-ui.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
traefik.http.routers.n8n-ui.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
||||||
traefik.http.routers.n8n-ui.tls: "true"
|
traefik.http.routers.n8n-ui.tls: "true"
|
||||||
@@ -40,6 +39,7 @@ services:
|
|||||||
traefik.http.routers.n8n-ui.priority: "10"
|
traefik.http.routers.n8n-ui.priority: "10"
|
||||||
traefik.http.routers.n8n-ui.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE}"
|
traefik.http.routers.n8n-ui.middlewares: "${TRAEFIK_AUTH_MIDDLEWARE}"
|
||||||
|
|
||||||
|
# Webhooks (NO protegidos, para que terceros puedan llamar)
|
||||||
traefik.http.routers.n8n-webhook.rule: "Host(`${N8N_DOMAIN}`) && (PathPrefix(`/webhook`) || PathPrefix(`/webhook-test`))"
|
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.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
|
||||||
traefik.http.routers.n8n-webhook.tls: "true"
|
traefik.http.routers.n8n-webhook.tls: "true"
|
||||||
@@ -47,6 +47,7 @@ services:
|
|||||||
traefik.http.routers.n8n-webhook.service: "n8n"
|
traefik.http.routers.n8n-webhook.service: "n8n"
|
||||||
traefik.http.routers.n8n-webhook.priority: "20"
|
traefik.http.routers.n8n-webhook.priority: "20"
|
||||||
|
|
||||||
|
# Puerto interno de n8n
|
||||||
traefik.http.services.n8n.loadbalancer.server.port: "${N8N_PORT}"
|
traefik.http.services.n8n.loadbalancer.server.port: "${N8N_PORT}"
|
||||||
|
|
||||||
n8n-db:
|
n8n-db:
|
||||||
@@ -54,9 +55,9 @@ services:
|
|||||||
container_name: n8n-pg
|
container_name: n8n-pg
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=${POSTGRES_USER}
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
- POSTGRES_DB=${POSTGRES_DB}
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
volumes:
|
volumes:
|
||||||
- ${N8N_DB_DATA_PATH}:/var/lib/postgresql/data:Z
|
- ${N8N_DB_DATA_PATH}:/var/lib/postgresql/data:Z
|
||||||
networks:
|
networks:
|
||||||
@@ -65,7 +66,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
authentik_internal:
|
||||||
|
driver: bridge
|
||||||
n8n:
|
n8n:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
438
ruleta/README.md
438
ruleta/README.md
@@ -1,438 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
##### 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=
|
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ WG_DOMAIN=vpn-admin.tudominio.com
|
|||||||
TRAEFIK_DOCKER_NETWORK=proxy
|
TRAEFIK_DOCKER_NETWORK=proxy
|
||||||
TRAEFIK_ENTRYPOINT_SECURE=websecure
|
TRAEFIK_ENTRYPOINT_SECURE=websecure
|
||||||
TRAEFIK_CERTRESOLVER=letsencrypt
|
TRAEFIK_CERTRESOLVER=letsencrypt
|
||||||
TRAEFIK_AUTH_MIDDLEWARE=authentik@docker
|
TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker
|
||||||
```
|
```
|
||||||
|
|
||||||
> **⚠️ Importante**:
|
> **⚠️ Importante**:
|
||||||
|
|||||||
Reference in New Issue
Block a user