How to Install Jellyfin on a VPS with Docker Compose

Build a private media server with the official Jellyfin container, HTTPS, read-only media mounts and a recovery plan you have actually tested.

Choose a Cloud VPSOfficial Jellyfin container guide
HYEHOST mascot deploying Jellyfin with Docker on a private VPS media server

Jellyfin is an open-source media system for organising and streaming films, television, music and photos from infrastructure you control. It can serve apps on televisions, phones, browsers and desktop systems without handing your library to a subscription streaming platform.

A reliable deployment needs more thought than launching one container. The server must keep its configuration persistent, expose the service through HTTPS, give Jellyfin safe access to media files and avoid promising video transcoding that the chosen CPU cannot deliver. This guide builds that foundation on a current Ubuntu or Debian VPS.

Choose the Right Jellyfin VPS Architecture

Direct Play sends a compatible file to the client without converting it. That is the most efficient path and should be your first target. Transcoding decodes and re-encodes video while someone watches, so it can consume far more CPU and may require hardware acceleration for high-resolution media.

WorkloadPractical starting pointWhat matters most
Personal Direct Play2 vCPU, 2GB to 4GB RAMClient codec support and network speed
Family library4 vCPU, 4GB to 8GB RAMMetadata scans and concurrent streams
Live transcodingTest with the real files and clientsCodec, bitrate, CPU and GPU access
Large media archiveSeparate fast system disk and capacity storageLibrary size, backup time and disk throughput

These are planning points rather than performance guarantees. A low-bitrate H.264 file and a high-bitrate 4K HEVC file can place completely different demands on the same server.

Prepare Ubuntu or Debian for Jellyfin

Point a DNS record such as media.example.com at the VPS. Install Docker Engine and the Compose plugin using our Docker installation guide, then create persistent directories:

sudo install -d -m 0750 /opt/jellyfin/config
sudo install -d -m 0750 /opt/jellyfin/cache
sudo install -d -m 0750 /srv/media
sudo chown -R "$USER":"$USER" /opt/jellyfin

Place films, programmes, music and photos into clearly named directories below /srv/media. Jellyfin will receive that path as read-only, reducing the chance that an application mistake changes the source library.

sudo install -d -m 0755 /srv/media/movies
sudo install -d -m 0755 /srv/media/shows
sudo install -d -m 0755 /srv/media/music
cd /opt/jellyfin

Deploy Jellyfin with Docker Compose

Create /opt/jellyfin/compose.yml using the official Jellyfin image:

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    ports:
      - "127.0.0.1:8096:8096"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /srv/media:/media:ro
    environment:
      - TZ=Europe/London

The official container stores settings in /config, temporary transcoding and artwork data in /cache, and listens on TCP port 8096. Binding that port to 127.0.0.1 keeps it private until an HTTPS proxy is ready.

Validate and start the service:

docker compose config
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 jellyfin

Jellyfin also documents UDP port 7359 for local-network discovery. It is normally unnecessary for an internet-hosted VPS. Host networking is mainly relevant when DLNA discovery is required on a trusted local network, so bridge networking is the cleaner default here.

Publish Jellyfin Through HTTPS

Install Caddy or another reverse proxy on the host. A minimal Caddy site is:

media.example.com {
  reverse_proxy 127.0.0.1:8096
}

Once DNS resolves correctly, Caddy obtains and renews the certificate. Allow SSH, HTTP and HTTPS through the firewall, but do not open 8096 publicly:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

In Jellyfin, add the reverse proxy address under Dashboard, Networking, Known Proxies. Preserve forwarded headers and WebSocket support. The official Jellyfin reverse proxy documentation covers proxy trust, HTTPS and URL-handling details.

Add Libraries and Plan for Transcoding

Open https://media.example.com, create the administrator account and add libraries using paths such as /media/movies, /media/shows and /media/music. Select the content type and language carefully because they affect metadata matching.

  • Prefer Direct Play by using formats supported by the expected clients.
  • Keep configuration and cache on SSD-backed storage.
  • Use capacity storage for large media libraries when HDD latency is acceptable.
  • Limit simultaneous transcodes to what the server can sustain.
  • Keep enough free disk space for transcode cache and metadata growth.

Hardware acceleration is optional. Jellyfin supports technologies including Intel Quick Sync, NVIDIA NVENC and VA-API when the host exposes a compatible device to the container. A standard virtual server may not provide that device. Do not add a /dev/dri or GPU mapping unless the platform exposes it and you have tested the exact driver, codec and container permissions. See the official hardware acceleration guide.

Choose Storage Without Slowing the Application

Jellyfin's database, metadata and cache benefit from low-latency SSD storage. The media files themselves are read mostly in long sequential streams, so a Storage VPS can make sense when a large HDD-backed library matters more than SSD performance.

Keep the application and media paths operationally simple. Remote storage mounted over the public internet introduces latency and another failure point, so a Storage Box is better used for encrypted configuration backups than as Jellyfin's active transcode cache or database.

Back Up Jellyfin and Prove the Restore

The valuable application state is under /opt/jellyfin/config. It contains users, libraries, watched status, metadata choices and server settings. The cache can be regenerated, while the media library may need a separate retention policy because of its size.

Stop Jellyfin briefly for a simple consistent archive:

cd /opt/jellyfin
docker compose stop jellyfin
sudo tar -czf jellyfin-config-$(date +%F).tar.gz config compose.yml
docker compose start jellyfin

Encrypt and copy that archive to an independent destination. Our rclone Storage Box guide shows how to send scheduled backups over SFTP. Restore the archive into a temporary directory, start an isolated Jellyfin container and confirm that users, libraries and settings return correctly.

Update Jellyfin Safely

Read the Jellyfin release notes, confirm the backup and then recreate the container from the current image:

cd /opt/jellyfin
docker compose pull
docker compose up -d
docker compose logs --tail=100 jellyfin

Pin a specific image version if you require a controlled maintenance window. A floating latest tag is convenient, but it does not replace release review and a working rollback plan.

Common Jellyfin VPS Problems

The proxy returns 502 Bad Gateway

Confirm the container is running, port 8096 is bound to loopback and the proxy points to 127.0.0.1:8096. Check docker compose logs jellyfin before changing firewall rules.

Jellyfin cannot see the media files

Verify the host path, container mount and filesystem permissions. The container path is /media, not /srv/media. Read-only mounts still require read and directory traversal permission.

Playback buffers or uses too much CPU

Open the playback information and check whether the client is Direct Playing or transcoding. Test a compatible media format, lower the requested bitrate or use supported hardware acceleration.

Jellyfin records the proxy address as every client

Configure Known Proxies and forwarded headers according to the reverse proxy documentation. Trust only the proxy addresses that actually send requests to Jellyfin.

Frequently Asked Questions

Can Jellyfin run on a VPS?

Yes. A Linux VPS is a practical home for Jellyfin when its CPU, memory, storage and bandwidth match the library and expected playback. Direct Play is considerably lighter than real-time transcoding.

How much RAM does Jellyfin need?

A small direct-play server can start with 2GB to 4GB RAM. Large libraries, several users, metadata processing and concurrent transcodes need more memory and CPU headroom.

Should Jellyfin use SSD or HDD storage?

Keep configuration, cache and metadata on SSD. HDD-backed storage is suitable for larger media libraries when capacity matters more than low latency.

Should I expose Jellyfin port 8096?

No. Bind it to loopback and publish the service through an HTTPS reverse proxy on ports 80 and 443.

Can a normal VPS transcode 4K video?

That depends on codec, bitrate, CPU and hardware acceleration. Prefer Direct Play and test representative files before promising live 4K transcoding to users.

What should I back up?

Back up the configuration directory, Compose file and protected settings. Maintain a separate plan for the media library and prove both recovery paths with test restores.