298 lines
9.4 KiB
Markdown
298 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!
|