SSD Nodes Learn 8GB de RAM — $66/año
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-02

Docker Compose para Prowlarr, Sonarr, Radarr y qBittorrent

Configura Prowlarr, Sonarr, Radarr y qBittorrent en un VPS con un solo archivo Docker Compose, PUID, PGID y volúmenes compartidos para mantener hardlinks.

Qué va a crear

Una pila arr de Docker Compose consta de cuatro contenedores que gestionan una biblioteca multimedia: Prowlarr para la configuración de indexadores, Sonarr para series, Radarr para películas y qBittorrent como cliente de descargas. Se comunican entre sí mediante la red de Compose usando el nombre del servicio y comparten un único árbol de carpetas en el host. La instalación es breve. Lo que determina si la pila funcionará durante años o le causará problemas cada semana es la disposición de los volúmenes, por lo que la mayor parte de esta guía trata sobre ella.

La pila no busca contenido por usted. Prowlarr contiene los indexadores que añada, y usted decide qué indexadores usar y asume la responsabilidad legal correspondiente. Esta guía cubre la configuración necesaria: usuarios, rutas, permisos, redes de contenedores y comprobaciones que demuestran que funciona.

Si nunca ha escrito un archivo de Compose, lea primero los conceptos básicos de Docker Compose para un VPS. Esta publicación supone que docker compose version ya muestra algo en su servidor.

Cuando Sonarr termina una descarga, importa el archivo a la biblioteca. Si la carpeta de descargas y la carpeta de la biblioteca están en el mismo sistema de archivos, la importación usa un hardlink: un segundo nombre que apunta a los mismos datos del disco. No ocupa espacio adicional ni requiere tiempo adicional. El torrent sigue compartiendo desde el nombre anterior mientras el servidor multimedia lee el nuevo.

Si las dos carpetas están en sistemas de archivos diferentes, el kernel no puede crear ese enlace. Sonarr recurre a una copia. Una temporada de 40 GB ahora ocupa 80 GB de disco y requiere varios minutos de entrada y salida. Además, el registro de importación indica que el hardlink falló y que el archivo se copió en su lugar. En un VPS con una cuota de disco fija, así es como se agota el espacio en una semana.

Esta es la trampa. Dentro de un contenedor, un bind mount es un límite del sistema de archivos. Monte /mnt/data/torrents como /downloads y /mnt/data/media como /tv. Aunque ambos estén en un solo disco del host, Sonarr ve dos montajes independientes y no permite crear enlaces entre ellos. La documentación oficial de la imagen de LinuxServer.io lo indica directamente: usar las rutas independientes /downloads y /tv impide crear hardlinks.

La solución es usar un solo montaje. Cada contenedor que accede a los archivos multimedia obtiene el mismo volumen único, /mnt/data:/data, y cada ruta que utiliza es una carpeta dentro de ese volumen. Un punto de montaje, un sistema de archivos y hardlinks funcionales.

Cree el usuario, el grupo y las carpetas

Los contenedores escriben los archivos con un ID de usuario numérico, definido por PUID y PGID. Use su propia cuenta para poder leer y editar esos archivos mediante SSH sin sudo.

id -u
id -g

Ambos suelen mostrar 1000 en una VPS de Ubuntu recién creada. Ahora cree el árbol de directorios. Colóquelo en el disco que contiene los archivos multimedia y mantenga todo el árbol en ese mismo disco.

sudo mkdir -p /mnt/data/torrents/movies /mnt/data/torrents/tv
sudo mkdir -p /mnt/data/media/Movies /mnt/data/media/Shows
sudo chown -R 1000:1000 /mnt/data
sudo chmod -R 775 /mnt/data

Compruebe que realmente se trata de un solo sistema de archivos antes de continuar:

df --output=source,target /mnt/data/torrents /mnt/data/media

Ambas líneas deben mostrar el mismo dispositivo de origen. Si muestran dos dispositivos distintos, los enlaces físicos nunca funcionarán, independientemente de lo que configure en el contenedor.

Las carpetas de la biblioteca se llaman Movies y Shows a propósito. Si ya ejecuta Jellyfin como servidor multimedia, monte /mnt/data/media en Jellyfin como /media; sus bibliotecas quedarán en /media/Movies y /media/Shows, exactamente donde las coloca esa guía.

El archivo de entorno

Mantén en .env los valores que cambian según el servidor, junto al archivo de Compose.

mkdir -p ~/arr && cd ~/arr

Escribe ~/arr/.env:

PUID=1000
PGID=1000
TZ=Etc/UTC
DATA_ROOT=/mnt/data

Establece TZ con tu propia zona, como Europe/Berlin. Las aplicaciones arr programan tareas y registran las líneas de log en esa zona, por lo que un valor incorrecto hará que todos los logs sean confusos más adelante.

El archivo de Compose

Escriba ~/arr/docker-compose.yml:

services:
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ./config/prowlarr:/config
    ports:
      - 127.0.0.1:9696:9696
    restart: unless-stopped

  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ./config/sonarr:/config
      - ${DATA_ROOT}:/data
    ports:
      - 127.0.0.1:8989:8989
    restart: unless-stopped

  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ./config/radarr:/config
      - ${DATA_ROOT}:/data
    ports:
      - 127.0.0.1:7878:7878
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - WEBUI_PORT=8080
      - TORRENTING_PORT=6881
    volumes:
      - ./config/qbittorrent:/config
      - ${DATA_ROOT}:/data
    ports:
      - 127.0.0.1:8080:8080
      - 6881:6881
      - 6881:6881/udp
    stop_grace_period: "10s"
    restart: unless-stopped

Cuatro elementos de ese archivo realizan funciones importantes.

${DATA_ROOT}:/data es idéntico en los tres contenedores que acceden a archivos multimedia. Prowlarr no lo necesita porque nunca abre un archivo multimedia.

Todos los puertos web están vinculados a 127.0.0.1, por lo que Docker los publica únicamente en la dirección de loopback. Un 8989:8989 sin más los publicaría en todas las interfaces, y las propias reglas del firewall de Docker dirigirían ese tráfico directamente más allá de una regla deny de ufw. Este comportamiento confunde constantemente a los usuarios y se explica en por qué Docker publica los puertos directamente a través de ufw.

El puerto 6881 se publica en todas las interfaces de forma intencionada. Es el puerto de escucha de torrent y debe ser accesible para las conexiones entrantes de los pares. Permítalo con sudo ufw allow 6881 y consulte los fundamentos del firewall ufw para un VPS si no conoce ese comando.

Los directorios de configuración están separados por aplicación y solo se comparte el volumen multimedia. Créelos antes del primer inicio para que pertenezcan a su usuario y no a root:

mkdir -p ~/arr/config/prowlarr ~/arr/config/sonarr ~/arr/config/radarr ~/arr/config/qbittorrent
docker compose up -d
docker compose ps

Los cuatro servicios deben leer running. En julio de 2026, estas imágenes se publican en lscr.io y la etiqueta latest sigue la versión estable actual. Por tanto, use una etiqueta de versión específica si quiere que las actualizaciones sean una decisión y no una sorpresa.

Acceder de forma segura a las interfaces web

Como los puertos están en loopback, todavía no hay nada expuesto. Reenvíalos mediante SSH desde tu propio equipo:

ssh -L 9696:127.0.0.1:9696 -L 8989:127.0.0.1:8989 \
    -L 7878:127.0.0.1:7878 -L 8080:127.0.0.1:8080 you@your-server

Ahora http://127.0.0.1:8989 en tu navegador accede a Sonarr en el servidor. Para obtener acceso permanente, coloca la pila detrás de Traefik con certificados TLS para varias aplicaciones, o accede al servidor mediante una VPN WireGuard que alojes tú mismo. Ninguna de estas aplicaciones debe estar en Internet pública con solo su propia página de inicio de sesión como protección.

qBittorrent genera una contraseña de administrador aleatoria durante el primer inicio y la muestra en el registro del contenedor. Léela y cámbiala en la interfaz web:

docker compose logs qbittorrent | grep -i password

Si omites este cambio, se genera una nueva contraseña aleatoria en cada reinicio y tendrás que volver a consultar los registros cada vez.

Establecer las rutas dentro de cada aplicación

En qBittorrent, abra Options y después Downloads. Establezca la ruta de guardado predeterminada en /data/torrents. Mantenga la carpeta de descargas incompletas dentro del mismo árbol, por ejemplo, /data/torrents/incomplete. Una descarga que termine fuera de /data no se puede enlazar mediante hardlink en la biblioteca.

En Sonarr, abra Settings y después Media Management. Añada la carpeta raíz /data/media/Shows. En Radarr, la carpeta raíz es /data/media/Movies. Estas son rutas dentro del contenedor. La ruta del host /mnt/data/media/Shows se rechaza porque ese directorio no existe desde el punto de vista del contenedor.

En Sonarr y Radarr, abra Settings y después Download Clients. Añada qBittorrent. El host es qbittorrent y el puerto es 8080. El nombre del servicio funciona como nombre de host porque Compose coloca los cuatro contenedores en una misma red con un servicio DNS (domain name system) interno. No use localhost aquí: dentro del contenedor de Sonarr, localhost es Sonarr.

Deje Remote Path Mappings vacío. Esta función traduce una ruta que el cliente de descargas comunica a una ruta que la aplicación arr puede ver. Con un único montaje compartido /data, ambos contenedores ya usan las mismas rutas. Esta es la segunda razón por la que vale la pena usar este diseño.

Conectar Prowlarr con Sonarr y Radarr

Prowlarr inserta las definiciones de los indexadores en las otras aplicaciones. Así, configura un indexador una sola vez en lugar de dos. Necesita una clave de API (interfaz de programación de aplicaciones) de cada aplicación.

En Sonarr, abra Settings y, después, General. Copie la clave de API. En Prowlarr, abra Settings y, después, Apps. Añada una aplicación Sonarr y complete tres campos. Prowlarr Server es http://prowlarr:9696. Sonarr Server es http://sonarr:8989. API Key es el valor que copió. Pulse Test. Un resultado en verde indica que Prowlarr llegó a Sonarr a través de la red de Compose. Repita el proceso con Radarr en http://radarr:7878.

Un resultado en rojo que indique que se rechazó la conexión casi siempre significa que el nombre del servicio es incorrecto o que falta el prefijo http://. Confirme que el nombre se resuelve desde dentro del contenedor:

docker compose exec prowlarr curl -sS -o /dev/null -w '%{http_code}\n' http://sonarr:8989

Un código de estado HTTP demuestra que la ruta de red funciona. Un error de resolución de nombres demuestra que el nombre del servicio es incorrecto.

Comprueba que los enlaces físicos se están creando realmente

No des por válida la configuración hasta comprobar el número de enlaces. Después de importar un elemento, compara el archivo descargado con el archivo de la biblioteca:

stat -c '%i %h %n' /mnt/data/torrents/tv/*/*.mkv
stat -c '%i %h %n' /mnt/data/media/Shows/*/*/*.mkv

El primer número es el inode y el segundo es el número de enlaces. Un archivo con un enlace físico muestra el mismo inode en ambas ubicaciones y un número de enlaces de 2. Dos inodes distintos, cada uno con un número de enlaces de 1, indican que Sonarr copió el archivo. El registro de importación indicará que el enlace físico falló.

Supervisa también el disco. df -h /mnt/data apenas debería cambiar durante una importación, porque un enlace físico añade un nombre, pero no datos.

Qué se rompe realmente

Los errores de permisos al importar indican que el ID de usuario del contenedor no puede escribir en la carpeta de la biblioteca. El mensaje es Access to the path ... is denied. Comprueba con ls -ln /mnt/data/media que el ID del propietario coincide con tu PUID y recuerda que los directorios necesitan el bit de ejecución para que el contenedor pueda acceder a ellos.

Los archivos que aparecen como propiedad de root indican que el contenedor se inició antes de que existiera el directorio del host, por lo que Docker lo creó como root. Detén el stack, chown el directorio y vuelve a iniciarlo.

Si eliminas un torrent de qBittorrent y descubres que el archivo de la biblioteca también desapareció, significa que la importación fue una copia que después se eliminó, o que borraste los datos en lugar de la entrada del torrent. Con un hardlink real, eliminar un nombre deja intacto el otro, porque los datos solo se liberan cuando el recuento de enlaces llega a cero.

Un disco que se llena más rápido que el contenido multimedia que añadiste es la forma más costosa del problema de las copias. Ejecuta la comprobación stat anterior antes de comprar más almacenamiento.

Requisitos de esta pila para un VPS

Las tres aplicaciones arr consumen pocos recursos. Consultan los indexadores, escriben en una base de datos SQLite pequeña y cambian el nombre de los archivos. Un servidor con 2 GB de RAM ejecuta los cuatro contenedores sin problemas. La carga procede de otros servicios. Un cliente de descargas puede saturar la entrada y salida del disco con torrents grandes, y un servidor multimedia que transcodifica vídeo en el mismo equipo consumirá la CPU. Mantenga los archivos multimedia en un volumen con un rendimiento real de entrada y salida, y establezca un límite de ancho de banda en el cliente de descargas si el servidor ejecuta cualquier otra tarea importante.

FAQ

¿Por qué Sonarr copia los archivos en lugar de crear enlaces físicos?

Porque el origen y el destino están en sistemas de archivos diferentes desde el punto de vista del contenedor. Dos montajes bind independientes, como /downloads y /tv, son dos sistemas de archivos aunque ambos procedan de un mismo disco del host. Monte un único directorio principal como /data en cada contenedor y coloque dentro las descargas y la biblioteca. Así será posible crear el enlace. Confirme el resultado con stat -c '%i %h %n' en ambos archivos: deben tener el mismo inode y un recuento de enlaces de 2.

¿Qué PUID y PGID debo usar?

Use el id numérico de la cuenta del host propietaria del árbol de medios. Puede obtenerlo con id -u y id -g. En una VPS de Ubuntu recién instalada, normalmente es 1000 para ambos. Todos los contenedores de la pila deben usar el mismo par. De lo contrario, una aplicación escribe archivos que otra no puede modificar. Después de cambiar los valores, vuelva a crear los contenedores con docker compose up -d --force-recreate y corrija los archivos existentes con chown -R.

¿Debo exponer estas interfaces web a Internet?

No, y no debería hacerlo. Enlace cada puerto publicado a 127.0.0.1 en el archivo Compose. Después, acceda a las interfaces mediante un túnel SSH, una VPN o un proxy inverso que termine TLS (seguridad de la capa de transporte) y añada su propia autenticación. Publicarlas directamente es más peligroso de lo que parece, porque Docker inserta sus propias reglas de firewall y una regla deny de ufw no detendrá ese tráfico.

¿Dónde encuentro la contraseña de qBittorrent?

La imagen de LinuxServer.io muestra una contraseña temporal para el usuario admin en su registro de inicio. Ejecute docker compose logs qbittorrent | grep -i password para leerla y establezca después una contraseña permanente en Options y Web UI. Se genera una nueva contraseña temporal en cada reinicio hasta que establezca una propia.

¿Puede Jellyfin usar las mismas carpetas?

Sí, ese es el objetivo de esta estructura. Monte /mnt/data/media en el servidor multimedia como /media. Sus bibliotecas estarán en /media/Movies y /media/Shows, mientras que Sonarr y Radarr escribirán en esos mismos directorios mediante /data/media. Asigne al servidor multimedia los mismos PUID y PGID para que pueda leer lo que escribe la pila de arr.

#sonarr#radarr#prowlarr#docker-compose#self-hosting