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

302 lines
9.4 KiB
Markdown

---
title: Jellyfin
description: 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](https://jellyfin.org) 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](https://docs.linuxserver.io/images/docker-jellyfin).
::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](/serveex/security/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`:
```bash [Terminal]
mkdir -p /media/movies /media/library /media/tvseries
```
Open Dockge, click `compose`, name the stack `jellyfin`, and add the following config:
```yaml [compose.yaml]
---
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:
```yaml [compose.yaml]
services:
jellyfin:
#...
labels:
- com.centurylinklabs.watchtower.enable=true
```
::
Find your PUID and GUID by running:
```bash [Terminal]
id username
```
Fill in your `.env` file with the retrieved values, for example:
```properties [.env]
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](https://docs.linuxserver.io/images/docker-jellyfin/#hardware-acceleration).
::
## 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](/general/networking/samba) 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](/general/networking/dns). And of course, [unless you use Cloudflare Zero Trust](/serveex/security/cloudflare), your box's port `443` must be forwarded to your server's port `443` in [NAT rules](/general/networking/nat).
::
Go to Dockge and edit SWAG's compose file by adding Jellyfin's network:
```yaml [compose.yaml]
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](/serveex/files/file-browser-quantum) to navigate and edit files instead of using terminal commands.
::
```bash [Terminal]
sudo nano /docker/swag/config/nginx/proxy-confs/jellyfin.subdomain.conf
```
Paste the following configuration:
```nginx [jellyfin.subdomain.conf]
## 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](/serveex/security/tinyauth)'s forward-auth check directly to `jellyfin.subdomain.conf`, the same way as [the TinyAuth guide](/serveex/security/tinyauth#protecting-an-app-via-reverse-proxy):
```nginx [jellyfin.subdomain.conf]{22-34,37-38}
## 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](/serveex/security/tinyauth#exposing-tinyauth-with-swag). 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](/serveex/advanced/authentik#protecting-an-app-via-reverse-proxy).
::
And you're done!