Jellyfin auf VPS installieren Anleitung
Lernen Sie die Installation von Jellyfin in Docker auf einem VPS kennen. Vermeiden Sie Fehler bei den Dateiberechtigungen und beim CPU-Transcoding.
Was Sie aufbauen
Ein Jellyfin-Mediaserver auf einem VPS: ein Container, drei Volumes und eine Block-Storage-Disk für Ihre Filme und Serien, erreichbar über jeden Browser oder die Jellyfin-App. Die Installation erfolgt über eine fifteen-line compose file. Fehler treten später meist aus zwei Gründen auf: Dateiberechtigungen, die der Container nicht lesen kann, oder die Anforderung an einen VPS ohne GPU, Videos zu transcodieren, für die er nicht ausgelegt ist. Dieser Guide konzentriert sich hauptsächlich auf diese beiden Punkte, da hier die meisten Support-Anfragen entstehen.
Jellyfin ist kostenlos und vollständig Open Source, ohne Benutzerkonto, ohne kostenpflichtige Funktionen und ohne Telemetrie – weshalb es auf fast jeder Liste von Dingen, die man 2026 selbst hosten sollte steht. Es spielt Medien ab, die Sie besitzen. Es liefert keine Inhalte, und dieser Guide dient nicht der Beschaffung von Inhalten.
Die Realität des Transcodings, bevor Sie etwas mieten
Lesen Sie dies zuerst, da es Ihre Kaufentscheidung beeinflusst. Ein Mediaserver führt beim Drücken der Play-Taste eine von zwei Aktionen aus. Direct play streamt die Datei im Originalzustand: Der VPS liest Bytes von der Festplatte und überträgt sie über das Netzwerk, was kaum CPU-Leistung benötigt. Transcoding kodiert das Video während der Wiedergabe neu — für eine neue Auflösung, einen neuen Codec oder um Untertitel einzubrennen — und dies beansprucht die CPU vollständig.
Ein typischer VPS besitzt keine GPU. Daher läuft jedes Transcoding auf der CPU mit libx264/libx265, und Software-Encoding ist rechenintensiv. Ein einzelnes 1080p H.264 Transcoding kann mehrere vCPUs vollständig auslasten; ein 4K oder HEVC Transcoding kann meist nicht mit der Echtzeit mithalten, wodurch die Wiedergabe stoppt und ständig puffert. Hardware-Transcoding — die Funktion, die dies auf einem Heimserver mit einer Intel iGPU oder einer Nvidia-Karte kostengünstig macht — steht Ihnen nicht zur Verfügung, es sei denn, Ihr Anbieter vermietet GPU-Instanzen.
Die gesamte Strategie für einen VPS lautet daher: Transcoding vermeiden. Speichern Sie Ihre Bibliothek in Codecs, die Ihre Clients nativ abspielen können — H.264 Video, AAC oder AC3 Audio, in einem MP4 oder MKV Container — und wählen Sie Client-Apps mit Direct-Play-Unterstützung: die nativen Jellyfin-Apps für Android TV, iOS und Roku sowie Infuse, Kodi und der Jellyfin Media Player für Desktop. Wenn Sie dies tun, wird der VPS niemals ffmpeg nutzen, und ein bescheidener 2 vCPU-Server kann gleichzeitig an mehrere Personen streamen. Wenn Sie Transcoding planen, benötigen Sie einen viel größeren, teureren Server, und selbst dann ist 4K eine unsichere Wahl.
Berechnen Sie auch die Bandbreite, da dies die zweite Überraschung ist. Direct play überträgt die Datei mit ihrer eigenen Bitrate. Eine komprimierte 1080p-Datei läuft mit 8–12 Mbps; ein 1080p Blu-ray Remux mit 20–30 Mbps; 4K HDR mit 40–80 Mbps. Drei Personen, die 10-Mbps-Dateien per Direct play streamen, verursachen einen dauerhaften Upload von 30 Mbps von Ihrem VPS. Prüfen Sie zwei Werte in Ihrem Tarif: die Port-Geschwindigkeit (kann er 30 Mbps Upstream bereitstellen?) und das monatliche Datenlimit. Ein zweistündiger 10-Mbps-Film verbraucht etwa 9 GB an ausgehendem Datenverkehr. Ein monatliches Limit von 1 TB entspricht also etwas mehr als hundert solcher Filme pro Monat — drei oder vier pro Tag. Ein Haushalt, der 4K mit der vier- bis achtfachen Bitrate streamt, verbraucht das Kontingent wesentlich schneller.
Voraussetzungen
- Ein frisches Ubuntu 24.04 KVM VPS mit root- oder sudo-Rechten sowie installiertem Docker und dem Compose-Plugin.
- Ein Block-Storage-Volume für die Medien, dessen Größe auf Ihre Bibliothek abgestimmt ist (siehe Größenberechnung unten). Die kleine Root-Disk eines VPS ist nicht für die Speicherung von Filmen geeignet.
- Eine Domain für öffentlichen HTTPS-Zugriff oder ein WireGuard VPN auf demselben VPS, falls das gesamte System privat bleiben soll.
- Medien, für deren Streaming Sie rechtlich berechtigt sind — eigene Rips, eigene Aufnahmen oder Dateien in Ihrem Besitz.
Mounten Sie zuerst den Block-Speicher
Hängen Sie das Volume im Panel Ihres Providers an, suchen Sie es und mounten Sie es. Ermitteln Sie den Gerätenamen über lsblk — dieser wird ähnlich wie /dev/sdb oder /dev/vdb lauten, niemals die Root-Disk.
lsblk
sudo mkfs.ext4 /dev/sdb # ONLY on a new, empty volume — this ERASES it
sudo mkdir -p /mnt/media
sudo blkid /dev/sdb # copy the UUID shown for this deviceMounten Sie das Volume über die UUID, nicht über /dev/sdb. Gerätenamen ändern sich nach einem Reboot, was dazu führen kann, dass Sie die falsche Disk formatieren oder mounten. Fügen Sie eine Zeile zu /etc/fstab hinzu:
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/media ext4 defaults,nofail 0 2sudo mount -a
df -h /mnt/medianofail ist wichtig: Ohne diesen Eintrag verweigert der Server den Bootvorgang und landet in einer Emergency Shell, falls das Block-Volume jemals getrennt wird. Der häufigste Fehler ist die Ausführung von mkfs.ext4 auf einem Volume, das bereits Daten enthält — dies löscht alle Daten. Formatieren Sie nur neue Volumes; falls die Disk bereits Ihre Library enthält, überspringen Sie den Formatierungsschritt und gehen Sie direkt zur fstab-Zeile über.
Strukturieren Sie die Medien so, wie Jellyfin sie erwartet
Jellyfin ordnet Metadaten anhand von Ordner- und Dateinamen zu. Eine falsche Struktur führt dazu, dass Filme als unbenannte Dateien ohne Poster erscheinen oder eine Episode der falschen Serie zugeordnet wird. Es gelten genau drei Regeln: Jeder Film befindet sich in einem eigenen Name (Year)-Ordner mit einem passenden Dateinamen; Staffelordner werden als Season 01 bezeichnet, nicht als S01; Episoden-Dateien verwenden S01E01; und Specials gehören in Season 00.
/mnt/media
├── Movies
│ ├── Blade Runner (1982)
│ │ └── Blade Runner (1982).mkv
│ └── Arrival (2016)
│ └── Arrival (2016).mkv
└── Shows
└── Severance (2022)
├── Season 01
│ ├── Severance - S01E01.mkv
│ └── Severance - S01E02.mkv
└── Season 00
└── Severance - The Lexington Letter.mkvDie (Year) bei Filmen dient nicht der Dekoration — sie dient der Unterscheidung von Remakes, damit der Matcher den richtigen Titel findet. Behalten Sie Movies und Shows als separate oberste Verzeichnisebene bei, da jedes daraus eine Jellyfin-Bibliothek eines spezifischen Inhaltstyps wird. Eine Vermischung führt zu Fehlern beim Metadaten-Provider.
Berechtigungen: der Hauptgrund für leere Bibliotheken
Dies ist ein häufiger Irrtum, der viel Zeit kostet. Das offizielle jellyfin/jellyfin-Image unterstützt die Umgebungsvariablen PUID/PGID nicht — diese gehören zum LinuxServer.io-Image (lscr.io/linuxserver/jellyfin). Beim offiziellen Image steuern Sie den Benutzer über den user:-Key in compose. Wenn dieser fehlt, läuft der Container als root. Unabhängig von der Wahl gilt: Die uid/gid, unter der der Container läuft, muss alle Medienverzeichnisse lesen und durchlaufen können.
Wir verwenden uid/gid 1000, den ersten Nicht-Root-Benutzer auf einem Standard-Ubuntu-System. Prüfen Sie Ihre Werte und setzen Sie die Besitzrechte:
id # confirm your user is uid=1000 gid=1000
sudo chown -R 1000:1000 /mnt/media
sudo find /mnt/media -type d -exec chmod 755 {} \;
sudo find /mnt/media -type f -exec chmod 644 {} \;
mkdir -p ~/jellyfin/config ~/jellyfin/cache
sudo chown -R 1000:1000 ~/jellyfinVerzeichnisse benötigen das execute-Bit (das x in 755), nicht nur das read-Bit. Ohne dieses Bit kann der Container das Verzeichnis nicht betreten, selbst wenn die Namen aufgelistet werden können. Die Ursache für eine komplett leere Bibliothek ist oft das übergeordnete Verzeichnis: Wenn die uid des Containers das Mount-Verzeichnis selbst nicht durchlaufen kann, erreicht er /media/Movies oder /media/Shows nicht. Die Bibliothek bleibt dann leer und Access to the path ... is denied erscheint im Log. Jedes einzelne Medienverzeichnis, das nicht lesbar ist, wird protokolliert und übersprungen. Dateien, die als root kopiert wurden, verschwinden so lautlos aus der Bibliothek. Deshalb führen wir ein rekursives chown aus und setzen das execute-Bit für jedes Verzeichnis, anstatt nur einen einzelnen Ordner zu korrigieren.
Die docker-compose Datei
services:
jellyfin:
image: jellyfin/jellyfin:10
container_name: jellyfin
user: "1000:1000"
restart: unless-stopped
ports:
- "127.0.0.1:8096:8096"
volumes:
- ./config:/config
- ./cache:/cache
- /mnt/media:/media:ro
environment:
- JELLYFIN_PublishedServerUrl=https://jellyfin.example.comZeile für Zeile: user: "1000:1000" legt die Dateiberechtigungen fest und entspricht der oben genannten Besitzzuordnung. /config enthält den gesamten Server – Konten, Bibliotheken, Metadaten und den Watch-Status – daher muss dieser beschreibbar sein; dies ist das Element, das Sie sichern. /cache ist ein temporärer Arbeitsbereich. Der Media-Mount ist absichtlich als :ro (read-only) konfiguriert: Jellyfin speichert Artwork und Metadaten standardmäßig unter /config. Daher muss Jellyfin niemals in Ihre Bibliothek schreiben; der Read-only-Modus schützt Ihre Dateien vor versehentlichem Löschen oder fehlerhaften Plugins. Der Port ist bewusst an 127.0.0.1 gebunden – da der Web-Login von Jellyfin über HTTP läuft, veröffentlichen wir den Port 8096 nicht im öffentlichen Internet. JELLYFIN_PublishedServerUrl ist die Adresse, die der Server für die lokale Autodiscovery bereitstellt – ein UDP-Broadcast im LAN, sodass Clients über das Internet diese Adresse nicht sehen und stattdessen die manuell in der App eingegebene URL verwenden. Setzen Sie diesen Wert auf die Adresse, die den Clients mitgeteilt werden soll; auf Remote-Geräten muss diese URL manuell eingegeben werden.
Starten Sie den Container aus dem compose-Verzeichnis heraus:
docker compose up -d
docker logs -f jellyfinErster Durchlauf: der Setup-Assistent und Ihre Bibliotheken
Da der Port an localhost gebunden ist, erreichen Sie den Assistenten über einen SSH-Tunnel von Ihrem Laptop aus, anstatt eine Firewall-Regel zu öffnen:
ssh -L 8096:127.0.0.1:8096 you@your-vps-ipRufen Sie nun http://localhost:8096 auf. Der Assistent führt Sie durch die Sprachauswahl und die Erstellung eines Admin-Benutzers mit einem starken Passwort — dieses Konto ist Ihr Server, verwenden Sie daher kein temporäres Passwort. Fügen Sie Ihre erste Bibliothek hinzu: Wählen Sie den Inhaltstyp Movies, geben Sie /media/Movies an (dies ist der Pfad innerhalb des Containers, nicht der Host-Pfad), und wiederholen Sie den Vorgang für Shows unter /media/Shows. Schließen Sie den Vorgang ab, und Jellyfin startet den Scan. Bei einer kleinen Bibliothek werden Poster und Titel innerhalb von ein bis zwei Minuten geladen. Sie können Bibliotheken später unter Dashboard → Libraries hinzufügen oder bearbeiten. Erzwingen Sie einen erneuten Scan mit Scan All Libraries.
Falls Sie Transcoding nutzen, öffnen Sie Dashboard → Playback → Transcoding und setzen Sie den Pfad für temporäre Transcode-Dateien auf /cache/transcodes. Dadurch werden die temporären Daten auf dem Cache-Volume gespeichert, anstatt /config zu füllen. Lassen Sie die Hardwarebeschleunigung auf None eingestellt — es ist keine GPU zur Beschleunigung vorhanden.
Fernzugriff: TLS-Reverse-Proxy oder VPN nutzen
Es gibt zwei sichere Methoden, um von extern auf Jellyfin zuzugreifen, und eine unsichere Methode, die vermieden werden sollte. Die unsichere Methode besteht darin, den Port 8096 direkt im Internet zu veröffentlichen: Die Anmeldedaten werden im Klartext übertragen und der Port wird innerhalb weniger Stunden per Brute-Force-Angriff angegriffen.
Option A — TLS-Reverse-Proxy. Platzieren Sie Jellyfin auf einer Subdomain hinter Traefik mit automatischem TLS für Ihre Docker-Apps oder hinter nginx mit einem von Certbot ausgestellten Let's Encrypt Zertifikat. Jellyfin nutzt WebSockets für Echtzeit-Updates; der Proxy muss daher die Upgrade-Header weiterleiten. Traefik erledigt dies automatisch. Bei nginx müssen diese explizit angegeben werden, zudem ist HTTP/1.1 zum Upstream erforderlich, damit der Upgrade-Vorgang funktioniert:
location / {
proxy_pass http://127.0.0.1:8096;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}Setzen Sie JELLYFIN_PublishedServerUrl auf die https:// Adresse, damit die lokale Autodiscovery die korrekte URL meldet — externe Apps nutzen die angegebene Adresse. Installieren Sie zudem fail2ban, um Brute-Force-Angriffe zu verlangsamen für den Login. Sobald der Server öffentlich erreichbar ist, richten Sie Uptime Kuma für die URL ein, um über Ausfallzeiten informiert zu werden, bevor es Ihre Zuschauer tun.
Option B — Privater Zugriff über ein VPN. Veröffentlichen Sie den Port 8096 überhaupt nicht. Greifen Sie nur über einen WireGuard-Tunnel zu, der auf demselben System endet. Für Privathaushalte ist dies die einfachste sichere Lösung — ohne Zertifikat, ohne öffentliche Exponierung und ohne Angriffsfläche für Brute-Force-Angriffe. Binden Sie den Container an die Tunnel-Adresse oder localhost und verbinden Sie sich über das VPN. Details zur Einrichtung des Tunnels finden Sie unter WireGuard VPN-Setup für einen privaten VPS.
Speicherplatzplanung und Backups
Planen Sie nach Dateigröße, nicht nach Dateianzahl. Komprimierte 1080p-Filme benötigen jeweils 4–15 GB; ein 1080p-Remux benötigt 20–40 GB; eine Staffel mit 1080p-Inhalten benötigt 15–40 GB; 4K-Inhalte liegen bei 40–100 GB pro Film. Eine Bibliothek mit einigen hundert Filmen und Serien benötigt ein Volume von 2–4 TB. Es ist kostengünstiger, das Block-Volume einmalig zu groß zu dimensionieren, als später Daten zu migrieren.
/config enthält den gesamten Server-Status und muss daher unbedingt gesichert werden. Erstellen Sie einen Snapshot oder nutzen Sie ein tar-Archiv und speichern Sie die Kopie extern:
docker compose down
sudo tar czf jellyfin-config-$(date +%F).tgz -C ~/jellyfin config
docker compose up -d/cache und der Transcode-Ordner sind entbehrlich. Die Medien auf /mnt/media sichern Sie separat oder akzeptieren deren Verlust, falls sie erneut gerippt werden können — aufgrund der Größe wählen die meisten Benutzer die zweite Option. Upgrades sind docker compose pull && docker compose up -d; das Tag :10 oben bleibt innerhalb der 10.x Major-Version. Ein Wechsel auf die nächste Major-Version erfordert eine bewusste Änderung des Tags — lesen Sie die Jellyfin Release Notes, bevor Sie dies tun, da Schema-Migrationen der Bibliothek bei Major-Versionen stattfinden.
Fehlerursachen und die angezeigten Meldungen
Die Bibliothek ist nach einem Scan leer. Das Log unter Dashboard → Logs (oder ~/jellyfin/config/log/log_*.log) zeigt:
System.UnauthorizedAccessException: Access to the path '/media/Movies' is denied.Die uid des Containers kann diesen Pfad nicht lesen. Ursache: Medien gehören root oder einer anderen uid als Ihrem user:-Wert, ein Verzeichnis hat das execute-Bit nicht gesetzt oder der übergeordnete Mount-Punkt ist für diese uid nicht durchlaufbar. Lösung: chown -R 1000:1000 /mnt/media, Verzeichnisse 755, Dateien 644, dann Rescan durchführen.
Wiedergabe belastet die CPU und puffert. docker stats jellyfin zeigt eine CPU-Auslastung von nahezu 100 % multipliziert mit der Anzahl Ihrer Kerne an, und Dashboard → Playback listet die Session als Transcode mit einer Geschwindigkeit unter 1.0x auf. Der Client nutzt kein Direct Play, daher transcodiert der VPS per CPU langsamer als in Echtzeit und verliert den Anschluss. Ursache: ein nicht unterstützter Codec oder Container, Subtitle Burn-in oder HDR Tone-Mapping. Lösung: Wechseln Sie zu einem Client mit Direct Play Unterstützung, behalten Sie Quellen in H.264/AAC bei, verwenden Sie text Untertitel (SRT) anstatt image Untertitel (PGS/VOBSUB), da diese ein Burn-in erzwingen, und vermeiden Sie 4K HDR auf Systemen, die nur über eine CPU verfügen.
"No compatible streams are available." Die vollständige Meldung lautet meist: "This client isn't compatible with the media and the server isn't sending a compatible media format." Der Client hat die Quelle abgelehnt und das Fallback-Transcoding konnte ebenfalls nicht starten. Ursache: ein fehlerhafter ffmpeg-Befehl, eine unlesbare Datei oder ein Benutzerprofil, das die Videokonvertierung blockiert. Lösung: Lesen Sie die ffmpeg-Zeile unter Dashboard → Logs, prüfen Sie, ob die Datei überhaupt abspielbar ist, kontrollieren Sie die Wiedergabe-Berechtigungen des Benutzers, falls Sie auf Transcoding angewiesen sind, und testen Sie einen anderen Client, um Browser-Codec-Probleme auszuschließen.
Filme haben kein Poster oder ein falsches Poster. Die Metadaten stimmen nicht überein. Ursache: ein Film befindet sich nicht in seinem eigenen Name (Year)-Ordner, ein Staffel-Ordner ist nach S01 statt Season 01 benannt, Episoden liegen nicht im S01E01-Format vor oder die Jahreszahl fehlt. Lösung: Benennen Sie die Ordner gemäß dem oben genannten Layout um, führen Sie dann Refresh metadata → Replace all aus oder nutzen Sie Identify für ein einzelnes Element, um den korrekten TMDB/TVDB-Eintrag festzulegen.
FAQ
Kann ein VPS Videos ohne GPU transcodieren?
Ja, aber nur über die CPU, und dies ist teuer. Ein einzelner 1080p Software-Transcode kann mehrere vCPUs auslasten. 4K oder HEVC erreichen meist nicht die Echtzeitrate, was zu Pufferschritten führt. Die beste Lösung ist, das Transcoding zu vermeiden: Behalten Sie Ihre Bibliothek in H.264/AAC und nutzen Sie Client-Apps mit Direct-Play-Unterstützung, damit der VPS nur Daten streamt. Mieten Sie eine GPU-Instanz nur, wenn Sie zwingend On-the-fly-Transcoding benötigen.
Warum ist meine Jellyfin-Bibliothek nach einem Scan leer?
Meistens liegt es an den Berechtigungen. Das offizielle jellyfin/jellyfin Image läuft unter dem von Ihnen festgelegten user: (oder root). Wenn die Dateien für diese UID nicht lesbar sind, bricht der Scan in den Access to the path ... is denied ab und überspringt diese Dateien. Korrigieren Sie die Besitzrechte mit chown -R 1000:1000 /mnt/media, vergeben Sie das Execute-Bit für Verzeichnisse (755) und führen Sie einen erneuten Scan durch. Prüfen Sie auch das übergeordnete Verzeichnis: Wenn die UID des Containers /mnt/media nicht durchlaufen kann, erreicht er die Bibliotheksordner nicht und die Anzeige bleibt leer. Die zweithäufigste Ursache ist eine Ordnerstruktur, die nicht den Anforderungen von Jellyfin entspricht.
Wie greife ich sicher und remote auf Jellyfin zu?
Es gibt zwei gute Optionen. Nutzen Sie einen TLS-Reverse-Proxy auf einer Subdomain, um Login und Stream zu verschlüsseln, und installieren Sie fail2ban. Exponieren Sie niemals den Port 8096 im Klartext, da Passwörter sonst unverschlüsselt gesendet werden. Alternativ halten Sie den Zugriff rein privat und nutzen nur ein VPN; dies ist die einfachste sichere Methode für Privathaushalte. Geben Sie den Apps direkt die öffentliche Adresse an. Die Autodiscovery basiert auf Local-Network-Broadcasts und funktioniert nicht für Clients aus dem Internet.
Wie viel Festplatte und Bandbreite benötigt ein Jellyfin VPS?
Der Speicherplatz hängt von der Qualität ab: Planen Sie 4–15 GB pro komprimiertem 1080p-Film, 20–40 GB pro Remux und 40–100 GB für 4K ein. Die meisten Bibliotheken benötigen daher ein Block-Volume von 2–4 TB. Die Bandbreite wird durch die Direct-Play-Bitrate bestimmt: 8–12 Mbps pro 1080p-Stream, deutlich mehr bei 4K. Stellen Sie sicher, dass die Port-Geschwindigkeit für die Anzahl der gleichzeitigen Zuschauer ausreicht, und beachten Sie das monatliche Transferlimit. Planen Sie CPU-Reserven ein, falls Sie transcodieren möchten; Priorisieren Sie Bandbreite vor CPU-Kernen, wenn Sie Direct-Play nutzen möchten.
Ist der Betrieb von Jellyfin auf einem VPS legal?
Jellyfin selbst ist kostenlose Open-Source-Software; der Betrieb ist völlig legal. Entscheidend ist der Inhalt: Streamen Sie nur Medien, an denen Sie die Rechte besitzen oder für die eine Lizenz vorliegt – also eigene Disc-Rips, Aufnahmen oder Dateien, für die Sie das Nutzungsrecht haben. Jellyfin liefert keine Medien aus und bietet keine Möglichkeit, diese zu erwerben; es ist ein Player für eine bereits vorhandene Bibliothek.