Stack multimedia autohospedado basado en Docker Compose para automatizar la búsqueda, descarga, organización y subtitulación de películas y series.
El repositorio está pensado para ser reutilizable: la configuración específica
del servidor se inyecta mediante .env y la operación avanzada se documenta en
docs/OPERATIONS.md.
| Servicio | Propósito | URL por defecto |
|---|---|---|
| Sonarr | Gestión automática de series | https://sonarr.<MEDIA_DOMAIN> |
| Radarr | Gestión automática de películas | https://radarr.<MEDIA_DOMAIN> |
| Prowlarr | Gestión centralizada de indexers | https://prowlarr.<MEDIA_DOMAIN> |
| Bazarr | Gestión automática de subtítulos | https://bazarr.<MEDIA_DOMAIN> |
| qBittorrent | Cliente BitTorrent | https://qbittorrent.<MEDIA_DOMAIN> |
| Traefik | Entrada HTTP/HTTPS y routing | https://<MEDIA_DOMAIN> |
| Tailscale | Red privada y salida mediante exit node | — |
Las imágenes de los contenedores están fijadas en los Compose individuales para hacer las actualizaciones explícitas y permitir que Renovate las proponga de forma controlada.
La topología separa cada servicio en su propio directorio, mientras que
docker-compose.yml actúa como orquestador mediante
Compose include.
Cliente
│
▼
DNS local / AdGuard
│ *.media-domain
▼
Traefik :80/:443
│
├── Sonarr
├── Radarr
├── Prowlarr
├── Bazarr
└── qBittorrent
│
└── network_mode: service:tailscale
│
└── Tailscale exit node
Los servicios ARR comparten el namespace de red de tailscale. Por tanto, su
tráfico de salida utiliza el exit node configurado en TS_EXTRA_ARGS. Traefik
permanece como punto de entrada público y enruta mediante labels de Docker.
Todos los servicios que procesan contenido montan el árbol de datos en /data.
Mantener torrents y bibliotecas bajo el mismo filesystem permite hardlinks y
movimientos atómicos durante la importación.
.
├── docker-compose.yml # Orquestador principal
├── .env.example # Plantilla de configuración
├── tailscale/
│ ├── tailscale-compose.yml # Namespace de red y exit node
│ └── config/ # Estado ignorado de Tailscale
├── traefik/ # Routing, TLS y certificados ACME
│ └── config/
├── sonarr/ # Compose de Sonarr
├── radarr/ # Compose de Radarr
├── prowlarr/ # Compose de Prowlarr
├── bazarr/ # Compose de Bazarr
├── qbittorrent/ # Compose de qBittorrent
├── scripts/
│ ├── init-data-dirs.sh # Crea el layout de bibliotecas
│ └── backup-config.sh # Backup de configuración
└── docs/
└── OPERATIONS.md # Runbook operativo del servidor
- Linux con Docker Engine y Docker Compose v2.
- Compose
includedisponible en la versión instalada de Docker Compose. - Soporte para
/dev/net/tuny capacidadesNET_ADMIN/SYS_MODULEpara Tailscale en modo kernel. - Un dominio administrado por Cloudflare si se usa el resolver ACME DNS.
- Una cuenta de Tailscale y un exit node autorizado.
- Directorios persistentes para configuración y datos multimedia.
Este repositorio no instala Docker, configura AdGuard ni crea el exit node. Esas piezas pertenecen a la infraestructura del host.
cp .env.example .env
chmod 600 .envEdita .env y revisa como mínimo:
PUIDyPGID: usuario y grupo propietarios de los datos.TZ: zona horaria del host.CONFIG_ROOT: raíz de las configuraciones persistentes. Para el layout recomendado dentro del checkout usa.; cada servicio escribirá en su propia carpetaconfig/ignorada.DATA_ROOT: raíz que contienetorrents,movies,tv,animesymusic.MEDIA_DOMAIN: dominio base para las URLs de los servicios.TRAEFIK_ACME_EMAIL: correo usado por Let's Encrypt.CF_DNS_API_TOKEN: token de Cloudflare con permisos de edición DNS para el dominio configurado.TS_STATE_DIR: directorio persistente del estado de Tailscale. Para el layout recomendado usa./tailscale/config.TS_AUTHKEY: auth key de Tailscale. No la guardes en Git ni la compartas.TS_EXTRA_ARGS: argumentos de Tailscale, incluido el exit node aprobado.
Los nombres de red TRAEFIK_NETWORK y TAILSCALE_NETWORK deben coincidir con
las redes Docker externas que usará el despliegue.
Los Compose esperan que las redes existan antes de iniciar el stack:
docker network create "${TRAEFIK_NETWORK:-frontend}"
docker network create "${TAILSCALE_NETWORK:-backend}"Si las redes ya existen, Docker devolverá un error de nombre duplicado; en ese caso no las recrees y continúa con el siguiente paso.
Con el .env cargado en el shell:
set -a
. ./.env
set +a
./scripts/init-data-dirs.shComprueba que el usuario indicado por PUID/PGID puede leer y escribir tanto
en ${CONFIG_ROOT} como en ${DATA_ROOT}.
Primero renderiza la configuración para detectar variables obligatorias faltantes:
docker compose configDespués inicia todos los servicios:
docker compose up -dComprueba el estado:
docker compose ps
docker compose logs -f --tail=100La primera emisión de certificados puede tardar. Traefik necesita resolver el
DNS challenge de Cloudflare y guardar el estado ACME en
traefik/config/certs/acme.json.
La infraestructura levanta los contenedores, pero la configuración interna de cada aplicación se completa desde sus respectivas interfaces:
- Configura credenciales administrativas.
- Configura Prowlarr y sus indexers.
- Conecta Prowlarr con Sonarr y Radarr.
- Configura qBittorrent como cliente de descarga.
- Define categorías y rutas de descarga bajo
/data/torrents. - Configura Sonarr y Radarr para importar desde
/datahacia las bibliotecas. - Conecta Bazarr con Sonarr/Radarr y configura proveedores de subtítulos.
- Verifica que las URLs públicas funcionan por HTTPS.
No expongas directamente los puertos internos de Sonarr, Radarr, Prowlarr, Bazarr o qBittorrent. El acceso debe pasar por Traefik y las redes previstas.
# Ver estado
docker compose ps
# Seguir logs de un servicio
docker compose logs -f --tail=100 sonarr
# Reiniciar un servicio
docker compose restart sonarr
# Actualizar después de revisar los cambios
docker compose pull
docker compose up -d
# Detener el stack sin borrar volúmenes ni configuración
docker compose downPara rutas, backups, troubleshooting, DNS local, hardlinks, Tailscale y
recomendaciones específicas del servidor, consulta
docs/OPERATIONS.md.
El script incluido crea un archivo comprimido con la configuración de Sonarr, Radarr, Prowlarr, Bazarr y qBittorrent:
set -a
. ./.env
set +a
BACKUP_DIR=./backups ./scripts/backup-config.shEl backup excluye logs, carátulas y datos de Sentry para reducir su tamaño. La
carpeta backups/ está ignorada por Git; almacénala además fuera del host si
necesitas protección ante pérdida del disco.
El estado de Traefik, incluyendo acme.json, se encuentra bajo
traefik/config/certs/ y también debe incluirse en la estrategia de backup si
quieres conservar los certificados y el estado ACME.
Renovate supervisa los Compose y propone actualizaciones de imágenes:
- Cambios
patch,minory de digest: agrupados, sin automerge. - Cambios
major: requieren aprobación explícita desde el Dependency Dashboard. - Las imágenes permanecen fijadas para evitar actualizaciones implícitas.
Antes de aplicar una actualización importante:
docker compose config
docker compose pull
docker compose up -d
docker compose psRevisa los logs y prueba el acceso HTTPS a cada servicio después del cambio.
Copia .env.example a .env, completa todos los valores obligatorios y vuelve
a ejecutar el comando. Compose no debe iniciarse con tokens inventados ni con
replace-me.
Comprueba que tailscale está levantado y que TS_EXTRA_ARGS apunta al exit
node esperado:
docker compose ps tailscale
docker compose logs --tail=100 tailscaleLos servicios ARR usan network_mode: service:tailscale deliberadamente. No
elimines esa relación si el requisito de salida por Tailscale sigue vigente.
Verifica:
- Que el DNS del hostname resuelve hacia el host correcto.
- Que los puertos 80 y 443 llegan al host.
- Que
CF_DNS_API_TOKENtiene permisos DNS suficientes. - Que
MEDIA_DOMAINcoincide con las labels de los Compose. - Que los servicios están conectados a la red
frontend. - Los logs de Traefik:
docker compose logs -f --tail=100 traefik.
Asegúrate de que las descargas y bibliotecas están bajo ${DATA_ROOT} y que
los contenedores ven el árbol completo en /data. Montajes separados para
/downloads y /movies pueden estar en filesystems distintos y romper los
hardlinks.
- Nunca commits
.env, auth keys de Tailscale, tokens de Cloudflare o passwords. - Usa
.env.examplecomo plantilla y mantén.envcon permisos restrictivos. - El socket de Docker se monta en Traefik como solo lectura, pero sigue siendo una superficie sensible: limita quién administra el host.
- No publiques el dashboard de Traefik sin autenticación y una política de acceso adecuada.
- Revisa los permisos de
${CONFIG_ROOT}y${DATA_ROOT}antes de dar acceso a otros usuarios.
Este repositorio contiene configuración de infraestructura. Las aplicaciones y las imágenes utilizadas pertenecen a sus respectivos proyectos y conservan sus propias licencias.