El Streaming Está Roto VI: La Pila Completa

Esta publicación fue originalmente escrita en inglés. La traducción puede no reflejar el 100% de las ideas originales del autor.

Ya basta de darle vueltas, ¿verdad?

Bromas aparte, considero los posts anteriores de esta serie extremadamente importantes. Cada uno cubre una pieza crítica:

  • Streaming is Broken II: Choosing Hardware. Donde aprendimos sobre una configuración de servidor doméstico de bajo costo con mis dos centavos sobre almacenamiento.
  • Streaming is Broken III: The Foundation (OS, Docker, and “Day One”). Donde configuramos nuestro SO, Docker y preparamos los cimientos para lo que vendría después.
  • Streaming is Broken IV: The Fortress: VPN and Gluetun. Un capítulo que normalmente no encontrarás en otros tutoriales, centrado en seguridad y privacidad.
  • Streaming is Broken V: Hardlinks and Permissions. Consejos para evitar futuros dolores de cabeza en nuestras configuraciones.

Pero si tuviera que elegir solo un post para explicar cómo configurar un servidor doméstico, sería este.

Sin más dilación, comencemos.

La Pila Multimedia

qBittorrent

Como dije en posts anteriores, la piratería es el peor crimen del mundo, amo a las empresas que ofrecen servicios pésimos y disfruto pagar más por menos. Por supuesto, por razones legales, digo esto.

Qbittorrent

Ahora, hablando en serio, el flujo de nuestro servidor multimedia doméstico será el siguiente:

  • Buscaremos películas y series en Overseerr (todo se explicará más adelante)
  • Overseerr enviará las peticiones a Radarr (Películas) y Sonarr (Series)
  • Radarr y Sonarr buscarán el material en sitios indexados por Prowlarr, cuya única función será gestionar estos indexadores
  • qBittorrent descargará el archivo. Radarr y Sonarr identificarán automáticamente el archivo y moverán la descarga a sus propias carpetas
  • Jellyfin será nuestra aplicación de streaming en la TV, iPad, computadora, etc. Es donde veremos el contenido adquirido

Con eso en mente, comencemos con el primer elemento a configurar en nuestra lista: el descargador.

En nuestro docker compose, tendremos algo así:

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - WEBUI_PORT=8080
    volumes:
      - /home/donkey/EmuleVision/Settings/Qbittorrent:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Aquí, como expliqué en mi post de seguridad, qBittorrent estará protegido a través de VPN, y Gluetun será quien proteja nuestro contenedor. En mi caso, conectado a un servicio de VPN de pago (tiene integraciones con NordVPN, Surfshark, etc.). Como estamos hablando de descargar archivos multimedia, olvídate de las VPN gratuitas: además de ser limitadas por razones obvias, son extremadamente inseguras.

Es importante dejar claro que para evitar fugas de IP, qBittorrent dependerá absolutamente de que Gluetun esté funcional. Si la VPN cae, qBittorrent se detendrá automáticamente. Esta es la belleza del depends_on con condition: service_healthy. El contenedor ni siquiera arrancará si Gluetun no está listo.

En este caso y de aquí en adelante, estaremos configurando permisos y zona horaria (PUID, PGID y TZ) de la misma manera. Para esto, crea un archivo .env para estos parámetros.

Ejemplo ficticio:

PUID=1000
PGID=1000
TZ=Etc/UTC

Para configurar la aplicación en sí, no voy a reinventar la rueda. Enlazaré el tutorial correspondiente de TRaSH Guides para cada tecnología:

  • Basic-Setup - Configuración básica de los ajustes más comunes.
  • Paths - Dónde establecer tu ubicación de descarga raíz.
  • How to add Categories - Cómo configurar categorías para qBittorrent, y cómo puedes gestionar y organizar tus torrents en grupos. Las aplicaciones Starr pueden usar categorías en qBittorrent para rastrear las descargas a monitorear, en lugar de vigilar cada torrent en tu cliente.
  • Port forwarding - Dónde en tu cliente de descargas debes agregar el puerto que has reenviado con tu servicio de VPN.

Prowlarr: El Gestor de Indexadores

Prowlarr es el héroe anónimo de esta pila. Es el intermediario que conecta tu Radarr y Sonarr con los indexadores de torrents. Piensa en él como una operadora de centralita de los años 50, excepto que en lugar de conectar llamadas telefónicas, está conectando tus peticiones de descarga a sitios de torrents.

  prowlarr:
    image: ghcr.io/hotio/prowlarr:latest
    container_name: prowlarr
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Prowlarr:/config
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Prowlarr

¿Notas el patrón aquí? También está detrás de Gluetun. Todo lo que toque la internet pública para “métodos de adquisición alternativos” se mantiene detrás de la VPN. Sin excepciones.

La configuración de Prowlarr es sencilla:

  1. Agrega tus indexadores (trackers públicos o privados)
  2. Conéctalo a Radarr y Sonarr mediante claves API
  3. Déjalo sincronizar automáticamente

La belleza es que configuras los indexadores una vez en Prowlarr, y se propagan a todas tus aplicaciones Arr. No más copiar y pegar URLs de trackers en cinco interfaces diferentes.

Para una configuración detallada, consulta TRaSH Guides - Prowlarr.

FlareSolverr: El Desbloqueador de Cloudflare

Algunos indexadores se protegen con las medidas anti-bot de Cloudflare. FlareSolverr es un navegador sin cabeza que resuelve estos desafíos automáticamente.

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    container_name: flaresolverr
    network_mode: "service:gluetun"
    environment:
      - TZ=${TZ}
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Lo configuras una vez en Prowlarr, y él se encarga del resto. Cuando Prowlarr accede a un sitio protegido por Cloudflare, FlareSolverr interviene, resuelve el desafío y devuelve los resultados. Es como tener un abogado robot especializado en pasar porteros. La guía está aquí

Sonarr: El Gestor de Series de TV

Sonarr es donde ocurre la magia para las series de televisión. Monitorea tu “lista de seguimiento”, busca nuevos episodios en Prowlarr, los envía a qBittorrent y organiza todo automáticamente.

  sonarr:
    image: ghcr.io/linuxserver/sonarr:latest
    container_name: sonarr
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Sonarr:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Sonarr

Puntos clave de configuración:

  • Carpetas Raíz: Establecer en /data/media/tv
  • Cliente de Descarga: Apuntar a qBittorrent en localhost:8080 (recuerda, comparten la misma pila de red a través de Gluetun)
  • Perfiles de Calidad: Usa Configuraciones de Calidad de TRaSH Guides para evitar descargar versiones de calidad basura

Sonarr automáticamente:

  • Buscará nuevos episodios cuando se emitan
  • Mejorará episodios existentes si aparecen versiones de mejor calidad
  • Renombrará archivos según tu esquema de nombres preferido
  • Moverá las descargas completadas a tu biblioteca de medios usando Hardlinks (¿recuerdas esa publicación?)

Radarr: El Gestor de Películas

Radarr es el hermano de Sonarr, pero para películas. La misma lógica, diferente tipo de contenido.

  radarr:
    image: ghcr.io/linuxserver/radarr:latest
    container_name: radarr
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Radarr:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Radarr

La configuración es un espejo de Sonarr:

  • Carpeta Raíz: /data/media/movies
  • Cliente de Descarga: qBittorrent en localhost:8080
  • Perfiles de Calidad: TRaSH Guides para Radarr

La diferencia es el tipo de contenido. Radarr rastrea películas individuales en lugar de series/temporadas/episodios. También se integra perfectamente con servicios como listas de Trakt o IMDb si quieres automatizar la adición de películas a tu colección.

Bazarr: El Especialista en Subtítulos

¿Recuerdas cuando me quejé de la pésima calidad de los subtítulos de Netflix en la primera publicación? Bazarr resuelve eso.

  bazarr:
    image: ghcr.io/linuxserver/bazarr:latest
    container_name: bazarr
    restart: unless-stopped
    network_mode: "service:gluetun"
    environment:
      - TZ=${TZ}
      - PUID=${PUID}
      - PGID=${PGID}
    volumes:
      - /home/donkey/EmuleVision/media/movies:/movies
      - /home/donkey/EmuleVision/media/tv:/tv
      - /home/donkey/EmuleVision/Settings/Bazarr:/config
    depends_on:
      gluetun:
        condition: service_healthy

Bazarr

Bazarr automáticamente:

  • Descarga subtítulos para tus películas y series
  • Soporta múltiples idiomas
  • Se sincroniza con OpenSubtitles, Subscene y otros proveedores
  • Incluso puede mejorar subtítulos existentes si aparecen versiones mejores

La configuración es simple: conéctalo a Sonarr y Radarr mediante claves API, selecciona tus idiomas y proveedores preferidos, y déjalo funcionar. Tu thriller polaco finalmente tendrá subtítulos en inglés comprensibles.

Kaizoku: El Descargador de Manga

Para aquellos que consumen más que solo películas y series, Kaizoku maneja la adquisición de manga.

  kaizoku:
    image: ghcr.io/oae/kaizoku:latest
    container_name: kaizoku
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - KAIZOKU_PORT=3002
    volumes:
      - /home/donkey/EmuleVision/Settings/Kaizoku:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

Rastrea series de manga, descarga automáticamente nuevos capítulos y los organiza para tu placer de lectura. Piensa en él como Sonarr, pero para cómics.

Overseerr: El Gestor de Solicitudes

Este es el componente orientado al usuario. Overseerr es con lo que interactúan los miembros de tu familia cuando quieren ver algo.

  overseerr:
    image: lscr.io/linuxserver/overseerr:latest
    container_name: overseerr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    ports:
      - "5055:5055"
    volumes:
      - /home/donkey/EmuleVision/Settings/Overseerr:/config
    restart: unless-stopped

Overserr

¿Notas algo diferente? Sin Gluetun. Overseerr no descarga nada. Es solo una interfaz de solicitudes. ¿Tu esposa quiere ver Gossip Girl? Ella abre Overseerr, lo busca, hace clic en “Solicitar”, y Sonarr se encarga del resto.

Plex: El Frontend de Streaming

Aquí es donde todo se une. Plex es tu servicio de streaming personal.

  plex:
    image: lscr.io/linuxserver/plex:latest
    container_name: plex
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - VERSION=docker
      - PLEX_CLAIM=claim-6DcZ6Chj7tSXYU4n6GS7
    network_mode: host
    volumes:
      - /home/donkey/EmuleVision/Settings/Plex:/config
      - /home/donkey/EmuleVision/media/movies:/data/movies
      - /home/donkey/EmuleVision/media/tv:/data/tvshows
    devices:
      - /dev/dri:/dev/dri
    restart: unless-stopped

Plex

Detalles críticos:

  1. network_mode: host - A diferencia de los otros contenedores, Plex necesita acceso directo a la red para el descubrimiento DLNA y el máximo rendimiento de streaming. ¿Recuerdas el diagrama de arquitectura del post sobre VPN? Este es el “Clean Group”.

  2. devices: /dev/dri - Esto expone el codificador de hardware Intel QuickSync al contenedor. Sin esto, la transcodificación asesinaría tu CPU. Con él, la GPU de tu N100 maneja la transcodificación 4K mientras la CPU echa una siesta.

  3. PLEX_CLAIM - Este token vincula tu servidor Plex a tu cuenta de Plex en el primer arranque. Lo obtienes de plex.tv/claim. Caduca después de 4 minutos, así que genéralo justo antes de tu primer docker compose up.

  4. Sin dependencia de Gluetun - Plex transmite localmente. Pasar video 4K de 80Mbps a través de un túnel VPN es una locura. Este tráfico se queda en tu LAN, rápido y limpio.

Configuración esencial:

  • Habilita la Aceleración por Hardware (Intel QuickSync) en Configuración → Transcoder
  • Configura tus bibliotecas (Movies apuntando a /data/movies, TV Shows apuntando a /data/tvshows)
  • Configura el acceso remoto (Plex lo maneja automáticamente, pero puedes deshabilitarlo para solo LAN)
  • Instala la app de Plex en tu TV, teléfono, tableta

La belleza de Plex sobre las alternativas de código abierto es el acabado. Las apps son nativas, rápidas y funcionan a la perfección en todos los dispositivos imaginables. Tu esposa no necesitará un tutorial para ver Gossip Girl en su iPad.

Para una configuración detallada, consulta la documentación oficial de Plex.

La Pila de Soporte

Portainer: El Panel de Control de Docker

Gestionar contenedores mediante CLI está bien cuando estás configurando las cosas. Pero cuando algo se rompe a las 2 AM y necesitas reiniciar un servicio rápidamente, una interfaz web es invaluable.

  portainer:
    image: portainer/portainer-ce:2.20.2
    container_name: portainer
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock
      - /home/donkey/EmuleVision/Settings/Portainer:/data
    ports:
      - "9000:9000"
    restart: unless-stopped

Portainer te ofrece:

  • Estado de los contenedores de un vistazo
  • Reiniciar/detener/eliminar con un clic
  • Visualización de logs sin necesidad de SSH
  • Monitoreo del uso de recursos

Accede a él en http://tu-ip-del-servidor:9000.

Homepage: El Panel de Control Unificado

Homepage es tu centro de mando. Agrega todos tus servicios en una única interfaz hermosa.

  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    volumes:
      - /home/donkey/EmuleVision/Settings/Homepage:/app/config
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - HOMEPAGE_ALLOWED_HOSTS=*
    ports:
      - "3000:3000"
    restart: unless-stopped

Homepage

Lo configuras con archivos YAML para mostrar:

  • Estado de los servicios
  • Enlaces rápidos
  • Integraciones de API (cola de descargas de Sonarr, adiciones recientes de Jellyfin)
  • Estadísticas del sistema

Esto se convierte en tu página de inicio marcada. No más memorizar qué servicio está en qué puerto.

Scrutiny: El Monitor de Salud de las Unidades

¿Recuerdas ese SSD de 512GB del que dependemos? Necesitamos monitorear su salud.

  scrutiny:
    image: ghcr.io/analogj/scrutiny:master-omnibus
    container_name: scrutiny
    cap_add:
      - SYS_RAWIO
    devices:
      - /dev/sda:/dev/sda
    volumes:
      - /run/udev:/run/udev:ro
      - /home/donkey/EmuleVision/Settings/Scrutiny:/opt/scrutiny/config
      - /home/donkey/EmuleVision/Settings/Scrutiny/influxdb:/opt/scrutiny/influxdb
    ports:
      - "8086:8080"
    restart: unless-stopped

Scrutiny

Scrutiny lee los datos S.M.A.R.T. de tu unidad y te alerta si detecta degradación. Los SSD no fallan gradualmente; fallan repentinamente. Esto te da una advertencia antes de una pérdida de datos catastrófica.

FileBrowser: El Administrador de Archivos Web

A veces necesitas acceder a archivos directamente sin usar SSH o montar un recurso compartido Samba.

  filebrowser:
    image: filebrowser/filebrowser:latest
    container_name: filebrowser
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
    volumes:
      - /home/donkey/EmuleVision/Settings/Filebrowser/filebrowser.db:/database.db
      - /home/donkey/EmuleVision/Settings/Filebrowser/.filebrowser.json:/.filebrowser.json
      - /home/donkey/EmuleVision:/srv
    ports:
      - "8082:80"
    restart: unless-stopped

FileBrowser proporciona:

  • Gestión de archivos basada en web
  • Capacidades de subida/descarga
  • Controles de permisos de usuario
  • Enlaces para compartir archivos

Útil para esas raras ocasiones en las que necesitas agregar un archivo manualmente o verificar algo sin acceso a la terminal.

Kavita y Calibre-Web: La Pila de Lectura

Para los entusiastas de los libros:

  kavita:
    image: jvmilazz0/kavita:latest
    container_name: kavita
    environment:
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Kavita:/kavita/config
      - /home/donkey/EmuleVision/media/manga:/manga
      - /home/donkey/EmuleVision/media/comics:/comics
    ports:
      - "5000:5000"
    restart: unless-stopped

  calibre-web:
    image: lscr.io/linuxserver/calibre-web:latest
    container_name: calibre-web
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/CalibreWeb:/config
      - /home/donkey/EmuleVision/books:/books
    ports:
      - "8083:8083"
    restart: unless-stopped
  • Kavita: Para manga y cómics (archivos CBZ/CBR)
  • Calibre-Web: Para libros electrónicos (EPUB, MOBI, PDF)

Calibre

Ambos ofrecen interfaces de lectura basadas en web con seguimiento del progreso, gestión de metadatos y soporte para aplicaciones móviles.

El Docker Compose Completo

Así es como todo encaja. Observa la segregación de red entre el grupo VPN (Gluetun + clientes de descarga) y el grupo limpio (Jellyfin, Overseerr, etc.):

version: '3'

services:
  gluetun:
    image: qmcgaw/gluetun
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      - "8080:8080" # Qbittorrent
      - "9696:9696" # Prowlarr
      - "8191:8191" # Flaresolverr
      - "8989:8989" # Sonarr
      - "7878:7878" # Radarr
      - "3002:3002" # Kaizoku
      - "6881:6881" # Puerto Torrent
      - "6881:6881/udp"
      - "6767:6767" # Bazarr
      - "8090:8090"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - VPN_SERVICE_PROVIDER=custom
      - VPN_TYPE=openvpn
      - OPENVPN_USER=${VPN_USER}
      - OPENVPN_PASSWORD=${VPN_PASS}
      - OPENVPN_CUSTOM_CONFIG=/gluetun/custom.conf
      - FIREWALL_VPN_INPUT_PORTS=6881
      - BLOCK_MALICIOUS=no
      - BLOCK_ADS=no
      - BLOCK_SURVEILLANCE=no
      - FIREWALL_INPUT_PORTS=8080,9696,8191,8989,7878,3002,6767,8090
    volumes:
      - ./Settings/Gluetun:/gluetun
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "ping -c 1 1.1.1.1 || ping -c 1 8.8.8.8 || ping -c 1 9.9.9.9 || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 20s

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - WEBUI_PORT=8080
    volumes:
      - /home/donkey/EmuleVision/Settings/Qbittorrent:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  prowlarr:
    image: ghcr.io/hotio/prowlarr:latest
    container_name: prowlarr
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Prowlarr:/config
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
    container_name: flaresolverr
    network_mode: "service:gluetun"
    environment:
      - TZ=${TZ}
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  sonarr:
    image: ghcr.io/linuxserver/sonarr:latest
    container_name: sonarr
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Sonarr:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  radarr:
    image: ghcr.io/linuxserver/radarr:latest
    container_name: radarr
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Radarr:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  bazarr:
    image: ghcr.io/linuxserver/bazarr:latest
    container_name: bazarr
    restart: unless-stopped
    network_mode: "service:gluetun"
    environment:
      - TZ=${TZ}
      - PUID=${PUID}
      - PGID=${PGID}
    volumes:
      - /home/donkey/EmuleVision/media/movies:/movies
      - /home/donkey/EmuleVision/media/tv:/tv
      - /home/donkey/EmuleVision/Settings/Bazarr:/config
    depends_on:
      gluetun:
        condition: service_healthy

  kaizoku:
    image: ghcr.io/oae/kaizoku:latest
    container_name: kaizoku
    network_mode: "service:gluetun"
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - KAIZOKU_PORT=3002
    volumes:
      - /home/donkey/EmuleVision/Settings/Kaizoku:/config
      - /home/donkey/EmuleVision:/data
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  overseerr:
    image: lscr.io/linuxserver/overseerr:latest
    container_name: overseerr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    ports:
      - "5055:5055"
    volumes:
      - /home/donkey/EmuleVision/Settings/Overseerr:/config
    restart: unless-stopped

  adguardhome:
    image: adguard/adguardhome
    container_name: adguardhome
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "3001:3000"
    volumes:
      - /home/donkey/EmuleVision/Settings/AdGuard/work:/opt/adguardhome/work
      - /home/donkey/EmuleVision/Settings/AdGuard/conf:/opt/adguardhome/conf
    restart: unless-stopped

  calibre-web:
    image: lscr.io/linuxserver/calibre-web:latest
    container_name: calibre-web
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/CalibreWeb:/config
      - /home/donkey/EmuleVision/books:/books
    ports:
      - "8083:8083"
    restart: unless-stopped

  kavita:
    image: jvmilazz0/kavita:latest
    container_name: kavita
    environment:
      - TZ=${TZ}
    volumes:
      - /home/donkey/EmuleVision/Settings/Kavita:/kavita/config
      - /home/donkey/EmuleVision/media/manga:/manga
      - /home/donkey/EmuleVision/media/comics:/comics
    ports:
      - "5000:5000"
    restart: unless-stopped

  filebrowser:
    image: filebrowser/filebrowser:latest
    container_name: filebrowser
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
    volumes:
      - /home/donkey/EmuleVision/Settings/Filebrowser/filebrowser.db:/database.db
      - /home/donkey/EmuleVision/Settings/Filebrowser/.filebrowser.json:/.filebrowser.json
      - /home/donkey/EmuleVision:/srv
    ports:
      - "8082:80"
    restart: unless-stopped

  portainer:
    image: portainer/portainer-ce:2.20.2
    container_name: portainer
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock
      - /home/donkey/EmuleVision/Settings/Portainer:/data
    ports:
      - "9000:9000"
    restart: unless-stopped

  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    volumes:
      - /home/donkey/EmuleVision/Settings/Homepage:/app/config
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - HOMEPAGE_ALLOWED_HOSTS=*
    ports:
      - "3000:3000"
    restart: unless-stopped

  scrutiny:
    image: ghcr.io/analogj/scrutiny:master-omnibus
    container_name: scrutiny
    cap_add:
      - SYS_RAWIO
    devices:
      - /dev/sda:/dev/sda
    volumes:
      - /run/udev:/run/udev:ro
      - /home/donkey/EmuleVision/Settings/Scrutiny:/opt/scrutiny/config
      - /home/donkey/EmuleVision/Settings/Scrutiny/influxdb:/opt/scrutiny/influxdb
    ports:
      - "8086:8080"
    restart: unless-stopped

  plex:
    image: lscr.io/linuxserver/plex:latest
    container_name: plex
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - VERSION=docker
      - PLEX_CLAIM=
    network_mode: host
    volumes:
      - /home/donkey/EmuleVision/Settings/Plex:/config
      - /home/donkey/EmuleVision/media/movies:/data/movies
      - /home/donkey/EmuleVision/media/tv:/data/tvshows
    devices:
      - /dev/dri:/dev/dri

Lista de Verificación del Primer Arranque

Después de ejecutar docker compose up -d, aquí está tu secuencia de inicio:

  1. Espera a Gluetun - Revisa los registros: docker logs gluetun

    • Busca “VPN connection successful”
    • Verifica la IP: docker exec gluetun curl ifconfig.me
  2. Configura Prowlarr (puerto 9696)

    • Añade indexadores
    • Conéctalo a Sonarr/Radarr mediante las claves API
    • Prueba FlareSolverr si usas indexadores protegidos
  3. Configura qBittorrent (puerto 8080)

    • Cambia la contraseña por defecto
    • Establece la ruta de descarga: /data/downloads/torrents
    • Añade categorías: tv, movies
    • Sigue las Guías TRaSH
  4. Configura Sonarr (puerto 8989)

    • Añade Prowlarr como indexador
    • Añade qBittorrent como cliente de descarga (localhost:8080)
    • Establece la carpeta raíz: /data/media/tv
    • Importa perfiles de calidad de las Guías TRaSH
  5. Configura Radarr (puerto 7878)

    • Igual que Sonarr, pero con carpeta raíz: /data/media/movies
  6. Configura Bazarr (puerto 6767)

    • Conéctalo a Sonarr/Radarr
    • Añade proveedores de subtítulos (OpenSubtitles, Subscene)
    • Establece los idiomas preferidos
  7. Configura Jellyfin (puerto 8096)

    • Añade bibliotecas: Películas (/data/movies), Series de TV (/data/tvshows)
    • Habilita la Aceleración por Hardware (Intel QuickSync)
    • Crea cuentas de usuario
  8. Configura Overseerr (puerto 5055)

    • Conéctalo a Jellyfin
    • Conéctalo a Sonarr/Radarr
    • Habilita las peticiones de los usuarios

Consejos de Optimización del Rendimiento

Gestión del Almacenamiento

Dado que trabajamos con un SSD de 512GB, la gestión del espacio es crítica:

  1. Habilita la eliminación automática en Sonarr/Radarr después de X días
  2. Establece límites de calidad - No descargues remux de 80GB a menos que realmente los necesites
  3. Monitoriza el uso del disco mediante Homepage o Scrutiny
  4. Limpieza regular - Elimina contenido visto que no vayas a volver a ver

Optimización de Red

  1. Reenvío de puertos - Reenvía el puerto 6881 en tu VPN para maximizar las velocidades de descarga
  2. WiFi de 5GHz para la TV Box - Como se comentó en la publicación sobre hardware, WiFi AC > Ethernet de 100Mbps para streaming 4K
  3. Direct Play en lugar de Transcodificación - Configura los clientes de Jellyfin para que admitan tus formatos de archivo de forma nativa

Fortalecimiento de la Seguridad

  1. Cambia todas las contraseñas por defecto
  2. Deshabilita el acceso remoto a menos que sea absolutamente necesario
  3. Mantén las credenciales de VPN de Gluetun en .env - Nunca las codifiques directamente
  4. Actualizaciones regulares - Ejecuta docker compose pull && docker compose up -d mensualmente

Solución de Problemas Comunes

“qBittorrent no arranca”

  • Revisa los registros de Gluetun: docker logs gluetun
  • Verifica las credenciales de VPN en .env
  • Asegúrate de que el healthcheck pasa: docker inspect gluetun | grep Health

“Sonarr/Radarr no puede alcanzar qBittorrent”

  • Comparten la red de Gluetun, usa localhost:8080
  • No uses nombres de contenedores o IPs
  • Revisa las reglas del firewall en la configuración de Gluetun

“La transcodificación de Jellyfin es lenta”

  • Verifica que la aceleración por hardware esté habilitada
  • Comprueba que /dev/dri esté montado correctamente
  • Instala intel-media-va-driver-non-free en el host

“Los subtítulos no se descargan”

  • Revisa los registros de Bazarr para ver problemas con los proveedores
  • Verifica que las claves API sean correctas
  • Algunos proveedores limitan la tasa; espera y reintenta
  • Todos los contenedores deben mapear el mismo volumen raíz (/data)
  • Las descargas y el contenido multimedia deben estar en el mismo sistema de archivos
  • Comprueba la propiedad de los archivos (PUID/PGID)

¿Qué Viene Después?

Ahora tenemos un servidor doméstico completamente funcional que rivaliza con cualquier servicio de streaming. Pero esto es solo la base. En futuras publicaciones, cubriré:

  • Automatización Avanzada: Scripts personalizados para eliminación, notificaciones y mantenimiento
  • Acceso Remoto: Exponer tu servidor de forma segura mediante Tailscale o Cloudflare Tunnels
  • Optimización 4K: Mapeo de tonos HDR, perfiles de calidad específicos y gestión del ancho de banda
  • Estrategias de Copia de Seguridad: Protegiendo tu configuración y contenido multimedia
  • Gestión Multi-Usuario: Bibliotecas separadas, restricciones de visualización y cuotas de ancho de banda
  • Integración con Trakt/IMDb: Sincronización automática de listas de seguimiento
  • Personalización Avanzada de Jellyfin: Plugins, temas y configuraciones específicas del cliente

La belleza de este sistema es que es modular. Puedes añadir o eliminar servicios según sea necesario. ¿No te importa el manga? Elimina Kaizoku. ¿Quieres añadir gestión de música? Añade Lidarr. La arquitectura escala con tus necesidades.

Has transformado un mini PC barato en una infraestructura de nivel empresarial. Has tomado el control de tu consumo de contenido multimedia, alejándolo de las corporaciones que te cobran más por menos. Y has aprendido los fundamentos de la contenerización, las redes y la arquitectura de sistemas en el camino.

¡Victoria!

El servidor está construido. La pila está completa. Ahora ve y adquiere (legalmente, por supuesto) el contenido que realmente quieres ver.

Nos vemos en la próxima publicación.