Problema
Los entusiastas de los servidores domésticos suelen combinar Plex con servicios de arr (Sonarr, Radarr, etc.) y clientes de Usenet o torrents. En la práctica, aparecen dos grupos de fallos recurrentes:
- Plex se cae cada vez que se reinicia Docker – los contenedores que gestionan descargas y organización se ejecutan en la misma máquina que Plex, de modo que cualquier reinicio de Docker desmonta los volúmenes y rompe la biblioteca.
- Los hard links no funcionan – cuando las descargas se guardan en un filesystem distinto al de la biblioteca, Sonarr/Radarr copian los archivos en vez de enlazarlos, duplicando temporalmente el uso de disco y saturando el pool ZFS.
- Inconsistencias de rutas y permisos – los servicios dentro de Docker esperan rutas absolutas diferentes a las que ve el host, lo que provoca que los archivos no se muevan o que los procesos fallen al iniciar.
El patrón subyacente es una arquitectura monolítica donde Plex, los arr y el cliente de Usenet comparten el mismo entorno de contenedores o VM sin una separación clara del almacenamiento. El resultado es inestabilidad, pérdida de rendimiento y una gestión de permisos engorrosa.
Causa
1. Falta de aislamiento de servicios críticos
Ejecutar Plex dentro de Docker o en la misma VM que los arr hace que cualquier operación de Docker (reinicio, actualización, despliegue) afecte a Plex. Además, la asignación de GPU para transcodificación suele requerir passthrough a nivel de hipervisor; mezclar esto con Docker genera conflictos de dispositivos.
2. Almacenamiento fragmentado
ZFS permite crear datasets con propiedades independientes (compress, dedup, quota). Cuando los downloads se guardan en un dataset distinto al de la biblioteca, el kernel no puede crear hard links entre sistemas de archivos diferentes. Sonarr y Radarr, al no encontrar la capacidad de enlazar, recurren a copiar.
3. Mapeo de rutas inconsistente
Los contenedores Docker usan su propio namespace de filesystem. Si el host monta /mnt/media/tv en /media/tv dentro del contenedor, pero Plex (en LXC) ve /mnt/media/tv, los servicios no comparten la misma ruta y los scripts de movimiento fallan.
4. Permisos predeterminados
Muchas imágenes Docker usan variables PUID/PGID para mapear al usuario del host. Si los directorios de configuración se crean como root antes de lanzar el contenedor, el cambio de UID/GID no tiene efecto y los procesos no pueden escribir.
Solución
Separar Plex y los arr en dos entornos aislados pero con acceso al mismo pool ZFS mediante NFS. La arquitectura recomendada es:
- LXC para Plex – un contenedor ligero que monta directamente los datasets ZFS (
/mnt/media/*). El LXC tiene acceso directo a la GPU mediante passthrough de Proxmox. - VM con Docker – una máquina virtual (por ejemplo Ubuntu 22.04) que ejecuta Docker Compose con Sonarr, Radarr, SABnzbd, Prowlarr y Seerr. La VM monta los mismos datasets a través de NFS, garantizando que los paths sean idénticos dentro de los contenedores.
- ZFS layout – tres datasets en un pool espejo:
tank/media/moviestank/media/tvtank/downloadsMantenerdownloadsdentro del mismo pool evita la copia innecesaria y permite hard links.
- Exportar NFS desde el host Proxmox y montar en la VM con la opción
no_root_squashpara que los UID/GID coincidan. - Crear directorios de configuración con el UID/GID que usarán los contenedores (
1000:1000típico) antes de lanzar Docker Compose.
Paso a paso resumido
-
Crear pool y datasets en Proxmox:
zpool create -f -o ashift=12 tank mirror /dev/sda /dev/sdb zfs create -o compression=lz4 tank/media zfs create -o compression=lz4 tank/downloads zfs create -o mountpoint=/mnt/media/movies tank/media/movies zfs create -o mountpoint=/mnt/media/tv tank/media/tv -
Configurar export NFS en
/etc/exportsdel host:/mnt/media 192.168.1.0/24(rw,no_root_squash,sync,no_subtree_check) /mnt/downloads 192.168.1.0/24(rw,no_root_squash,sync,no_subtree_check)Ejecutar
exportfs -ra. -
Crear LXC para Plex:
- Plantilla
ubuntu. - Añadir bind mounts en la configuración del contenedor:
mp0: /mnt/media/movies,mp=/media/movies mp0: /mnt/media/tv,mp=/media/tv - Passthrough de GPU:
lxc.cgroup2.devices.allow: c 195:* rwm lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create=file
- Plantilla
-
Crear VM para Docker (2‑4 vCPU, 8 GB RAM, 100 GB disk):
- Instalar Docker y Docker‑Compose.
- Montar NFS en
/mediay/downloads:mkdir -p /media/movies /media/tv /downloads mount -t nfs4 host-proxmox:/mnt/media /media mount -t nfs4 host-proxmox:/mnt/downloads /downloads - Añadir entradas a
/etc/fstabpara persistir.
-
Docker‑Compose (solo los servicios críticos):
version: "3.8" services: sabnzbd: image: linuxserver/sabnzbd container_name: sabnzbd environment: - PUID=1000 - PGID=1000 volumes: - /downloads:/downloads - /config/sabnzbd:/config restart: unless-stopped sonarr: image: linuxserver/sonarr container_name: sonarr environment: - PUID=1000 - PGID=1000 volumes: - /downloads:/downloads - /media/tv:/tv - /config/sonarr:/config restart: unless-stopped radarr: image: linuxserver/radarr container_name: radarr environment: - PUID=1000 - PGID=1000 volumes: - /downloads:/downloads - /media/movies:/movies - /config/radarr:/config restart: unless-stopped prowlarr: image: linuxserver/prowlarr container_name: prowlarr environment: - PUID=1000 - PGID=1000 volumes: - /config/prowlarr:/config restart: unless-stopped seerr: image: ghcr.io/hotio/seerr container_name: seerr environment: - PUID=1000 - PGID=1000 volumes: - /config/seerr:/config restart: unless-stopped -
Ajustar permisos antes de
docker compose up:sudo mkdir -p /config/{sabnzbd,sonarr,radarr,prowlarr,seerr} sudo chown -R 1000:1000 /config sudo chown -R 1000:1000 /downloads /media
Con esta separación, Plex nunca se ve afectado por reinicios de Docker y los arr pueden crear hard links directamente en los datasets ZFS.
Cuándo aplicar esta solución
- Entorno doméstico o de pequeña oficina con un único nodo Proxmox y necesidad de alta disponibilidad de Plex.
- Uso intensivo de descargas (Usenet o torrents) donde el espacio temporal de los archivos es comparable al tamaño de la biblioteca.
- Requerimientos de transcodificación por hardware que obligan a pasar la GPU al hipervisor.
- Necesidad de aislar servicios por motivos de seguridad o para simplificar actualizaciones (Docker vs LXC).
No es necesario si:
- Solo se usa Plex sin automatización de descargas.
- Todas las aplicaciones ya corren dentro de Docker y la pérdida de Plex durante reinicios es aceptable.
- No se dispone de ZFS o de una GPU dedicada.
Código
# 1. Crear pool y datasets ZFS
zpool create -f -o ashift=12 tank mirror /dev/sda /dev/sdb
zfs create -o compression=lz4 tank/media
zfs create -o compression=lz4 tank/downloads
zfs create -o mountpoint=/mnt/media/movies tank/media/movies
zfs create -o mountpoint=/mnt/media/tv tank/media/tv
# 2. Configurar export NFS
cat <<EOF >> /etc/exports
/mnt/media 192.168.1.0/24(rw,no_root_squash,sync,no_subtree_check)
/mnt/downloads 192.168.1.0/24(rw,no_root_squash,sync,no_subtree_check)
EOF
exportfs -ra
# 3. Preparar directorios de configuración y permisos
mkdir -p /config/{sabnzbd,sonarr,radarr,prowlarr,seerr}
chown -R 1000:1000 /config /downloads /media
# 4. Iniciar Docker Compose
cd /path/to/compose
docker compose up -d
Verificación
-
Hard links – después de que Sonarr o Radarr muevan un archivo, verifica que el inode sea el mismo:
ls -i /downloads/example.mkv ls -i /media/tv/Show/Season\ 01/example.mkvLos números de inode deben coincidir.
-
Plex siempre disponible – reinicia Docker en la VM:
docker compose restartAccede a Plex en el LXC y confirma que la interfaz responde y la biblioteca sigue intacta.
-
GPU passthrough – en el LXC, ejecuta
lspci | grep -i nvidia(o AMD) y verifica que Plex muestra la GPU en sus logs de transcodificación.
Notas adicionales
- Sincronización de tiempo: asegúrate de que el host Proxmox y la VM tengan NTP activo; diferencias de hora provocan fallos de certificados en SABnzbd.
- Snapshots ZFS: crea snapshots de
tank/mediaantes de grandes actualizaciones de Plex; permite volver atrás sin perder datos. - Limitar NFS version: