Setup self-hosted Jellyfin Media Server in Docker

Last updated on

docker

Though Plex is a very popular media server for self-hosting, some open source enthusiasts prefer to use an alternative since Plex Media Server is not open source. A nice, simpler and admittedly less pretty alternative is Jellyfin. This guide will show you how to run it in Docker container.

Table of Contents

  1. Installing Docker and Docker Compose
  2. Preparing and the Docker-Compose file
  3. Starting the container and configuring Jellyfin
  4. Theming the web UI with custom CSS
  5. References

Installing Docker and Docker-Compose

I’ll be quoting from the Docker docs, which as of mid-2023 recommend uninstalling older packages like the separate docker-compose in favor of the new docker-compose-plugin, among other things.

This post assumes you are installing on Debian or Ubuntu, check the Docker docs for installation instructions on CentOS and it’s offshoots, Fedora, RHEL, or Raspbian.

First, uninstall all conflicting packages:

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt remove $pkg; done

Install necessary packages to allow apt to use a repository over HTTPS:

sudo apt update
sudo apt install ca-certificates curl gnupg

Add Docker’s official GPG key:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Set up the repository:

echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Now install Docker:

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo service docker start && sudo service docker enable

Preparing the Docker-Compose file

Though Jellyfin has an official Docker image, I highly suggest you instead use the Linuxserver image, which is built and maintained by the Linuxserver community. I’ve run the Linuxserver image of Jellyfin without issue, and it seems that to be the most common way to run Jellyfin.

Here is an example docker-compose.yml file to setup jellyfin:

---
version: "3"
services:
  jellyfin:
    image: lscr.io/linuxserver/jellyfin:latest
    container_name: jellyfin
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - JELLYFIN_PublishedServerUrl=192.168.0.100
    volumes:
      - ~/docker/jellyfin:/config
      - ~/media/tvshows:/data/tvshows
      - ~/media/movies:/data/movies
    ports:
      - 8096:8096
      - 8920:8920
      - 7359:7359/udp
    restart: unless-stopped

Let’s break down what each of these parameters do:

ParameterFunction
imageHere we’re using the latest version of the Linuxserver-maintained image.
container_nameOptional, but you should give your containers a name for clarity.
PUID=1000
PGID=1000
These env variable sets a UID and GID for Jellyfin and should match the owner of the volumes you are adding; check your UID and GID with the command id.
JELLYFIN_PublishedServerUrl=This will allow the server to be discoverable on your home network. Add this with your server’s IP to easily connect your devices to Jellyfin. Make sure to map UDP port 7359 for this to work. (See below.)
portsThis will map ports on your machine (left of the colon) to ports inside the container (right of the colon) — optional in Linux but required in Windows and WSL.

Port 8096 is for HTTP access, 8920 for HTTPS (optional) and 7359:7359/udp lets the server be discoverable on your local network when using the JELLYFIN_PublishedServerUrl parameter. (See above.)
volumesHere we’re mapping local directories (left of the colon) to directories inside the container (right of the colon).
restartThis tells Docker under what circumstances to restart the container when it is stopped — the options are no, always, on-failure and unless-stopped.

If you’d like to use hardware acceleration, see this part of the Jellyfin documentation. If the machine you’re hosting Jellyfin on has an Intel CPU, there’s a good chance is supports Quick Sync and you should let Jellyfin use it. To do so, add the following option to your docker compose:

devices:
  - /dev/dri/renderD128:/dev/dri/renderD128
  - /dev/dri/card0:/dev/dri/card0

Starting the container and configuring Jellyfin

Once your docker-compose.yml is ready, use the command docker compose up -d from within the same directory as the docker-compose.yml to run it. After completion, use the command docker ps to verify the container is up and running. You should see output similar to the below:

CONTAINER ID   IMAGE                                 COMMAND   CREATED         STATUS         PORTS                                                                   NAMES
7383028393f4   lscr.io/linuxserver/jellyfin:latest   "/init"   9 seconds ago   Up 7 seconds   0.0.0.0:8096->8096/tcp, 0.0.0.0:8920->8920/tcp, 0.0.0.0:359->7359/udp   jellyfin

Good to go. Now to configure Jellyfin you’ll need to access it’s web UI, which by default is at (for example) http://192.168.0.100:8096. On the first page you’ll be asked to choose a language and can also use the Quick Start if desired, for purposes of this guide we’ll choose English and click Next. On the following page you can create a user and password (or you can use no password if preferred), create your login and click Next.

Creating a user in Jellyfin.

You’ll be taken to setup your media libraries, click on Add Media Library.

Setting up media library in Jellyfin.

In the Content Type drop down menu, choose like kind of media you’re adding. For this guide we’ll choose Movies, then click Ok.

Creating a movie library in Jellyfin.

A series of options will appear, read through them and make your choices, or just leave the defaults if you don’t want to change anything. To add a folder to the library, click the Plus (+) button and you’ll get a pop-up where you can choose a folder. Choose from the list, or type out the path, and click Ok (You can also add a network share as the folder.)

Adding a folder to Jellyfin movie library.

On the following page you can set up remote access to Jellyfin, meaning whether other devices will be able to access Jellyfin. Check the box Allow remote connections to this server, but leave unchecked Enable automatic port mapping unless you want to access Jellyfin from outside your network. (You’ll additionally need to open port 8096 on your router for that. I don’t suggest it.) Then click Next.

Remote access in Jellyfin.

Your movies should now appear within the Movies section of the Jellyfin UI. Repeat the process to add other directories for your TV, Music, Books, Photos and other libraries if desired. And you’re done! You can now watch jellyfin right in the web UI.

Theming the web UI with custom CSS

If you’d like to change the web GUI’s colors and vibe, you’ll need the Skin Manager community plugin. (These affect the web UI accessed via the browser only.) As per the directions on their GitHub:

  1. In jellyfin, go to Dashboard -> Plugins -> Repositories -> add and paste this link https://raw.githubusercontent.com/danieladov/JellyfinPluginManifest/master/manifest.json
  2. Go to Catalog and search for Skin Manager
  3. Click on it and install
  4. Restart Jellyfin

Use docker restart jellyfin and once the Jellyfin container has restarted, go back into the GUI, go to Dashboard -> Plugins and click on Skin Manager. Use the dropdown menu to pick a skin (my favorite is JellySkin), tweak any options if it has them, and click Set Skin. If it doesn’t switch to the new time right away, try a hard refresh with Ctrl + F5. Also, sometimes Nginx Proxy Manager the skins won’t work due to CSP issues. (I haven’t encountered this problem, but I have my reverse proxy set up without HTTPS and that may be why.)