Pourquoi un conteneur LXC pour Jellyfin sur Proxmox
Jellyfin est un serveur multimédia open source : il diffuse films, séries, musique et photos depuis votre propre serveur vers un navigateur, une application mobile ou une Smart TV, sans abonnement ni compte tiers. Notre guide Jellyfin avec Docker sur un VPS Linux couvre le déploiement par Docker Compose. Ce guide prend l'autre cas, très courant chez les administrateurs de serveur dédié : un hyperviseur Proxmox VE sur lequel Jellyfin tourne dans un conteneur LXC.
Sur Proxmox, le conteneur LXC a deux atouts face à une machine virtuelle qui ferait tourner Docker. D'abord, il partage le noyau de l'hôte : pas de RAM réservée pour un second système, pas de couche de virtualisation entre le média et le processeur. Ensuite, le passthrough GPU se résume à passer un noeud de périphérique (/dev/dri/renderD128 pour un GPU Intel, /dev/nvidia0 pour une carte NVIDIA) au conteneur. Le même GPU reste utilisable par l'hôte et par d'autres conteneurs, là où une VM exige un passthrough PCI exclusif via VFIO.
Les versions de référence au moment de la rédaction : Proxmox VE 9.2, publié le 21 mai 2026 sur base Debian 13 avec le noyau Linux 7.0, et Jellyfin 12.4, publié le 26 octobre 2026. Les commandes de ce guide fonctionnent aussi sur Proxmox VE 8.2 et suivants, version qui a apporté le passthrough de périphériques dans l'interface web (la ligne de commande le gère depuis la 8.1). Si votre hyperviseur est encore en 8.x, consultez notre guide migrer Proxmox VE 8 vers 9.
| Critère | Conteneur LXC | Docker dans une VM | VM KVM dédiée |
|---|---|---|---|
| Noyau | Partagé avec l'hôte Proxmox | Noyau de la VM, puis Docker | Noyau de la VM |
| Surcharge mémoire | Quasi nulle, RAM allouée à la demande | RAM de la VM réservée en plus | RAM de la VM réservée |
| Accès GPU | Noeud /dev passé au conteneur, GPU partageable | Passthrough PCI exclusif de la carte, puis --device | Passthrough PCI exclusif |
| Isolation | Espaces de noms utilisateur (conteneur non privilégié) | Hyperviseur + conteneur | Hyperviseur |
| Sauvegarde | vzdump du conteneur | vzdump de la VM entière | vzdump de la VM entière |
| Mise à jour Jellyfin | apt upgrade dans le conteneur | docker compose pull | apt upgrade |
| Console et snapshots | Interface Proxmox | Interface Proxmox pour la VM, Docker pour le service | Interface Proxmox |
Prérequis
- Un serveur dédié sous Proxmox VE 8.2 ou supérieur, avec un accès root au shell de l'hôte (SSH ou console web) ;
- Un stockage pour la médiathèque : un répertoire sur l'hôte (dataset ZFS, volume LVM monté, disque dédié) ou un volume Proxmox créé pour l'occasion ;
- Pour le transcodage matériel, un GPU Intel avec Quick Sync Video ou une carte NVIDIA avec NVENC, visible sur l'hôte (voir plus bas) ;
- Environ 4 Go de RAM et 4 coeurs pour le conteneur, à ajuster selon le nombre de flux simultanés. Pour répartir les ressources entre vos VMs et conteneurs, voyez dimensionner Proxmox VE sur un serveur dédié.
Un point d'honnêteté sur le matériel : les processeurs Xeon des serveurs dédiés n'ont pas de GPU intégré. Sur une machine sans carte graphique, Jellyfin transcode en logiciel, et il faut compter de l'ordre de quatre coeurs par flux 1080p transcodé en temps réel. Le transcodage matériel suppose une carte PCIe (Intel Arc ou NVIDIA), ce qui est typiquement le cas d'une machine que vous assemblez vous-même et placez en housing GPU en datacenter.
Conteneur privilégié ou non privilégié
Proxmox crée par défaut un conteneur non privilégié (unprivileged: 1). Dans ce mode, les identifiants utilisateur du conteneur sont décalés sur l'hôte : le root du conteneur (UID 0) devient l'UID 100000 sur l'hôte, l'UID 1 devient 100001, et ainsi de suite. Un processus qui s'échapperait du conteneur n'aurait donc aucun droit sur l'hyperviseur. C'est le mode recommandé pour Jellyfin, un service exposé à des clients distants.
Un conteneur privilégié fait tourner son root avec le vrai UID 0 de l'hôte et ne s'appuie que sur AppArmor, seccomp et les espaces de noms. La documentation Proxmox le réserve aux environnements de confiance. Il n'est plus nécessaire pour le GPU : l'ancienne méthode, qui consistait à ajouter des lignes lxc.cgroup2.devices.allow et lxc.mount.entry dans /etc/pve/lxc/ID.conf d'un conteneur privilégié, ne concerne que Proxmox VE 7 et antérieurs. Depuis la 8.1, l'option dev0 passe un périphérique à un conteneur non privilégié en fixant l'UID, le GID et le mode du noeud côté conteneur.
Le décalage d'UID a une conséquence pratique sur le stockage : les fichiers d'un répertoire de l'hôte monté dans un conteneur non privilégié apparaissent comme appartenant à nobody (UID 65534) si leur propriétaire n'est pas dans la plage mappée. La section stockage règle ce point.
Créer le conteneur LXC
Depuis le shell de l'hôte Proxmox, mettez à jour la liste des templates et repérez le nom exact du template Debian 13 :
pveam update
pveam available --section system | grep debian-13
Téléchargez-le sur le stockage local en reprenant le nom affiché par la commande précédente :
pveam download local debian-13-standard_VERSION_amd64.tar.zst
Créez ensuite le conteneur. L'exemple utilise l'ID 110, quatre coeurs, 4 Go de RAM, un disque système de 16 Go sur local-lvm et une adresse IP statique sur le pont vmbr0. Remplacez le template, le réseau et le mot de passe par vos valeurs :
pct create 110 local:vztmpl/debian-13-standard_VERSION_amd64.tar.zst \
--hostname jellyfin \
--ostype debian \
--unprivileged 1 \
--cores 4 \
--memory 4096 \
--swap 512 \
--rootfs local-lvm:16 \
--net0 name=eth0,bridge=vmbr0,ip=192.0.2.110/24,gw=192.0.2.1 \
--onboot 1 \
--password 'MotDePasseRootDuConteneur'
pct start 110
pct enter 110
Pour un conteneur qui prend son adresse par DHCP, remplacez la partie adresse par ip=dhcp. L'option --ssh-public-keys permet de déposer une clé SSH au lieu d'un mot de passe. --onboot 1 démarre le conteneur avec l'hôte. La même création est possible depuis l'interface web (bouton Créer CT), avec les mêmes paramètres.
Une fois dans le conteneur, mettez les paquets à jour et installez les outils dont le script d'installation Jellyfin a besoin :
apt update && apt full-upgrade -y
apt install -y curl gnupg
Installer Jellyfin dans le conteneur
Jellyfin fournit un script officiel qui ajoute son dépôt apt et installe le serveur, l'interface web et sa version de FFmpeg. Le script prend en charge Debian bullseye, bookworm et trixie ainsi qu'Ubuntu focal, jammy et noble. Téléchargez-le avec sa somme de contrôle et vérifiez-la avant de l'exécuter en root :
curl -s https://repo.jellyfin.org/install-debuntu.sh -O
curl -s https://repo.jellyfin.org/install-debuntu.sh.sha256sum -O
sha256sum -c install-debuntu.sh.sha256sum
less install-debuntu.sh
bash install-debuntu.sh
La vérification doit afficher install-debuntu.sh: OK. À la fin de l'installation, le service jellyfin tourne sous l'utilisateur système jellyfin. Les répertoires du paquet Debian sont :
/var/lib/jellyfin: données (base SQLite, métadonnées, images) ;/etc/jellyfin: configuration ;/var/cache/jellyfin: cache et fichiers de transcodage temporaires ;/var/log/jellyfin: journaux ;/usr/lib/jellyfin-ffmpeg/ffmpeg: le FFmpeg compilé par le projet, seul binaire qui donne l'accélération matérielle complète.
Vérifiez que le service écoute sur le port HTTP par défaut, 8096 :
systemctl status jellyfin
ss -tlnp | grep 8096
L'assistant de première configuration est accessible sur http://IP_DU_CONTENEUR:8096 depuis le réseau de l'hôte. Créez le compte administrateur et passez l'étape des bibliothèques : la médiathèque n'est pas encore montée.
Stockage : monter la médiathèque dans le conteneur
Le disque système de 16 Go n'est pas fait pour accueillir des téraoctets de vidéos. Deux approches existent sur Proxmox : un bind mount d'un répertoire de l'hôte, ou un volume supplémentaire alloué sur un stockage Proxmox.
Le bind mount est le plus courant : la médiathèque vit sur l'hôte (par exemple un dataset ZFS /tank/media ou un disque monté sur /mnt/media) et le conteneur la voit sous /media. Depuis l'hôte, conteneur arrêté ou non :
pct set 110 --mp0 /mnt/media,mp=/media
Deux règles de la documentation Proxmox s'appliquent : le chemin source ne doit contenir aucun lien symbolique, et le contenu d'un bind mount n'est jamais inclus dans une sauvegarde vzdump. La médiathèque se sauvegarde donc à part (voir la dernière section).
Reste la question des droits. Dans un conteneur non privilégié, les fichiers de /mnt/media appartiennent sur l'hôte à des UID hors de la plage mappée et apparaissent comme nobody dans le conteneur. Jellyfin n'a besoin que de lire la médiathèque. Le plus simple est donc de rendre les fichiers lisibles par tous, sur l'hôte :
chmod -R o+rX /mnt/media
Si le conteneur doit aussi écrire (téléchargement de sous-titres dans le dossier des films, par exemple), donnez les fichiers à l'UID décalé correspondant. Le root du conteneur vaut 100000 sur l'hôte ; pour l'utilisateur jellyfin du conteneur, relevez son UID avec id -u jellyfin dans le conteneur et ajoutez 100000 :
# Exemple si id -u jellyfin renvoie 106 dans le conteneur
chown -R 100106:100106 /mnt/media
L'alternative est un volume Proxmox dédié, que vzdump sait sauvegarder si l'option backup=1 est activée sur le point de montage. La syntaxe STOCKAGE:TAILLE_EN_GIO crée le volume à la volée :
pct set 110 --mp1 local-lvm:500,mp=/media/local,backup=1
Redémarrez le conteneur puis ajoutez vos bibliothèques dans Jellyfin (Tableau de bord > Bibliothèques) en pointant vers /media/films, /media/series, etc. :
pct stop 110 && pct start 110
pct exec 110 -- ls -l /media
Passthrough GPU Intel : QSV et VA-API
Sur un GPU Intel, Jellyfin propose deux API d'accélération. QSV (Quick Sync Video) est l'option recommandée sur les GPU récents, pour les performances. VA-API sert aux GPU antérieurs à Broadwell : sous Linux, QSV n'est pris en charge qu'à partir de Broadwell (Core de 5e génération). Les capacités dépendent de la génération :
| Codec | Génération Intel minimale |
|---|---|
| H.264 8 bits | Tout GPU Intel avec Quick Sync Video |
| HEVC 8 bits | Gen 9 Skylake (Core 6e génération) |
| HEVC 10 bits | Gen 9.5 Kaby Lake (Core 7e génération), Apollo Lake, Gemini Lake |
| AV1 décodage 8/10 bits | Gen 12 Tiger Lake (Core 11e génération) |
| AV1 encodage 8/10 bits | Arc série A (DG2), Meteor Lake (Core Ultra) |
Une carte Intel Arc série A (A310, A380) est la façon la plus économique d'ajouter QSV à un serveur Xeon sans GPU intégré. La documentation Jellyfin demande un noyau 6.2 ou plus récent pour ces cartes, ce que Proxmox VE 9.2 et son noyau 7.0 couvrent largement.
Sur l'hôte Proxmox
Le pilote graphique vit dans le noyau de l'hôte, jamais dans le conteneur. Vérifiez que le GPU expose un périphérique de rendu DRI et installez l'outil de supervision Intel, utile pour confirmer plus tard que le transcodage passe bien par le GPU :
ls -l /dev/dri
apt install -y intel-gpu-tools
intel_gpu_top
Vous devez voir renderD128 (et renderD129 si une seconde carte est présente). S'il n'apparaît pas, activez le GPU intégré dans le BIOS ou vérifiez que la carte PCIe est détectée avec lspci | grep -i vga.
Le mode d'encodage Low-Power de certaines générations exige le firmware GuC/HuC. Comme le noyau est celui de l'hôte, l'option se règle sur l'hôte Proxmox, pas dans le conteneur. La documentation Jellyfin précise que cette étape n'est nécessaire que pour les processeurs Jasper Lake et Elkhart Lake, ou pour accélérer le tone mapping OpenCL, et que les Core 12e à 14e génération ainsi que les Arc série A l'activent déjà par défaut :
echo "options i915 enable_guc=2" > /etc/modprobe.d/i915.conf
update-initramfs -u && update-grub
reboot
Passer le périphérique au conteneur
Le noeud /dev/dri/renderD128 doit apparaître dans le conteneur avec un groupe que l'utilisateur jellyfin peut rejoindre. Relevez le GID du groupe render dans le conteneur :
pct exec 110 -- getent group render
Puis, sur l'hôte, passez le périphérique avec ce GID (l'exemple suppose render = 104 dans le conteneur, adaptez) :
pct set 110 --dev0 /dev/dri/renderD128,gid=104
pct stop 110 && pct start 110
L'équivalent dans l'interface web est Ressources > Ajouter > Passthrough de périphérique, avec le chemin du périphérique et le GID dans les options avancées. Seul l'utilisateur root de Proxmox peut ajouter un passthrough de périphérique.
Dans le conteneur
Installez le FFmpeg de Jellyfin (il embarque les pilotes Intel en espace utilisateur), le runtime OpenCL nécessaire au tone mapping HDR, puis ajoutez jellyfin au groupe render :
apt install -y jellyfin-ffmpeg8 intel-opencl-icd
usermod -aG render jellyfin
systemctl restart jellyfin
ls -l /dev/dri
/usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128
La sortie de vainfo doit mentionner le pilote iHD et lister les profils d'encodage et de décodage. Sur certaines versions, le groupe propriétaire du périphérique est video plutôt que render : adaptez le usermod. La documentation Jellyfin note que la version 23.xx ou supérieure d'intel-opencl-icd couvre les N95, N100 et Arc A380 ; vérifiez avec apt policy intel-opencl-icd.
Activez enfin l'accélération dans l'interface : Tableau de bord > Lecture > Transcodage, accélération matérielle Intel QuickSync (QSV) (ou VA-API sur un GPU ancien), périphérique /dev/dri/renderD128, puis décochez les codecs que votre génération ne gère pas d'après le tableau ci-dessus. Lancez une lecture en forçant une qualité inférieure dans le lecteur web et observez intel_gpu_top sur l'hôte : les moteurs Video doivent monter en charge.
Passthrough GPU NVIDIA : NVENC
Jellyfin accélère le transcodage avec NVENC/NVDEC sur les GPU NVIDIA depuis l'architecture Maxwell. HEVC 8 bits demande une Maxwell de 2e génération (GM206), l'encodage HEVC 10 bits une Pascal, le décodage AV1 une Ampere et l'encodage AV1 une Ada Lovelace. Certains modèles d'entrée de gamme comme la GT 1030 n'ont pas de NVENC : vérifiez la matrice de support NVIDIA avant d'acheter. Côté pilote, la documentation Jellyfin exige au minimum la version 520.56.06 sous Linux.
Le principe en LXC diffère d'une VM : le module noyau NVIDIA est chargé sur l'hôte Proxmox, et le conteneur ne reçoit que les bibliothèques utilisateur, dans exactement la même version que le module de l'hôte. Un décalage de version entre les deux, par exemple après une mise à jour apt de l'un sans l'autre, casse l'accès au GPU. C'est pourquoi on installe le même fichier .run des deux côtés.
Sur l'hôte Proxmox
Installez les en-têtes du noyau Proxmox et les outils de compilation, téléchargez le pilote depuis le site NVIDIA, puis lancez l'installeur avec enregistrement DKMS pour que le module soit recompilé à chaque mise à jour du noyau :
apt install -y proxmox-default-headers build-essential dkms
bash NVIDIA-Linux-x86_64-VERSION.run --dkms
nvidia-smi
ls -l /dev/nvidia*
Vous devez voir au minimum /dev/nvidia0, /dev/nvidiactl et /dev/nvidia-uvm. Si le noeud nvidia-uvm manque, créez-le avec l'utilitaire fourni par l'installeur :
nvidia-modprobe -u -c=0
Passer les périphériques au conteneur
Les noeuds NVIDIA sont par défaut accessibles en lecture-écriture à tous (mode 0666), il n'y a donc pas de GID à fixer. Passez-les un par un avec les options dev0, dev1, etc. Ajoutez /dev/nvidia-caps/nvidia-cap1 et nvidia-cap2 si ces noeuds existent sur votre hôte, la documentation Jellyfin les liste parmi les périphériques à exposer :
pct set 110 \
--dev0 /dev/nvidia0 \
--dev1 /dev/nvidiactl \
--dev2 /dev/nvidia-uvm \
--dev3 /dev/nvidia-uvm-tools
pct stop 110 && pct start 110
Dans le conteneur
Copiez le même fichier .run dans le conteneur (par exemple avec pct push 110 NVIDIA-Linux-x86_64-VERSION.run /root/ depuis l'hôte) et installez-le sans module noyau, puis installez le FFmpeg de Jellyfin :
bash /root/NVIDIA-Linux-x86_64-VERSION.run --no-kernel-module
nvidia-smi
apt install -y jellyfin-ffmpeg8
systemctl restart jellyfin
Si nvidia-smi affiche la carte dans le conteneur, activez NVIDIA NVENC dans Tableau de bord > Lecture > Transcodage et décochez les codecs non pris en charge par votre génération. Pour vérifier, lancez une lecture transcodée et relancez nvidia-smi : le processus /usr/lib/jellyfin-ffmpeg/ffmpeg doit apparaître dans la liste avec sa consommation de VRAM.
Accès réseau et reverse proxy
Jellyfin utilise trois ports : 8096/TCP pour HTTP, 8920/TCP pour HTTPS (inactif par défaut) et 7359/UDP pour la découverte automatique des clients sur le réseau local. La documentation Jellyfin recommande de terminer le TLS sur un reverse proxy plutôt que d'activer le port 8920.
Sur un serveur dédié, le conteneur a été créé sur vmbr0, le pont relié à la carte réseau physique. Deux situations :
- Vous disposez d'adresses IP supplémentaires : attribuez-en une au conteneur dans
net0. Le reverse proxy peut alors tourner dans le conteneur Jellyfin lui-même ; - Une seule IP publique : placez le conteneur sur un pont interne (
vmbr1avec un sous-réseau privé) et faites entrer le trafic par un reverse proxy qui écoute sur l'IP publique, dans un autre conteneur ou sur l'hôte. Notre guide SDN Proxmox et isolation réseau détaille la création de ces réseaux internes, et le guide Proxmox VE Helper Scripts montre comment déployer Nginx Proxy Manager dans un conteneur LXC en une commande.
Dans les deux cas, ne publiez jamais le port 8096 en clair sur Internet. Le pare-feu Proxmox, activé au niveau du conteneur (Pare-feu > Options), n'autorise que le reverse proxy à joindre le port 8096 :
# /etc/pve/firewall/110.fw
[OPTIONS]
enable: 1
[RULES]
IN ACCEPT -source 192.0.2.20 -p tcp -dport 8096 -log nolog
IN ACCEPT -p tcp -dport 22 -log nolog
Pour la configuration du reverse proxy lui-même (bloc location /socket pour les WebSockets, taille des requêtes), reprenez la section correspondante de notre guide Nginx en reverse proxy et obtenez le certificat avec Certbot et Let's Encrypt. Dernière étape, souvent oubliée : dans Tableau de bord > Réseau, renseignez l'adresse IP du reverse proxy dans Proxies connus. Sans cela, la documentation Jellyfin est explicite, les réglages d'accès externe derrière un reverse proxy ne fonctionnent pas et les journaux affichent l'IP du proxy à la place de celle des clients.
Sauvegarder et mettre à jour
La sauvegarde du conteneur passe par vzdump, depuis le shell de l'hôte ou depuis Datacenter > Sauvegarde pour une planification. Le mode snapshot évite d'arrêter Jellyfin :
vzdump 110 --mode snapshot --storage local --compress zstd
Cette archive contient le disque système, donc /var/lib/jellyfin (comptes, bibliothèques, progression de lecture) et /etc/jellyfin. Elle ne contient pas la médiathèque montée en bind mount : sauvegardez-la séparément, par exemple avec un rsync incrémental vers un serveur distant. Pour une stratégie complète sur l'hôte (Proxmox Backup Server, rétention, test de restauration), voyez sauvegardes et haute disponibilité d'un serveur dédié.
Avant toute mise à jour majeure de Jellyfin, prenez un snapshot du conteneur, puis mettez à jour par apt : le dépôt ajouté par le script d'installation fournit les nouvelles versions de jellyfin-server, jellyfin-web et jellyfin-ffmpeg8. Les migrations de base de données s'exécutent automatiquement au premier démarrage :
pct snapshot 110 avant-maj-jellyfin
pct exec 110 -- bash -c "apt update && apt upgrade -y"
pct exec 110 -- systemctl status jellyfin
Si la mise à jour pose problème, pct rollback 110 avant-maj-jellyfin revient à l'état précédent. Sur une installation NVIDIA, souvenez-vous que le pilote du conteneur doit suivre celui de l'hôte : après une mise à jour du pilote hôte, réinstallez la même version dans le conteneur avec --no-kernel-module. L'hôte lui-même se maintient avec les procédures de notre guide sécuriser et mettre à jour Proxmox VE.
Conclusion
Un conteneur LXC non privilégié est le bon format pour Jellyfin sur un hyperviseur Proxmox : démarrage en quelques secondes, aucune RAM gaspillée, et un passthrough GPU qui tient en une ligne dev0 pour un GPU Intel ou quelques noeuds pour une carte NVIDIA. Le stockage par bind mount garde la médiathèque sur le stockage de l'hôte, vzdump couvre la configuration, et le reverse proxy avec la liste des proxies connus sécurise l'accès distant. Si votre infrastructure n'est pas sous Proxmox, le guide Jellyfin avec Docker reste la référence ; et pour l'hôte, les premiers réglages de sécurité d'un serveur dédié s'appliquent avant d'exposer quoi que ce soit.
FiveM
Minecraft
Rust
RedM
Hytale