Skip to main content

Container

Container images

Official container image: jellyfin/jellyfin Docker Pull Count.

LinuxServer.io image: linuxserver/jellyfin Docker Pull Count.

hotio image: hotio/jellyfin Docker Pull Count.

Jellyfin distributes official container images on Docker Hub for multiple architectures. These images are based on Debian and built directly from the Jellyfin source code.

Additionally the LinuxServer.io project and hotio distribute images based on Ubuntu and the official Jellyfin Ubuntu binary packages, see here and here to see their Dockerfile.

Docker

Docker allows you to run containers on Linux, Windows and MacOS.

The basic steps to create and run a Jellyfin container using Docker are as follows.

  1. Follow the official installation guide to install Docker.

  2. Download the latest container image.

    docker pull jellyfin/jellyfin
  3. Create persistent storage for configuration and cache data.

    Either create two directories on the host and use bind mounts:

    mkdir /path/to/config
    mkdir /path/to/cache

    Or create two persistent volumes:

    docker volume create jellyfin-config
    docker volume create jellyfin-cache
  4. Create and run a container in one of the following ways.

note

The default network mode for Docker is bridge mode. Bridge mode will be used if host mode is omitted. Using host networking (--net=host) is optional but required in order to use DLNA.

Using Docker command line interface:

docker run -d \
--name jellyfin \
--user uid:gid \
--net=host \
--volume /path/to/config:/config \ # Alternatively --volume jellyfin-config:/config
--volume /path/to/cache:/cache \ # Alternatively --volume jellyfin-cache:/cache
--mount type=bind,source=/path/to/media,target=/media \
--restart=unless-stopped \
jellyfin/jellyfin

Bind Mounts are needed to pass folders from the host OS to the container OS whereas volumes are maintained by Docker and can be considered easier to backup and control by external programs. For a simple setup, it's considered easier to use Bind Mounts instead of volumes. Multiple media libraries can be bind mounted if needed:

--mount type=bind,source=/path/to/media1,target=/media1
--mount type=bind,source=/path/to/media2,target=/media2,readonly
...etc
note

There is currently an issue with read-only mounts in Docker. If there are submounts within the main mount, the submounts are read-write capable.

Using Docker Compose

Create a docker-compose.yml file with the following contents. Add in the UID and GID that you would like to run jellyfin as in the user line below, or remove the user line to use the default (root).

version: '3.5'
services:
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
user: uid:gid
network_mode: 'host'
volumes:
- /path/to/config:/config
- /path/to/cache:/cache
- /path/to/media:/media
- /path/to/media2:/media2:ro
restart: 'unless-stopped'
# Optional - alternative address used for autodiscovery
environment:
- JELLYFIN_PublishedServerUrl=http://example.com
# Optional - may be necessary for docker healthcheck to pass if running in host network mode
extra_hosts:
- "host.docker.internal:host-gateway"

Then while in the same folder as the docker-compose.yml run:

docker compose up

To run the container in background add -d to the above command.

You can learn more about using Docker by reading the official Docker documentation.

Unraid Docker

An Unraid Docker template is available in the repository.

  1. Open the unRaid GUI (at least unRaid 6.5) and click on the Docker tab.

  2. Add the following line under "Template Repositories" and save the options.

    https://github.com/jellyfin/jellyfin/blob/master/deployment/unraid/docker-templates
  3. Click "Add Container" and select "jellyfin".

  4. Adjust any required paths and save your changes.

Podman

Podman allows you to run rootless containers. It's also the officially supported container solution on Fedora Linux and its derivatives such as CentOS Stream and RHEL. Steps to run Jellyfin using Podman are similar to the Docker steps.

  1. Install Podman:

    sudo dnf install -y podman
  2. Create and run a Jellyfin container:

    podman run \
    --detach \
    --label "io.containers.autoupdate=registry" \
    --name myjellyfin \
    --publish 8096:8096/tcp \
    --rm \
    --user $(id -u):$(id -g) \
    --userns keep-id \
    --volume jellyfin-cache:/cache:Z \
    --volume jellyfin-config:/config:Z \
    --mount type=bind,source=/path/to/media,destination=/media,ro=true \
    docker.io/jellyfin/jellyfin:latest
  3. Open the necessary ports in your machine's firewall if you wish to permit access to the Jellyfin server from outside the host. This is not done automatically when using rootless Podman. If your distribution uses firewalld, the following commands save and load a new firewall rule opening the HTTP port 8096 for TCP connections.

    sudo firewall-cmd --add-port=8096/tcp --permanent
    sudo firewall-cmd --reload

Podman doesn't require root access to run containers, although there are some details to be mindful of; see the relevant documentation. For security, the Jellyfin container should be run using rootless Podman. Furthermore, it is safer to run as a non-root user within the container. The --user option will run with the provided user id and group id inside the container. The --userns keep-id flag ensures that current user's id is mapped to the non-root user's id inside the container. This ensures that the permissions for directories bind-mounted inside the container are mapped correctly between the user running Podman and the user running Jellyfin inside the container.

Keep in mind that the --label "io.containers.autoupdate=image" flag will allow the container to be automatically updated via podman auto-update.

The z (shared volume) or Z (private volume) volume option tells Podman to relabel files inside the volumes as appropriate, for systems running SELinux.

Replace jellyfin-config and jellyfin-cache with /path/to/config and /path/to/cache if you wish to use bind mounts.

This example mounts your media library read-only by setting ro=true; set this to ro=false if you wish to give Jellyfin write access to your media.

Managing via Systemd

To run as a systemd service see Running containers with Podman and shareable systemd services.

As always it is recommended to run the container rootless. Therefore we want to manage the container with the systemd --user flag.

  1. First we have to generate the container as seen above.

  2. Next generate the systemd.service file.

    podman generate systemd --new --name myjellyfin > ~/.config/systemd/user/container-myjellyfin.service
  3. Verify and edit the systemd.service file to your liking. To further sandbox see Mastering systemd: Securing and sandboxing applications and services. An example service file is shown below. Do not blindly copy, one should make edits to the service file generated by podman.

    # container-myjellyfin.service
    # autogenerated by Podman 2.2.1
    # Wed Feb 17 23:49:24 EST 2021

    [Unit]
    Description=Podman container-myjellyfin.service
    Documentation=man:podman-generate-systemd(1)
    Wants=network.target
    After=network-online.target

    [Service]
    Environment=PODMAN_SYSTEMD_UNIT=%n
    Restart=on-failure
    ExecStartPre=/bin/rm -f %t/container-myjellyfin.pid %t/container-myjellyfin.ctr-id
    ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-myjellyfin.pid --cidfile %t/container-myjellyfin.ctr-id --cgroups=no-conmon -d --replace --cgroup-manager=systemd --volume jellyfin-config:/config:z --volume jellyfin-cache:/cache:z --volume jellyfin-media:/media:z -p 8096:8096 --userns keep-id --name myjellyfin jellyfin/jellyfin
    ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-myjellyfin.ctr-id -t 10
    ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-myjellyfin.ctr-id
    PIDFile=%t/container-myjellyfin.pid
    KillMode=control-group
    Type=forking

    # Security Features
    PrivateTmp=yes
    NoNewPrivileges=yes
    ProtectSystem=strict
    ProtectHome=yes
    ProtectKernelTunables=yes
    ProtectControlGroups=yes
    PrivateMounts=yes
    ProtectHostname=yes

    [Install]
    WantedBy=multi-user.target default.target
  4. Stop the running Jellyfin container.

    podman stop myjellyfin
  5. Start and enable the service.

    systemctl --user enable --now container-myjellyfin.service

    At this point the container will only start when the user logs in and shutdown when they log off. To have the container start as the user at first login we'll have to include one more option.

    loginctl enable-linger $USER
  6. To enable Podman auto-updates, enable the necessary systemd timer.

    systemctl --user enable --now podman-auto-update.timer