Jellyfin Mediaserver auf meinem Rock64 Mini NAS
Durch einige Posts auf Mastodon und ein Video von Jeff Geerling bin ich auf die Multimediaserver-Software Jellyfin aufmerksam geworden. Mir war das Konkurrenzrodukt Plex bereits bekannt, aber mit Jellyfin bekommt man eine reine FOSS Lösung, bei der man sich keine Gedanken um Lizensierung oder Kosten machen muss. Für meine Ansprüche - vor allem Musikstreaming - sollte Jellyfin genügen, daher habe ich es kurzerhand auf meinem Rock64-basierten Mini NAS installiert.
Setup
Jellyfin kann als Debian-Paket oder Container installiert werden. Bei den Containerumgebungen kann man aus Docker und Podman wählen. Da Jellyfin für mich neu ist und ich den Betrieb erst einmal erproben will, habe ich mich für ein Podman-basiertes Setup entschieden. Auf Docker verzichte ich gerne, wenn es geht. Das modernere Podman mit seinen Features ist mir grundsätzlich sympathischer - aber das ist eine andere Geschichte und soll hier keine weitere Rolle spielen.
Zunächst wird Podman inkl. zweier Abhängigkeiten von den Ubuntu/Armbian-Paketquellen installiert:
apt install podman uidmap slirp4netns
Danach wird ein neuer User angelegt, unter dem der Jellyfish-Container später ausgeführt werden soll. Mit Podman können Container ohne Daemon und ohne Root-Rechte als einfacher Benutzer ausgeführt werden. Von diesem Sicherheitsvorteil will ich selbstverständlich profitieren:
adduser --disabled-password --home /opt/jellyfin jellyfin
su - jellyfin
(ein “normaler” Login dieses jellyfin
Users wird mittels --disabled-password
ausgeschlossen. Somit muss man kein Passwort vergeben und sich auch keine Gedanken um einen weiteren Angriffsvektor über einen Benutzeraccount machen. Der pseudo-Login wird über su
ausgeführt.)
Damit auch der jellyfin
User später die vom Container ausgegebenen Logs lesen kann, wird er zur systemc-journal
Gruppe hinzugefügt:
usermod -aG systemd-journal jellyfin
Im Homeverzeichnis des neuen Benutzers (/opt/jellyfin
) wird ein neues Bash-Script “init-jellyfin.sh” angelegt. Dieses dient nur dem ersten Start (und weiteren Starts nach einer Konfigurationsänderung). Nach dem ersten Start wird das Script aber idR. nicht mehr benutzt, sondern auf den systemd-basierten Autostart des Podman-Containers zurückgegriffen. Inhalt der Scriptdatei:
podman run \
--name jellyfin \
--detach \
--label "io.containers.autoupdate=registry" \
--volume jellyfin-cache:/cache:Z \
--volume jellyfin-config:/config:Z \
--mount type=bind,source=/mnt/raid2tb/media,destination=/media,ro=true \
--net=host \
docker.io/linuxserver/jellyfin:latest
(Pfad /mnt/raid2tb/media
ggf. anpassen und zu eigenem Medienbibliothek-Pfad ändern!)
--publish
Argumenten für das Durchreichen von Containerports und die Angabe von --net=host
sind hier entscheidend für die DLNA-Funktion. Damit der integrierte DLNA-Server im lokalen Netzwerk funktionieren kann, muss sich der Container im Host-Netzwerk befinden und darf nicht an ein separates Netzwerk angebunden sein.Die Datei wird nun ausführbar gemacht und gestartet:
chmod u+x create-jellyfin.sh
./create-jellyfin.sh
Im Hintergrund werden die Containerimages heruntergeladen und die darin befindlichen Applikationn gestartet. Das kann auf einem SBC wie dem Rock64 einige Momente dauern. Wird die Kommandozeile ohne Fehlermeldung wieder freigegeben, scheint alles funktioniert zu haben. Im Webbrowser sollte dann unter http://<server.ip>:8096
das Webinterface zu sehen sein.
systemd Service für Autostart erstellen
Mit den aktuellen Einstellungen wird der Container nach einem Server-Neustart nicht mehr automatisch gestartet und müsste händisch mittels
podman start jellyfin
neu gestartert werden. Das können wir mit einem systemd User-Service ändern.
Systemd erlaubt es, benutzerspezifische Services anzulegen und zu starten. Während der Jellyfin-Container im Hintergrund noch läuft, können wir über ein spezielles Podman-Kommando automatisch einen passenden systemd Service generieren lassen. Das geht so:
mkdir -p ~/.config/systemd/user/
podman generate systemd --new --name jellyfin > ~/.config/systemd/user/jellyfin.service
Im nächsten Schritt würde man den neuen Service normalerweise mittels systemctl --user enable jellyfin
aktivieren. Da wir zu Beginn einen jellyfin
Account ohne Passwort angelegt und uns mittels su
als dieser neue Benutzer eingeloggt haben, muss zunächst noch eine Korrektur vorgenommen werden.
Würde man an dieser Stelle das genannte systemd Kommando ausführen, erschiene die Fehlermeldung
Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined
Das kommt daher, dass wir uns mit dem jellyfin
User nicht regulär via SSH oder ein TTY eingeloggt haben. Deshalb wurde der systemd user
Service für den Benutzer nicht aktiviert und er verfügt über keine gültige Konfiguration des DBus-Zugriffs. Mit den folgenden Zeilen und Kommandos kann das Problem beseitigt werden:
In ~/.profile
am Ende hinzufügen:
# This is for enabling "systemctl --user" commands without valid login session
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
Nun zum root
User wechseln (z.B. durch exit
) - dann als root
User ausführen:
loginctl enable-linger $(id -u jellyfin)
systemctl start user@$(id -u jellyfin).service
Zurück zum jellyfin User (su - jellyfin
) - und der Service wird aktiviert:
systemctl --user daemon-reload
systemctl --user enable --now jellyfin.service
Das sollte nun ohne Fehlermeldungen funktionieren. Solltet ihr eine zsh
Shell verwenden, muss noch mittels source ~/.profile
die .profile
Datei gesourced werden. Alternativ lassen sich die oben genannten export
Zeilen selbstverständlich auch in die ~/.zshrc
Datei unten einbetten.
WebUI: Medienbibliotheken einrichten
Alles weitere wird im Webfrontend von Jellyfin eingerichtet. Das Initialsetup wird euch zu euren Wunschbibliotheken befragen. Hier gilt es zu beachten, dass der Medienpfad als Pfad innerhalb des Containers angegeben wird - und das ist idR. immer /media
. Egal, wie der Pfad zu euren Medien außerhalb des Containers lauten mag. Die beiden Pfade wurden im init-jellyfin.sh
Script aufeinander gemapped.
Extra: Webinterface mit Nginx Proxy
Wer seine Jellyfish-Instanz auf Port 80 und / oder über eine sichere HTTPS Verbindung bereitstellen will, kann sich von der Beispielkonfiguration unter https://jellyfin.org/docs/general/networking/nginx.html inspirieren lassen.
Die Einrichtung wird vor allem dann empfohlen, wenn ihr außerhalb des heimischen Netzwerks mit Jellyfin kommunizieren wollt. So umgeht ihr auch elegant Portsperren für nicht-HTTP Ports in Hotel WLANs und sorgt dafür, dass niemand euren Traffic belauscht.
Ein Wort zur Performance
Wunder darf man von einem kleinen Single Board Computer wie dem Rock64 nicht erwarten. Sobald der Medienscan abgeschlossen ist, reagiert die Weboberfläche zwar nicht raasend schnell, aber angemessen zügig. Was die Live-Transcodierung von Videos angeht, wird man aber enttäuscht: Wie sich herausstellt, bringt Jellyfin zwar alles mit, was es zum Hardware-Kodierung braucht, soch das Rock64 Board ist dafür nicht geschaffen und kann verschiedene Mediencodecs bestenfalls in Hardware decodieren - nicht aber codieren.
Wenn höher aufgelöste Filme gestreamt werden sollen und das Zielgerät das Format nicht direkt unterstützt, stößt man schnell an Grenzen. Der Filme-Fan greift also lieber zu einem x86-basierten Computer mit einem halbwegs starken Prozessor, der die fraglichen Codecs wie H264 und H265 sowie VP9 in Hardware codieren kann.
Da ich vorhabe, fast ausschließlich Musik zu streamen, fällt dieser Nachteil für mich nicht besonders ins Gewicht.