# Verified compose for Jellyfin, tested 2026-10-08 by the SelfHostBench lab (3 runs; the figures are the median). # Lab host: AMD EPYC 7763 64-Core Processor, 2 vCPU, 7.8 GiB RAM, x86_64, Docker 28.0.4. # Floating image tags below were replaced by the version resolved at test time; # the registry digest is in the comment on each image line. # Measurements: jellyfin.json (schema 3). # Jellyfin (official jellyfin/jellyfin image): config and cache in named volumes, the media library read-only from a folder. # Follows the Compose example in the Jellyfin docs (https://jellyfin.org/docs/general/installation/container/). # Differences from that example, all marked below: named volumes for /config and /cache, a tighter health check, # no published autodiscovery port (7359/udp), no container_name, and the media folder mounted read-only. # There is no TLS in this file. Put a reverse proxy in front before you expose it (see the article). name: jellyfin services: jellyfin: # Pin a release tag. `latest` follows every release, major ones included (tags: see the docs link above). image: jellyfin/jellyfin:12.2 # sha256:357724bf0ae27a672c7cbaa899db2d9abeb13dbd8657ccce750258a4c059d037 (version 12.2, from label:org.opencontainers.image.version) restart: unless-stopped # Runs as root by default, as in the docs. To run as another user, add `user: "1000:1000"` here (docs: "Optional - specify # the uid and gid you would like Jellyfin to use instead of root"). With the named volumes below that works as it is. # If you bind-mount /config and /cache from folders instead, chown them to that user first: otherwise Jellyfin stops with # "Access to the path '/config/log' is denied". The user must be able to read the media folder too. ports: # Web UI and API. Clients connect here. - "8096:8096/tcp" # In Compose's default bridge network the server reports its container address (for example http://172.18.0.2:8096) as its # own address. To advertise the address your clients use, add the variable below (docs: "alternative address used for autodiscovery"). # environment: # - JELLYFIN_PublishedServerUrl=http://media.example.lan:8096 volumes: # Settings, the SQLite database, users, metadata, logs and the built-in backups. This is your server: back it up. - config:/config # Transcoding segments, image cache and other data that can be rebuilt. Not part of a backup. - cache:/cache # Your library. Replace ./media with the folder that holds your movies and shows, for example /srv/media. # Read-only means Jellyfin cannot change or delete your files. It still has to be able to read them. - ./media:/media:ro healthcheck: # The image has its own check (curl on /health every 30 s). This is the same endpoint with a 5 s interval # so `docker compose up --wait` returns as soon as the server answers "Healthy". test: ["CMD-SHELL", "curl -fsS http://localhost:8096/health | grep -q Healthy"] interval: 5s timeout: 5s retries: 30 start_period: 5s volumes: config: cache: