SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-26

Jellyfin en un VPS: transmite tu propia biblioteca

Instala Jellyfin con Docker en un VPS y evita los fallos habituales: permisos de medios, almacenamiento en bloques, acceso remoto seguro y transcodificación por CPU.

Qué vas a configurar

Un servidor multimedia Jellyfin en un VPS: un contenedor, tres volúmenes y un disco de almacenamiento en bloques que contiene tus películas y series, accesible desde cualquier navegador o aplicación de Jellyfin. La instalación usa un archivo compose de quince líneas. Todo lo que falla después se debe a dos causas: permisos de archivos que impiden que el contenedor los lea y el intento de transcodificar vídeo en un VPS sin GPU, que no está diseñado para esa tarea. Esta guía dedica la mayor parte de su contenido a esos dos problemas, porque ahí es donde se concentran las solicitudes de soporte.

Jellyfin es gratuito y completamente de código abierto. No requiere una cuenta, no incluye funciones de pago y no recopila telemetría. Por eso aparece en casi todas las listas de proyectos que merece la pena alojar por cuenta propia en 2026. Reproduce contenido que te pertenece. No incluye contenido, y esta guía no trata sobre cómo obtenerlo.

La realidad de la transcodificación antes de contratar nada

Lea esto primero, porque cambia lo que debe contratar. Un servidor multimedia hace una de dos cosas al pulsar el botón de reproducción. La reproducción directa transmite el archivo tal cual: el VPS lee los bytes del disco y los envía por la red, con un consumo de CPU casi nulo. La transcodificación vuelve a codificar el vídeo sobre la marcha, ya sea para cambiar la resolución, el códec o insertar los subtítulos en la imagen. Esto requiere CPU.

Un VPS típico no tiene GPU. Por tanto, cada transcodificación se ejecuta en la CPU con libx264/libx265, y la codificación por software consume muchos recursos. Una sola transcodificación de 1080p H.264 puede saturar varias vCPU compartidas. Una transcodificación 4K o HEVC normalmente no puede mantener la reproducción en tiempo real, por lo que la reproducción se detiene y el búfer se vacía de forma continua. La transcodificación por hardware, que permite hacer esto con bajo coste en un equipo doméstico con una iGPU Intel o una tarjeta Nvidia, no está disponible salvo que el proveedor alquile instancias con GPU.

Por tanto, la estrategia completa en un VPS es evitar la transcodificación. Mantenga la biblioteca en códecs que los clientes reproduzcan de forma nativa: vídeo H.264, audio AAC o AC3, dentro de un contenedor MP4 o MKV. Elija aplicaciones cliente que admitan reproducción directa: las aplicaciones nativas de Jellyfin para Android TV, iOS y Roku, además de Infuse, Kodi y Jellyfin Media Player para equipos de escritorio. Así, el VPS nunca necesita ejecutar ffmpeg y un equipo modesto con 2 vCPU puede transmitir contenido a varias personas a la vez. Si planea transcodificar, necesitará un equipo mucho más grande y caro. Incluso entonces, 4K sigue siendo una mala opción.

Haga también los cálculos de ancho de banda, porque es la otra sorpresa. La reproducción directa envía el archivo a su propia tasa de bits. Un archivo 1080p comprimido usa 8-12 Mbps; un remux de Blu-ray 1080p, 20-30 Mbps; y contenido 4K HDR, 40-80 Mbps. Tres personas reproduciendo directamente archivos de 10 Mbps generan 30 Mbps de tráfico de subida sostenido desde su VPS. Compruebe dos datos de su plan: la velocidad del puerto (¿puede enviar 30 Mbps de subida?) y el límite mensual de transferencia. Una película de dos horas a 10 Mbps supone unos 9 GB de salida, por lo que una cuota medida de 1 TB/mes permite algo más de cien películas de ese tipo al mes, es decir, tres o cuatro al día. Un hogar que vea contenido 4K, con una tasa de bits entre cuatro y ocho veces mayor, agota esa cuota mucho más rápido. Incluya en el mismo presupuesto cualquier otro servicio que genere tráfico de salida desde el mismo servidor, incluido un relay de RustDesk autohospedado, que transporta una sesión de escritorio remoto completa cuando dos pares no pueden conectarse directamente.

Requisitos previos

  • Un VPS KVM nuevo con Ubuntu 24.04, acceso como root o mediante sudo, Docker y el plugin Compose instalados.
  • Un volumen de almacenamiento de bloques para los archivos multimedia, con capacidad suficiente para su biblioteca (consulte la sección sobre dimensionamiento). El disco raíz pequeño que incluye un VPS no es el lugar adecuado para almacenar sus películas.
  • Un nombre de dominio si desea acceso HTTPS público, o una VPN WireGuard en el mismo VPS si prefiere mantener todo privado.
  • Contenido multimedia que tenga derecho legal a transmitir: sus propias copias, sus propias grabaciones y archivos de su propiedad.

Monta primero el almacenamiento en bloques

Adjunta el volumen desde el panel de tu proveedor. Después, localízalo y móntalo. Obtén el nombre del dispositivo con lsblk. Será algo como /dev/sdb o /dev/vdb, nunca el disco raíz.

lsblk
sudo mkfs.ext4 /dev/sdb          # ONLY on a new, empty volume — this ERASES it
sudo mkdir -p /mnt/media
sudo blkid /dev/sdb              # copy the UUID shown for this device

Móntalo mediante su UUID, no mediante /dev/sdb. Las letras de los dispositivos pueden cambiar entre reinicios. Si usas el dispositivo incorrecto, puedes formatear o montar otro disco. Añade una línea a /etc/fstab:

UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /mnt/media  ext4  defaults,nofail  0  2
sudo mount -a
df -h /mnt/media

nofail es importante. Sin esta opción, si el volumen en bloques se desconecta, el servidor no arranca y entra en un shell de emergencia. El error más grave es ejecutar mkfs.ext4 en un volumen que ya contiene datos, porque los borra. Formatea sólo los volúmenes nuevos. Si el disco ya contiene tu biblioteca, pasa directamente a la línea de fstab.

Organice los medios como espera Jellyfin

Jellyfin busca los metadatos según los nombres de las carpetas y los archivos. Si la estructura es incorrecta, las películas aparecen como archivos sin título y sin carátula, o un episodio se asocia con la serie equivocada. Hay exactamente tres reglas: cada película debe estar en su propia carpeta Name (Year) con un nombre de archivo coincidente; las carpetas de temporada deben llamarse Season 01, no S01; los archivos de episodios deben usar S01E01; y los especiales deben ir en Season 00.

/mnt/media
├── Movies
│   ├── Blade Runner (1982)
│   │   └── Blade Runner (1982).mkv
│   └── Arrival (2016)
│       └── Arrival (2016).mkv
└── Shows
    └── Severance (2022)
        ├── Season 01
        │   ├── Severance - S01E01.mkv
        │   └── Severance - S01E02.mkv
        └── Season 00
            └── Severance - The Lexington Letter.mkv

El (Year) de las películas no es decorativo: permite distinguir las nuevas versiones para que el buscador seleccione el título correcto. Mantenga Movies y Shows como carpetas de nivel superior independientes, porque cada una se convierte en una biblioteca de Jellyfin para un tipo de contenido específico. Si los mezcla, el proveedor de metadatos puede confundirse. Jellyfin también indexa sin problemas una tercera carpeta de fotos, pero la experiencia es limitada frente a la de un servidor de fotos específico. Si sus álbumes son importantes, asígneles su propio equipo con PhotoPrism o Immich y deje este servidor para películas y series.

Permisos: el motivo principal por el que las bibliotecas aparecen vacías

Este es el error de concepto que puede hacerle perder una tarde. La imagen oficial de jellyfin/jellyfin no utiliza las variables de entorno PUID/PGID; esas variables pertenecen a la imagen de LinuxServer.io (lscr.io/linuxserver/jellyfin). En la imagen oficial, el usuario se controla con la clave user: en compose. Si se omite, el contenedor se ejecuta como root. En ambos casos, la regla es la misma: el uid/gid con el que se ejecuta el contenedor debe poder leer y atravesar todos los directorios de medios.

Se ejecutará con uid/gid 1000, el primer usuario que no es root en una instalación estándar de Ubuntu. Confirme el suyo y establezca el propietario:

id                                  # confirm your user is uid=1000 gid=1000
sudo chown -R 1000:1000 /mnt/media
sudo find /mnt/media -type d -exec chmod 755 {} \;
sudo find /mnt/media -type f -exec chmod 644 {} \;
mkdir -p ~/jellyfin/config ~/jellyfin/cache
sudo chown -R 1000:1000 ~/jellyfin

Los directorios necesitan el bit de ejecución (el x de 755), no sólo permisos de lectura. Sin él, el contenedor no puede entrar en la carpeta aunque pueda listar su nombre. El problema que deja vacía una biblioteca completa suele estar en el directorio padre: si el uid del contenedor no puede atravesar el punto de montaje, nunca llega a /media/Movies ni a /media/Shows, y todas las bibliotecas aparecen vacías al mismo tiempo, con Access to the path ... is denied en el registro. Cualquier carpeta de medios que no pueda leer se registra y se omite. Por eso, un conjunto de archivos copiados como root desaparece de la biblioteca sin mostrar un error evidente. Esta es la razón por la que cambiamos el propietario de forma recursiva y establecemos el bit de ejecución en todos los directorios, en lugar de corregir una sola carpeta.

El archivo docker-compose

services:
  jellyfin:
    image: jellyfin/jellyfin:10
    container_name: jellyfin
    user: "1000:1000"
    restart: unless-stopped
    ports:
      - "127.0.0.1:8096:8096"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/media:/media:ro
    environment:
      - JELLYFIN_PublishedServerUrl=https://jellyfin.example.com

Línea por línea: user: "1000:1000" es lo que establece realmente los permisos de los archivos y coincide con la propiedad indicada arriba. /config contiene todo el servidor, las cuentas, las bibliotecas, los metadatos y el estado de supervisión, por lo que debe admitir escritura y es lo que debe incluir en las copias de seguridad. /cache es un espacio de trabajo temporal. El montaje de medios es :ro (solo lectura) de forma intencionada: Jellyfin almacena de forma predeterminada las imágenes y los metadatos en /config, por lo que nunca necesita escribir en la biblioteca. Además, el modo de solo lectura protege los archivos frente a un borrado accidental o un complemento defectuoso. El puerto está enlazado deliberadamente a 127.0.0.1. El inicio de sesión web de Jellyfin usa HTTP sin cifrar, por lo que nunca publicamos 8096 en Internet. JELLYFIN_PublishedServerUrl es la dirección que el servidor anuncia para la autodetección local mediante una difusión UDP en la LAN. Los clientes de Internet nunca la ven y simplemente usan la URL que se introduce en la aplicación. Establézcala como la dirección que deben recibir los clientes y prevea introducir esa URL manualmente en los dispositivos remotos.

Inícielo desde el directorio de compose:

docker compose up -d
docker logs -f jellyfin

Primera ejecución: el asistente de configuración y las bibliotecas

Como el puerto está enlazado a localhost, abra el asistente mediante un túnel SSH desde su portátil en lugar de abrir un acceso en el firewall:

ssh -L 8096:127.0.0.1:8096 you@your-vps-ip

Ahora vaya a http://localhost:8096. El asistente le guía para seleccionar el idioma y crear un usuario administrador con una contraseña segura. Esta cuenta controla el servidor, así que no reutilice una contraseña temporal. Añada la primera biblioteca: seleccione el tipo de contenido Películas, indique /media/Movies (la ruta dentro del contenedor, no la ruta del host) y repita el proceso con Series en /media/Shows. Finalice el asistente y Jellyfin iniciará el análisis. El resultado esperado es que los carteles y títulos aparezcan en uno o dos minutos para una biblioteca pequeña. Más adelante puede añadir o editar bibliotecas en Dashboard → Libraries y forzar un nuevo análisis con Scan All Libraries. Esos carteles también son lo que hace interesante probar una interfaz alternativa cuando lo básico ya funciona, porque Halcyon reconstruye la misma biblioteca como un videoclub transitable de los años 90 a partir de las imágenes que Jellyfin ya ha descargado.

Si utiliza cualquier tipo de transcodificación, abra Dashboard → Playback → Transcoding y establezca la ruta temporal de transcodificación en /cache/transcodes para que la actividad se almacene en el volumen de caché en lugar de aumentar /config. Mantenga la aceleración por hardware en None; no hay ninguna GPU disponible para acelerarla.

Acceso remoto: proxy inverso TLS o mantenerlo en la VPN

Hay dos formas seguras de acceder a Jellyfin desde fuera y una forma insegura que debe evitar. La forma insegura consiste en publicar el puerto 8096 directamente en Internet: las credenciales de inicio de sesión viajan en texto claro y el puerto recibe ataques de fuerza bruta en pocas horas.

Opción A, proxy inverso TLS. Coloque Jellyfin en un subdominio detrás de Traefik con TLS automático para sus aplicaciones Docker o detrás de nginx con un certificado de Let's Encrypt emitido por Certbot. Jellyfin usa WebSockets para las actualizaciones en tiempo real, por lo que el proxy debe reenviar las cabeceras de actualización. Traefik lo hace automáticamente; en nginx debe especificarlas y usar HTTP/1.1 con el upstream. De lo contrario, la actualización no se realiza:

location / {
    proxy_pass http://127.0.0.1:8096;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Configure JELLYFIN_PublishedServerUrl con la dirección https:// para que cualquier mecanismo de autodetección local anuncie la URL correcta y las aplicaciones remotas usen la dirección que les proporcione. Añada también fail2ban para ralentizar los intentos de fuerza bruta contra el inicio de sesión. Cuando el servidor sea público, configure Uptime Kuma con la URL para recibir avisos de interrupciones antes que sus usuarios. Dirija sus notificaciones a un servidor ntfy autoalojado para que un fallo de comprobación llegue como notificación push al teléfono, en lugar de como un correo que leerá a la mañana siguiente. Publicar un inicio de sesión en Internet también es un buen momento para auditar el resto del servidor, en lugar de asumir que sólo responde el puerto 443, y open-kritt ejecuta ese análisis desde su propio contenedor en el mismo VPS.

Opción B, mantenerlo privado en una VPN. No publique el puerto 8096. Acceda a Jellyfin sólo mediante un túnel WireGuard terminado en el mismo servidor. Para un entorno doméstico, esta es la opción segura más sencilla: no requiere certificados, no expone el servicio públicamente y no ofrece una superficie para ataques de fuerza bruta. Enlace el contenedor a la dirección del túnel o a localhost y conéctese mediante la VPN. Consulte la guía para configurar una VPN WireGuard en un VPS privado para configurar el túnel.

Dimensionamiento del almacenamiento y copias de seguridad

Planifique según la calidad, no según la cantidad de archivos. Las películas 1080p comprimidas ocupan entre 4 y 15 GB cada una; un remux 1080p, entre 20 y 40 GB; una temporada de TV en 1080p, entre 15 y 40 GB; cualquier contenido 4K ocupa entre 40 y 100 GB por película. Una biblioteca con unos cientos de películas y algunas series necesita un volumen de 2-4 TB. Además, suele ser más barato sobredimensionar el volumen de bloques una sola vez que migrarlo más adelante.

/config contiene todo el estado del servidor, por lo que es el único elemento que debe copiar. Cree una instantánea, o detenga el servicio y use tar, y conserve la copia fuera del servidor:

docker compose down
sudo tar czf jellyfin-config-$(date +%F).tgz -C ~/jellyfin config
docker compose up -d

/cache y la carpeta de transcodificación se pueden eliminar sin consecuencias. El contenido multimedia de /mnt/media se copia por separado o se acepta que habrá que volver a extraerlo. La mayoría de las personas elige la segunda opción por el tamaño de los archivos. Las actualizaciones se controlan mediante docker compose pull && docker compose up -d. La etiqueta :10 anterior se mantiene dentro de la versión principal 10.x. Por tanto, pasar a la siguiente versión principal requiere modificar la etiqueta de forma deliberada. Revise las notas de la versión de Jellyfin antes de hacerlo, porque las migraciones del esquema de la biblioteca se realizan en las versiones principales. Una etiqueta fijada y un directorio de estado con copia de seguridad son toda la receta necesaria para cualquier contenedor que deba estar siempre activo. Es el mismo patrón que permite mantener activa la memoria y las programaciones de un agente autohospedado después de reinicios.

Modos de fallo y mensajes que verá

La biblioteca está vacía después de un análisis. El registro de Dashboard → Logs (o ~/jellyfin/config/log/log_*.log) muestra:

System.UnauthorizedAccessException: Access to the path '/media/Movies' is denied.

El uid del contenedor no puede leer esa ruta. Causa: los archivos multimedia pertenecen a root o a un uid distinto del valor de user:, un directorio no tiene el bit de ejecución o el propio montaje principal no permite que ese uid lo atraviese. Solución: chown -R 1000:1000 /mnt/media, directorios 755 y archivos 644. Después, vuelva a analizar.

La reproducción consume toda la CPU y se interrumpe. docker stats jellyfin muestra un uso de CPU cercano al 100% multiplicado por el número de núcleos, y Dashboard → Playback muestra la sesión como Transcode con una velocidad inferior a 1.0x. El cliente no está reproduciendo directamente. Por tanto, el VPS realiza la transcodificación mediante CPU a una velocidad inferior a la de reproducción y no puede mantener el ritmo. Causa: un códec o contenedor no compatible, la incrustación de subtítulos o la conversión de tono HDR. Solución: cambie a un cliente compatible con reproducción directa, mantenga las fuentes en H.264/AAC, use subtítulos de texto (SRT) en lugar de subtítulos de imagen (PGS/VOBSUB), que obligan a incrustarlos, y no reproduzca contenido 4K HDR en un equipo que sólo tenga CPU.

"No hay flujos compatibles disponibles". El mensaje completo suele ser "Este cliente no es compatible con el contenido multimedia y el servidor no está enviando un formato multimedia compatible." El cliente rechazó la fuente y la transcodificación alternativa tampoco pudo iniciarse. Causa: un comando de ffmpeg incorrecto, un archivo ilegible o el perfil del usuario bloquea la conversión de vídeo. Solución: lea la línea de ffmpeg en Dashboard → Logs, confirme que el archivo se puede reproducir, compruebe los permisos de reproducción del usuario si depende de la transcodificación y pruebe un segundo cliente para descartar problemas de códecs del navegador.

Las películas no tienen póster o muestran uno incorrecto. Los metadatos no coincidieron. Causa: una película no está en su propia carpeta Name (Year), una carpeta de temporada se llama S01 en lugar de Season 01, los episodios no siguen el formato S01E01 o falta el año. Solución: cambie los nombres para usar la estructura anterior y después seleccione Refresh metadata → Replace all, o use Identify en un único elemento para fijar la entrada correcta de TMDB/TVDB.

FAQ

¿Puede un VPS transcodificar vídeo sin GPU?

Sí, pero sólo con la CPU y con un coste elevado. Una única transcodificación de software a 1080p puede saturar varias vCPU, y 4K o HEVC normalmente no puede mantener el tiempo real, por lo que la reproducción se almacena en búfer. La mejor opción es evitar la transcodificación: mantenga la biblioteca en H.264/AAC y use aplicaciones cliente que reproduzcan directamente, de modo que el VPS sólo transfiera bytes. Alquile una instancia con GPU sólo si realmente necesita transcodificación sobre la marcha.

¿Por qué mi biblioteca de Jellyfin está vacía después de un análisis?

Casi siempre se debe a los permisos. La imagen oficial de jellyfin/jellyfin se ejecuta con el usuario indicado en user: (o como root), y si ese uid no puede leer los archivos, el análisis registra Access to the path ... is denied y los omite. Corrija el propietario con chown -R 1000:1000 /mnt/media, asigne el permiso de ejecución a los directorios (755), vuelva a analizar y compruebe también el directorio padre, porque si el uid del contenedor no puede atravesar /mnt/media, nunca llega a las carpetas de la biblioteca y todo aparece vacío. La segunda causa más común es una estructura de directorios que no coincide con la esperada por Jellyfin.

¿Cómo accedo a Jellyfin de forma remota y segura?

Hay dos opciones adecuadas. Colóquelo detrás de un reverse proxy TLS en un subdominio para cifrar el inicio de sesión y la transmisión, y añada fail2ban. Nunca exponga el puerto sin cifrado 8096, porque envía la contraseña en texto claro. Otra opción es mantenerlo completamente privado y acceder sólo mediante una VPN, que es la alternativa segura más sencilla para un hogar. Configure las aplicaciones con la dirección pública directamente. La autodetección es una difusión de la red local, por lo que no llega a los clientes que se conectan desde Internet.

¿Cuánto disco y ancho de banda necesita un VPS de Jellyfin?

El espacio en disco depende de la calidad: calcule 4-15 GB por película 1080p comprimida, 20-40 GB por remux y 40-100 GB para 4K. Por tanto, la mayoría de las bibliotecas necesitan un volumen en bloque de 2-4 TB. El ancho de banda lo determina la tasa de bits de la reproducción directa: 8-12 Mbps por flujo 1080p y mucho más para 4K. Confirme que la velocidad de su puerto admite el número de espectadores simultáneos y supervise el límite mensual de transferencia. Añada margen de CPU si planea transcodificar. Priorice el ancho de banda sobre los núcleos si planea usar la reproducción directa.

Jellyfin es software gratuito y de código abierto, y ejecutarlo es completamente legal. Lo importante es el contenido: transmita sólo contenido multimedia que posea o cuya custodia tenga autorizada, como sus propias copias de discos, grabaciones o archivos para los que tenga derechos. Jellyfin no incluye contenido multimedia ni proporciona ningún medio para obtenerlo. Es un reproductor para una biblioteca que ya posee.