Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen … (nur in der veröffentlichten Seite verfügbar).

Anwendungen Schwierigkeit: Fortgeschritten

Jellyfin selbst hosten: dein eigener Medienserver hinter Traefik

Jellyfin mit Docker hinter Traefik aufsetzen: deine Filme, Serien und Musik streamen – mit HTTPS und der Mediathek auf netcups Local Block Storage.

· 10 Min. Lesezeit ·Dauer: ca. 60 Minuten
Inhaltsverzeichnis

Netflix, Spotify und Google Fotos in einem – nur auf deinem eigenen Server und ohne monatliche Gebühr: Jellyfin streamt deine Film-, Serien- und Musiksammlung an jedes Gerät. In diesem Rezept hängen wir Jellyfin hinter Traefik und legen die Mediathek auf netcups Local Block Storage, damit dir der Platz nicht ausgeht.

Was bauen wir?

Am Ende läuft Jellyfin 10.11 als Container auf deinem Server, erreichbar unter https://jellyfin.DEINE_DOMAIN mit gültigem HTTPS. Jellyfin ist ein komplett freier Medienserver (keine Cloud, keine Telemetrie, kein Abo): Du legst deine Dateien ab, Jellyfin zieht automatisch Cover, Beschreibungen und Metadaten und streamt alles an Browser, Handy, Smart-TV oder die Jellyfin-App.

Die eigentliche Herausforderung bei einem Medienserver ist Speicherplatz – eine Filmsammlung sprengt die kleine System-SSD eines VPS schnell. Deshalb binden wir netcups Local Block Storage ein: eine zusätzliche, lokale Festplatte, die im Server wie ein normales Laufwerk erscheint und auf der die Mediathek liegt.

Ehrlich zum Transcoding

Jellyfin rechnet Videos bei Bedarf live in ein Format um, das dein Endgerät versteht (Transcoding) – das kostet viel CPU. netcup-Server sind reine CPU-Maschinen ohne Grafikkarte, echtes Hardware-Transcoding (über eine GPU) gibt es dort also nicht. Auf einem Root-Server mit dedizierten Kernen (RS 1000) läuft Software-Transcoding für ein, zwei parallele Streams gut; der Königsweg bleibt aber Direct Play – dazu unten mehr.

Voraussetzungen

  • Ein laufender Traefik-Reverse-Proxy mit dem proxy-Netzwerk und dem Resolver le – siehe Reverse Proxy mit Traefik.
  • Eine Subdomain jellyfin.DEINE_DOMAIN mit DNS-Record auf deine Server-IP – siehe Domain mit Server verbinden.
  • Dedizierte CPU-Kerne sind für flüssiges Streaming klar im Vorteil (Transcoding). Auf einem geteilten VPS geht es für Direct Play auch, wird bei Umrechnung aber schnell eng.
  • Optional, aber empfohlen: gebuchter netcup Local Block Storage für die Mediathek (Schritt 2). Ohne ihn legst du die Medien einfach in einen Ordner auf der System-Disk – bis der Platz ausgeht.
  • Ein paar eigene Medien-Dateien (Filme/Serien/Musik), die du hosten darfst.

Ob dein Setup wirklich dedizierte Kerne braucht, zeigt dir der Server-Rechner – bei Transcoding lautet die Antwort meist ja.

🍳 Empfehlung Anzeige

Root-Server RS 1000 G12

4 dedizierte Kerne · 8 GB RAM · 256 GB NVMe

ab 12,79 €/Monat

Dedizierte Kerne fürs Transcoding – und Local Block Storage lässt sich dazubuchen.

Zu netcup →

💶 5 € Gutschein für netcup-Neukunden: 36nc17844976032 (nur Neukunden, keine Domains)

Schritt für Schritt

Schritt 1: DNS-Record anlegen

Lege jellyfin.DEINE_DOMAIN an (A/AAAA auf deine Server-IP) und prüfe, dass er auflöst:

Terminal
dig +short jellyfin.DEINE_DOMAIN

Es muss deine Server-IP zurückkommen – sonst holt Traefik später kein Zertifikat.

Schritt 2: netcup Local Block Storage einbinden

Der Local Block Storage ist zusätzlicher Speicher, den du im netcup-Kundenkonto zu deinem Server dazubuchst. Anders als der netzgebundene Storage Space anderer Anbieter (der per NFS angebunden wird und langsamer ist) erscheint er im Server als ganz normale lokale Festplatte – ideal für eine Mediathek, weil schnell und beliebig partitionierbar.

Kein Block Storage gebucht?

Dann überspring diesen Schritt und lege die Mediathek einfach unter ~/jellyfin/media an – alle folgenden Befehle funktionieren genauso, nur der Pfad ist ein anderer. Du kannst den Block Storage jederzeit später dazunehmen und die Daten umziehen.

Sieh dir zuerst an, welche Festplatten der Server kennt:

Terminal
sudo fdisk -l

Die System-Disk ist typischerweise /dev/sda (bzw. /dev/vda). Der neue Block Storage taucht als zusätzliches Gerät auf, meist /dev/vdb – erkennbar an der Größe, die du gebucht hast.

Erst prüfen, dann partitionieren

Die Gerätenamen können je nach Server abweichen. Partitionierst du versehentlich die System-Disk, ist dein Server hinüber. Ordne das Gerät eindeutig über die Größe zu, bevor du fortfährst. Im Zweifel vorher einen Snapshot anlegen.

Lege eine Partition auf der neuen Disk an (hier /dev/vdb):

Terminal
sudo cfdisk /dev/vdb

Wähle bei der Abfrage gpt (der moderne Standard – dos/MBR kann maximal 2 TiB adressieren, Mediatheken wachsen gern darüber hinaus), dann New, nimm die volle Größe, und schreib die Tabelle mit Write (tippe yes), danach Quit. Es entsteht die Partition /dev/vdb1. Formatiere sie mit einem ext4-Dateisystem:

Terminal
sudo mkfs.ext4 /dev/vdb1

Erstelle einen Mount-Punkt und häng die Partition ein:

Terminal
sudo mkdir -p /mnt/media
sudo mount /dev/vdb1 /mnt/media

Damit die Disk auch nach einem Reboot automatisch eingehängt wird, trägst du sie mit ihrer UUID (nicht mit /dev/vdb1, das kann sich ändern) in die /etc/fstab ein. UUID auslesen:

Terminal
sudo blkid /dev/vdb1
Ausgabe
/dev/vdb1: UUID="a1b2c3d4-...." TYPE="ext4" ...

Öffne die fstab und häng die Zeile mit deiner UUID an:

Terminal
sudo nano /etc/fstab
Ausgabe
UUID=a1b2c3d4-....   /mnt/media   ext4   defaults   0   2

Prüfe die Einträge, bevor du dich auf den Reboot verlässt – ein Tippfehler in der fstab kann den Bootvorgang blockieren:

Terminal
sudo umount /mnt/media && sudo mount -a && df -h /mnt/media

Kommt hier keine Fehlermeldung und zeigt df -h deine neue Disk unter /mnt/media, ist alles korrekt eingetragen.

Schritt 3: Projekt und Medien-Ordner anlegen

Leg das Compose-Projekt an – die Konfiguration ist klein und darf auf die System-Disk. Die Unterordner config und cache legst du dabei gleich mit an, bevor der Container das erste Mal startet: Würde erst der Docker-Daemon sie erzeugen, gehörten sie root – Jellyfin läuft aber als UID 1000 (siehe Schritt 4) und könnte in sein eigenes /config nicht schreiben, der Container würde beim ersten Start abstürzen.

Terminal
mkdir -p ~/jellyfin/{config,cache} && cd ~/jellyfin

Und die Ordnerstruktur für die Mediathek auf dem Block Storage. Jellyfin sortiert am besten, wenn Film, Serie und Musik getrennt liegen:

Terminal
sudo mkdir -p /mnt/media/{filme,serien,musik}

Damit der Jellyfin-Container die Dateien lesen darf, müssen sie deinem Benutzer gehören. Ermittle deine User- und Gruppen-ID (meist 1000) und übereigne den Ordner:

Terminal
id -u && id -g
sudo chown -R 1000:1000 /mnt/media

Kopiere jetzt deine Medien in die passenden Unterordner (per scp, rsync oder einem SFTP-Client). Für eine saubere Erkennung hilft eine klare Benennung, z. B. filme/Der Pate (1972)/Der Pate (1972).mkv.

Schritt 4: Die compose.yaml

Jetzt die zentrale Datei. Ersetze jellyfin.DEINE_DOMAIN durch deine Subdomain:

YAML
services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.11
    user: "1000:1000"
    environment:
      - JELLYFIN_PublishedServerUrl=https://jellyfin.DEINE_DOMAIN
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/media:/media:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.jellyfin.rule=Host(`jellyfin.DEINE_DOMAIN`)"
      - "traefik.http.routers.jellyfin.entrypoints=websecure"
      - "traefik.http.routers.jellyfin.tls.certresolver=le"
      - "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
    networks:
      - proxy
    restart: unless-stopped

networks:
  proxy:
    external: true

Was die Zeilen bedeuten:

  • image: …:10.11.11 – die feste, aktuelle Stable-Version. Kein latest (siehe „Wartung & Backups").
  • user: "1000:1000" – Jellyfin läuft mit deiner User-/Gruppen-ID, damit es die Medien lesen kann. Passt du in Schritt 3 andere IDs an, hier ebenfalls ändern.
  • JELLYFIN_PublishedServerUrl – sagt Jellyfin, unter welcher öffentlichen Adresse es erreichbar ist. Das verhindert, dass App-Links plötzlich auf eine interne IP zeigen.
  • volumes: config (Einstellungen, Nutzer, Metadaten) und cache liegen klein im Projektordner; die Mediathek wird vom Block Storage unter /mnt/media als /media in den Container gehängt – :ro (read-only), damit Jellyfin deine Originale niemals verändert.
  • Die vier Traefik-Labels sind das bekannte Muster. Neu ist nur der Port: Jellyfin lauscht auf 8096, deshalb das loadbalancer.server.port-Label. Ohne es gäbe es einen 502 Bad Gateway.
  • Kein ports: – Jellyfin ist ausschließlich über Traefik (HTTPS) erreichbar, nicht direkt aus dem Internet.

Starte den Stack und sieh beim Hochfahren zu:

Terminal
docker compose up -d
docker compose logs -f jellyfin

Beim ersten Start braucht die Zertifikatsausstellung ein paar Sekunden. Sobald im Log Startup complete erscheint, ist Jellyfin bereit.

Schritt 5: Der Ersteinrichtungs-Assistent

Ruf https://jellyfin.DEINE_DOMAIN im Browser auf. Beim allerersten Aufruf führt dich ein Assistent durch die Grundeinrichtung:

  1. Sprache wählen (Deutsch).
  2. Ein Administrator-Konto anlegen – vergib ein langes, einmaliges Passwort, denn die Anmeldeseite steht öffentlich im Netz.
  3. Medienbibliotheken hinzufügen: Klick „Medienbibliothek hinzufügen", wähl den Typ (z. B. Filme), und trag als Ordner den Container-Pfad ein – also /media/filme (nicht /mnt/media/filme, das ist der Pfad auf dem Host!). Wiederhole das für serien und musik.
  4. Metadaten-Sprache auf Deutsch stellen, den Rest kannst du übernehmen.

Der Jellyfin-Einrichtungsassistent beim ersten Aufruf mit Feldern für Servername und bevorzugte Anzeigesprache
Der Einrichtungsassistent beim ersten Aufruf

Nach dem Assistenten scannt Jellyfin die Ordner und lädt Cover und Beschreibungen. Bei großen Sammlungen dauert der erste Scan etwas – den Fortschritt siehst du unter Dashboard → Geplante Aufgaben. Danach landest du auf der Startseite und siehst deine Mediathek mit den ersten Titeln:

Die Jellyfin-Startseite nach dem Setup mit der Bibliothek „Filme" und einem zuletzt hinzugefügten Film
Die Startseite mit der ersten Mediathek

Schritt 6: Jellyfin hinter dem Proxy sauber konfigurieren

Zwei Einstellungen sorgen dafür, dass Jellyfin hinter Traefik korrekt arbeitet. Öffne Dashboard → Netzwerk:

Das Jellyfin-Administrations-Dashboard mit Server-Version 10.11.11, aktiven Geräten und den Speicherpfaden, links das Menü mit Netzwerk- und Wiedergabe-Einstellungen
Das Admin-Dashboard – hier sitzen auch Netzwerk und Wiedergabe

  • Unter Bekannte Proxys / Known proxies trägst du das Traefik-Netzwerk ein, damit Jellyfin die echte Client-IP sieht (statt der Container-IP von Traefik). Das Subnetz ermittelst du mit:

    Terminal
    docker network inspect proxy --format '{{ (index .IPAM.Config 0).Subnet }}'

    Trag den zurückgegebenen Bereich (z. B. 172.19.0.0/16) dort ein.

  • HTTPS: Da Traefik die Verschlüsselung übernimmt, muss Jellyfin selbst kein TLS machen. Lass die HTTPS-Optionen in Jellyfin leer – alles läuft über den Proxy.

WebSockets (für Live-Updates der Oberfläche) leitet Traefik automatisch weiter, da ist nichts zu tun.

Schritt 7: Transcoding vs. Direct Play

Ob dein Server ins Schwitzen kommt, entscheidet sich hier. Zwei Fälle:

  • Direct Play – das Endgerät kann die Datei so abspielen, wie sie ist. Der Server schiebt nur Bytes durch, fast keine CPU-Last. Das ist der Idealfall.
  • Transcoding – Format, Codec oder Bitrate passen nicht zum Gerät (oder die Leitung ist zu langsam), also rechnet Jellyfin live um. Auf einem netcup-Server passiert das über die CPU – bei einem 4K-Stream kann das einen ganzen Server auslasten.

So hältst du die Last niedrig:

  • Passende Formate bereitstellen: H.264/AAC in einem .mp4/.mkv spielt praktisch jedes Gerät direkt ab. Exotische Codecs (z. B. bestimmte 4K-HEVC-Tonspuren) erzwingen Transcoding.
  • Client-Qualität in der App auf „Original/Direct Play" stellen, wenn die Leitung reicht.
  • Unter Dashboard → Wiedergabe kannst du die Transcoding-Einstellungen und ein Limit für gleichzeitige Streams setzen.

Hardware-Transcoding braucht eine GPU

Die in Jellyfin wählbare Hardwarebeschleunigung (VAAPI, QSV, NVENC) setzt eine Grafikeinheit unter /dev/dri voraus. Standard-VPS und -Root-Server bei netcup sind KVM-Maschinen ohne durchgereichte GPU – lass die Hardwarebeschleunigung dort aus, sie würde nur Fehler produzieren. Plane stattdessen mit dedizierten CPU-Kernen und Direct Play.

Wenn es nicht funktioniert

Symptom: 502 Bad Gateway beim Aufruf, obwohl der Container läuft.

Ursache & Lösung: Traefik erreicht den Container, trifft aber den falschen Port. Jellyfin lauscht auf 8096 – das Label traefik.http.services.jellyfin.loadbalancer.server.port=8096 muss gesetzt sein. Prüfe außerdem, dass Jellyfin im proxy-Netzwerk hängt.

Symptom: Die Bibliotheken bleiben leer, obwohl Dateien da sind.

Ursache & Lösung: Fast immer ein Rechte-Problem. Der Container läuft als 1000:1000 (Schritt 4), die Medien müssen also diesem Benutzer gehören: sudo chown -R 1000:1000 /mnt/media. Und: In Jellyfin muss der Container-Pfad stehen (/media/filme), nicht der Host-Pfad. Danach unter Dashboard → Geplante Aufgaben „Alle Bibliotheken scannen" starten.

Symptom: Video ruckelt/puffert, docker stats zeigt Jellyfin bei ~100 % CPU.

Ursache & Lösung: Es wird transcodiert. Unter Dashboard → Wiedergabe siehst du im Aktivitätsmonitor, ob „Transcode" statt „Direct Play" steht. Stell die Client-Qualität auf Original, stell exotische Codecs auf ein breit unterstütztes Format um, oder gib dem Server mehr (dedizierte) Kerne.

Symptom: Nach einem Reboot ist die Mediathek weg und Jellyfin zeigt leere Ordner.

Ursache & Lösung: Der Block Storage wurde nicht eingehängt – meist ein fehlender oder falscher fstab-Eintrag (Schritt 2). Prüfe mit df -h /mnt/media und sudo mount -a. Die Zeile muss die UUID verwenden, nicht /dev/vdb1.

Symptom: Login-Seite lädt, aber die App findet den Server nicht / Links zeigen auf eine interne Adresse.

Ursache & Lösung: JELLYFIN_PublishedServerUrl fehlt oder ist falsch. Setz sie in der compose.yaml auf https://jellyfin.DEINE_DOMAIN und starte mit docker compose up -d neu (ein restart reicht nicht, damit die Environment-Änderung greift).

Wartung & Backups

  • Updates bewusst einspielen. Der feste Tag (jellyfin:10.11.11) bedeutet: Du entscheidest, wann aktualisiert wird. Tag hochsetzen → docker compose pulldocker compose up -d. Vor dem Sprung auf eine neue Hauptversion die Release-Notes lesen – Datenbank-Migrationen sind nicht immer umkehrbar.
  • Config sichern, Medien getrennt behandeln. Das config-Volume (Nutzer, Einstellungen, Wiedergabe-Status, Metadaten) ist klein und der eigentlich wertvolle Teil – sichere es verschlüsselt off-site mit Restic. Die Mediathek selbst ist meist zu groß fürs klassische Backup und aus den Original-Datenträgern reproduzierbar; entscheide bewusst, ob du sie sicherst oder als „ersetzbar" einstufst. Ehrlich: Ein zweites Backup deiner Filmsammlung kostet richtig Speicher.
  • Plattenplatz überwachen. Eine Mediathek wächst stetig. Behalte die Belegung im Blick (df -h /mnt/media) und richte am besten einen Monitor in Uptime Kuma ein, der Alarm schlägt, bevor der Block Storage voll ist.
  • Öffentlich erreichbar = absichern. Die Anmeldeseite steht im Netz, und Jellyfin bringt keine Zwei-Faktor-Authentifizierung mit (auch nicht per offiziellem Plugin). Vergib deshalb konsequent starke Passwörter, deaktiviere ungenutzte Konten – und überlege bei rein privater Nutzung, Jellyfin gar nicht öffentlich, sondern nur über ein VPN erreichbar zu machen.

Feedback per E-Mail: feedback@serverkueche.de

Das könnte dir auch schmecken