Files
docudjeex/content/en/3.serveex/5.media/1.jellyfin.md
T

9.4 KiB

title, description
title description
Jellyfin Install Jellyfin, a free and open-source media server, to stream your movies and TV shows from anywhere without a paid subscription.

:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}

Jellyfin

::note 🎯 Objectives:

  • Install Jellyfin
  • Access your media from outside your network ::

Jellyfin is a free, open-source alternative to Plex and Emby. Unlike Plex, it has no paid tiers, no telemetry, and doesn't require an online account to use or manage your server: everything runs locally and stays yours.

It covers the same basics: a media library with metadata and artwork, transcoding (including hardware acceleration), and apps for TV, Android, iOS, Windows, and macOS.

As always, we'll use the linuxserver.io image.

::note

Unlike Plex, Jellyfin has no cloud relay: to access your server outside your local network, you must expose it yourself (see below), or use a VPN like Wireguard. ::

Install Jellyfin

::file-tree

tree: /: - docker: - jellyfin: - compose.yaml - .env - config/ - media: - tvseries/ - movies/ - library/

::

Create the movies, tvseries, and library folders in /media:

mkdir -p /media/movies /media/library /media/tvseries

Open Dockge, click compose, name the stack jellyfin, and add the following config:

---
services:
  jellyfin:
    image: lscr.io/linuxserver/jellyfin:latest
    container_name: jellyfin
    environment:

      - PUID=${PUID}
      - PGID=${GUID}
      - TZ=Europe/Paris
    volumes:

      - /docker/jellyfin/config:/config
      - /media:/media
    restart: unless-stopped
    devices:

      - /dev/dri:/dev/dri
    ports:

      - 8096:8096

::tip Add the Watchtower label to automate updates:

services:
  jellyfin:
    #...
    labels:

      - com.centurylinklabs.watchtower.enable=true

::

Find your PUID and GUID by running:

id username

Fill in your .env file with the retrieved values, for example:

PUID=1000
GUID=1000

Deploy the stack. The local interface is available at http://yourserverip:8096.

::note

The /dev/dri device is only needed for hardware-accelerated transcoding on Intel/AMD GPUs. Remove it if your server doesn't have one, or adapt it for an NVIDIA GPU following linuxserver.io's documentation. ::

Configure Jellyfin

On first visit, Jellyfin walks you through a setup wizard:

  • Choose a display language and create your admin account.
  • Add a media library, pointing to /media/movies for movies and /media/tvseries for TV shows.
  • (Optional) Enable hardware acceleration in Dashboard > Playback if you have a compatible GPU.

And that's it! Add your media to /media/movies and /media/tvseries on your server, then install the Jellyfin app on your devices to watch locally or remotely.

::note

If your media is stored on a network disk (e.g. NAS or external hard drive over the network), refer to the Samba mount guide so Jellyfin can access it. ::

Expose Jellyfin with Swag

To access Jellyfin outside your local network, we'll expose it through Swag.

::note

We assume you have the subdomain jellyfin.mydomain.com with a CNAME pointing to mydomain.com in your DNS zone. And of course, unless you use Cloudflare Zero Trust, your box's port 443 must be forwarded to your server's port 443 in NAT rules. ::

Go to Dockge and edit SWAG's compose file by adding Jellyfin's network:

services:
  swag:
     container_name: # ...
      # ... 
     networks:              # Attach container to custom network 
      # ...           

      - jellyfin            # Name of the declared network

networks:                   # Define the custom network
  # ...
  jellyfin:                 # Declared network name
    name: jellyfin_default  # Actual external network name
    external: true          # Marks it as externally defined

Redeploy the stack and wait for SWAG to be fully operational.

::note

Here we assume the Jellyfin network name is jellyfin_default. You can check the connection by visiting SWAG's dashboard at http://yourserverip:81. ::

In the Swag folders, create the file jellyfin.subdomain.conf:

::tip{icon=""} Tip: Use File Browser Quantum to navigate and edit files instead of using terminal commands. ::

sudo nano /docker/swag/config/nginx/proxy-confs/jellyfin.subdomain.conf

Paste the following configuration:

## Version 2023/12/19

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name jellyfin.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth (requires ldap-location.conf in the location block)
    #include /config/nginx/ldap-server.conf;

    # enable for Authelia (requires authelia-location.conf in the location block)
    #include /config/nginx/authelia-server.conf;

    # enable for Authentik (requires authentik-location.conf in the location block)
    #include /config/nginx/authentik-server.conf;

    location / {
        # enable the next two lines for http auth
        #auth_basic "Restricted";
        #auth_basic_user_file /config/nginx/.htpasswd;

        # enable for ldap auth (requires ldap-server.conf in the server block)
        #include /config/nginx/ldap-location.conf;

        # enable for Authelia (requires authelia-server.conf in the server block)
        #include /config/nginx/authelia-location.conf;

        # enable for Authentik (requires authentik-server.conf in the server block)
        #include /config/nginx/authentik-location.conf;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app jellyfin;
        set $upstream_port 8096;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

Press :kbd{value="Ctrl+O"}, then :kbd{value="Enter"} to save, and :kbd{value="Ctrl+X"} to exit.

Wait a few minutes, then open https://jellyfin.mydomain.com in your browser.

::caution

If it fails: check your firewall rules. ::

Protecting Jellyfin with TinyAuth

Add TinyAuth's forward-auth check directly to jellyfin.subdomain.conf, the same way as the TinyAuth guide:

## Version 2023/12/19

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name jellyfin.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth (requires ldap-location.conf in the location block)
    #include /config/nginx/ldap-server.conf;

    # enable for Authelia (requires authelia-location.conf in the location block)
    #include /config/nginx/authelia-server.conf;

    # enable for Authentik (requires authentik-location.conf in the location block)
    #include /config/nginx/authentik-server.conf;

    location /tinyauth {
        internal;
        proxy_pass http://tinyauth:3000/api/auth/nginx;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Uri $request_uri;
    }

    location @tinyauth_login {
        return 302 https://tinyauth.mydomain.com/login?redirect_uri=$scheme://$http_host$request_uri;
    }

    location / {
        auth_request /tinyauth;
        error_page 401 = @tinyauth_login;

        # enable the next two lines for http auth
        #auth_basic "Restricted";
        #auth_basic_user_file /config/nginx/.htpasswd;

        # enable for ldap auth (requires ldap-server.conf in the server block)
        #include /config/nginx/ldap-location.conf;

        # enable for Authelia (requires authelia-server.conf in the server block)
        #include /config/nginx/authelia-location.conf;

        # enable for Authentik (requires authentik-server.conf in the server block)
        #include /config/nginx/authentik-location.conf;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app jellyfin;
        set $upstream_port 8096;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

::note

The location /tinyauth block runs inside SWAG's own container, so SWAG needs to be on TinyAuth's Docker network to reach it by name (tinyauth here). This should already be set up from exposing TinyAuth itself. If you run into an error, double-check SWAG's compose file still has that network attached. ::

::tip{icon=""} Tip: You can protect this app with Authentik instead of TinyAuth by opening jellyfin.subdomain.conf and uncommenting include /config/nginx/authentik-server.conf;{lang=nginx} and include /config/nginx/authentik-location.conf;{lang=nginx}. Don't forget to create an application and provider in Authentik. ::

And you're done!