Pourquoi une seule machine pour quatre médiathèques
Sortir de Plex, de Google Photos, de Spotify ou d'Audible conduit presque toujours à un service par type de média. Un VPS unique ramène quatre mises à jour, quatre certificats et quatre sauvegardes à un point d'entrée, un réseau Docker et un plan de sauvegarde.
La difficulté n'est pas l'installation, que nos guides sur Immich, Jellyfin, Navidrome et Audiobookshelf détaillent déjà. La difficulté est le dimensionnement : Immich et le transcodage vidéo écrasent un petit serveur, alors que Navidrome et Audiobookshelf passent presque inaperçus. Cet article répond à une seule question : quelle machine, pour quelle bibliothèque.
Ce que vous gagnez à tout regrouper
- Un seul point d'entrée — un reverse proxy, un sous-domaine par service, des certificats obtenus et renouvelés automatiquement.
- Une RAM mutualisée — Navidrome et Audiobookshelf consomment peu, la mémoire laissée libre par l'un profite aux pics de l'autre.
- Un plan de sauvegarde unique — quatre dossiers de configuration, un dump PostgreSQL, un script.
- Une montée en charge verticale — quand la bibliothèque grossit, vous augmentez RAM, vCPU et disque du même VPS sans réinstaller la pile.
- Un accès root complet — vous choisissez la distribution, vous réglez le noyau, vous installez ce que la pile exige.
Le budget mémoire et processeur, service par service
Seuls les chiffres d'Immich et de Jellyfin viennent d'une documentation officielle ; les autres lignes sont des réglages de départ, à mesurer chez vous. Relevez vos valeurs une fois la pile en marche avec docker stats --no-stream, puis ajustez.
Immich est le poste dominant. Sa documentation donne 6 Go de RAM au minimum et 8 Go recommandés, 2 cœurs au minimum et 4 recommandés. Sur une machine à 4 Go, Immich tourne avec l'apprentissage automatique désactivé, et PostgreSQL demande au moins 2 Go si vous posez des limites Docker. Depuis la version 3, l'image d'apprentissage automatique sur amd64 exige le niveau de jeu d'instructions x86-64-v2 : vérifiez que le plan choisi l'expose.
Côté processeur, c'est l'indexation initiale qui sature, le temps de traiter la photothèque. Les autres services restent quasi invisibles tant que vous ne transcodez pas.
Budget de réservation par service
Faites défiler le tableau
| Service | RAM à réserver | Ce qui la fait grimper |
|---|---|---|
| Caddy (reverse proxy) | Réglage de départ : 100 Mo, à mesurer | Presque rien : le nombre de sous-domaines n'y change quasiment rien |
| Navidrome | Réglage de départ : 250 Mo, à mesurer | Les scans d'une grande bibliothèque et les clients qui demandent un transcodage audio |
| Audiobookshelf | Réglage de départ : 250 Mo, à mesurer | Les podcasts téléchargés automatiquement et les scans de métadonnées |
| Jellyfin en lecture directe | Réglage de départ : 1 Go, à mesurer (Jellyfin : 4 Go possibles sans interface, 8 Go recommandés) | Les analyses de bibliothèque et les images générées au premier passage |
| Jellyfin avec transcodage logiciel | Aucun chiffre officiel par flux : à mesurer avec un flux d'essai | Chaque flux converti en parallèle, surtout en HEVC ou avec incrustation de sous-titres |
| Immich (serveur, ML, PostgreSQL, Valkey) | 6 Go minimum, 8 Go recommandés | L'indexation initiale, la reconnaissance faciale, la recherche sémantique |
| Pile complète, une seule machine | 8 Go au moins (valeur recommandée d'Immich), 16 Go pour la marge : une estimation à vérifier | Les travaux Immich lancés pendant qu'un film est transcodé |
Le budget disque : calculez en Go avant de choisir
Le disque est le premier plafond d'un VPS multimédia, et il se calcule. Pour la vidéo, la formule est : débit en Mb/s multiplié par la durée en secondes, divisé par 8. Un film de deux heures à 8 Mb/s pèse environ 7 Go, à 4 Mb/s environ 3,6 Go. Pour la musique, un album de 45 minutes en MP3 à 320 kb/s fait environ 110 Mo ; en FLAC, comptez plutôt 300 à 500 Mo. Un audiolivre de 10 heures à 64 kb/s pèse près de 290 Mo.
Pour les photos, partez de 3 Mo par cliché : 10 000 photos occupent donc environ 30 Go, vidéos de téléphone en sus. La documentation d'Immich ajoute que les miniatures et les vidéos transcodées augmentent la taille de la photothèque de 10 à 20 % en moyenne.
Séparez ensuite ce qui doit être rapide de ce qui doit être grand. La base PostgreSQL d'Immich pèse typiquement de 1 à 3 Go, doit vivre sur un SSD local et jamais sur un partage réseau. La configuration de Jellyfin et d'Audiobookshelf aussi : Audiobookshelf déconseille expressément de placer son dossier de configuration sur un partage réseau, au risque de corrompre sa base SQLite. Les médias, eux, peuvent aller sur un volume séparé et plus grand.
Ne pas transcoder : la règle qui protège le petit VPS
Jellyfin distingue quatre modes de lecture, du plus léger au plus lourd : lecture directe, remux, flux direct et transcodage. Sa documentation décrit la lecture directe comme une livraison du fichier sans modification, avec presque aucune charge supplémentaire pour le serveur ; le transcodage vidéo est le mode le plus coûteux.
Sans carte graphique, tout transcodage vidéo passe par le processeur, et la documentation de Jellyfin rappelle qu'un GPU est toujours recommandé pour cela. Elle prévient aussi que le HEVC, le VP9 et l'AV1 peuvent être très exigeants en logiciel, tout comme le tone-mapping HDR vers SDR faute de GPU.
La règle pratique tient en trois gestes. Stockez vos films dans un format que vos appareils lisent nativement, typiquement H.264 en MP4 ou MKV. Convertissez une fois, en amont, les fichiers problématiques plutôt que de les convertir à chaque lecture. Et utilisez le réglage par utilisateur de Jellyfin pour interdire le transcodage audio et vidéo aux comptes qui n'en ont pas besoin. Pour vérifier qu'un flux ne consomme rien, lancez une lecture : le tableau de bord affiche le type de lecture, et le processeur doit rester au repos.
Assembler la pile : un réseau, un proxy, un sous-domaine par service
Créer les dossiers, les droits et le réseau partagé
Séparez médias, photos et configurations, donnez la propriété à l'utilisateur 1000 et créez le réseau que partageront tous les conteneurs :
sudo mkdir -p /srv/media/video /srv/media/music /srv/media/audiobooks /srv/photos /srv/stack/media /srv/stack/immichsudo mkdir -p /srv/stack/jellyfin/config /srv/stack/jellyfin/cache /srv/stack/navidrome/data /srv/stack/audiobookshelf/config /srv/stack/audiobookshelf/metadatasudo chown -R 1000:1000 /srv/stack /srv/photossudo chmod -R a+rX /srv/mediadocker network create edgePointer quatre sous-domaines vers le VPS
Créez quatre enregistrements A (jellyfin, music, books, photos) vers l'IPv4 du VPS. Caddy obtient les certificats seulement si les enregistrements A ou AAAA pointent vers le serveur et si les ports 80 et 443 sont ouverts de l'extérieur.
Écrire le compose des trois services légers
Dans
/srv/stack/media/compose.yaml, déclarez Jellyfin, Navidrome et Audiobookshelf. Aucun port n'est publié : seul Caddy parle au réseauedge. Les médias sont montés en lecture seule pour Jellyfin et Navidrome.services:jellyfin:image: jellyfin/jellyfinuser: 1000:1000volumes:- /srv/stack/jellyfin/config:/config- /srv/stack/jellyfin/cache:/cache- /srv/media/video:/media:rorestart: unless-stoppednetworks: [edge]navidrome:image: navidrome/navidrome:latestuser: 1000:1000volumes:- /srv/stack/navidrome/data:/data- /srv/media/music:/music:rorestart: unless-stoppednetworks: [edge]audiobookshelf:image: ghcr.io/advplyr/audiobookshelf:latestuser: 1000:1000volumes:- /srv/stack/audiobookshelf/config:/config- /srv/stack/audiobookshelf/metadata:/metadata- /srv/media/audiobooks:/audiobooksrestart: unless-stoppednetworks: [edge]Ajouter Caddy au même fichier
Complétez le fichier avec le service du proxy, puis les déclarations du réseau externe et du volume des certificats :
caddy:image: caddy:2ports:- "80:80"- "443:443"volumes:- ./Caddyfile:/etc/caddy/Caddyfile:ro- caddy_data:/datarestart: unless-stoppednetworks: [edge]networks:edge:external: truevolumes:caddy_data:Écrire le Caddyfile, un bloc par service
Dans
/srv/stack/media/Caddyfile, un nom de domaine suffit à déclencher le TLS automatique, et Caddy redirige HTTP vers HTTPS tout seul :jellyfin.votre-domaine.com {reverse_proxy jellyfin:8096}music.votre-domaine.com {reverse_proxy navidrome:4533}books.votre-domaine.com {reverse_proxy audiobookshelf:80}photos.votre-domaine.com {reverse_proxy immich_server:2283}Installer Immich avec son compose officiel
Téléchargez les deux fichiers de la dernière version, et ne modifiez pas le compose lui-même :
cd /srv/stack/immichwget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.ymlwget -O .env https://github.com/immich-app/immich/releases/latest/download/example.envDans
.env, réglez les trois valeurs ci-dessous (le mot de passe n'accepte que des lettres et des chiffres) :UPLOAD_LOCATION=/srv/photos/libraryDB_DATA_LOCATION=/srv/stack/immich/postgresDB_PASSWORD=<mot-de-passe-A-Za-z0-9>Brancher Immich sur le réseau commun
Créez
/srv/stack/immich/docker-compose.override.yml. Docker Compose le fusionne automatiquement avec le fichier officiel, qui reste intact et remplaçable à chaque mise à jour :services:immich-server:networks: [default, edge]networks:edge:external: trueDémarrer et vérifier chaque entrée
Lancez les deux piles, attendez l'émission des certificats, puis testez en-têtes HTTP et TLS. Vous devez obtenir un code 2xx ou 3xx sur HTTPS, jamais une erreur de certificat :
cd /srv/stack/media && docker compose up -dcd /srv/stack/immich && docker compose up -dcurl -I https://jellyfin.votre-domaine.comcurl -I https://photos.votre-domaine.comMesurer, puis régler Immich
Pendant l'indexation, relevez
docker stats --no-streamet la charge du processeur. Si la mémoire frôle le plafond, désactivez une fonction d'apprentissage automatique (recherche intelligente, reconnaissance faciale) dans les réglages d'administration, ou baissez la concurrence des tâches sans la porter au-delà du nombre de cœurs.
Sauvegarder chaque service, restaurer avant d'en avoir besoin
Le piège classique est de sauvegarder les photos sans la base : Immich ne scanne pas son dossier de bibliothèque, il se fie à sa base pour savoir ce qui existe. La documentation distingue les dossiers originaux (library, upload, profile), à sauvegarder impérativement, des dossiers régénérables (thumbs, encoded-video).
Immich produit aussi ses propres dumps de base, par défaut chaque jour à 2 h du matin, avec les 14 derniers conservés dans le dossier backups de l'emplacement de téléversement. Ils ne contiennent que des métadonnées, jamais les photos. Pour garantir la cohérence, arrêtez le conteneur du serveur pendant la sauvegarde ; sinon, sauvegardez la base d'abord, puis les fichiers.
Restauration, sur une machine de test, selon la procédure officielle (puis injection du dump dans psql). Attention : down -v efface toutes les données Immich de la machine où vous l'exécutez :
docker compose down -vdocker compose pulldocker compose createdocker start immich_postgres
Plan de sauvegarde par service
- Immich, base — un dump compressé hors du VPS :
docker exec -t immich_postgres pg_dump --clean --if-exists --dbname=immich --username=postgres | gzip > "/srv/backup/immich-db.sql.gz", en adaptant nom de base et utilisateur à votre.env. - Immich, fichiers —
library,uploadetprofilecopiés avecrsyncvers un stockage distant ;thumbsetencoded-videopeuvent être régénérés. - Jellyfin — le dossier
/srv/stack/jellyfin/config(bibliothèques, utilisateurs, métadonnées), conteneur arrêté le temps de l'archive. Le cache se reconstruit. - Navidrome —
/srv/stack/navidrome/data(base, listes de lecture, cache) ; la musique elle-même est votre source de vérité et se sauvegarde comme un dossier de fichiers. - Audiobookshelf —
/configet/metadata: la base SQLite et la progression d'écoute vivent dans le premier, les sauvegardes internes dans le second. - La restauration se teste — rejouez la procédure officielle d'Immich, détaillée au-dessus, sur une machine de test avant de vous y fier.
Dépannage : mémoire saturée, droits refusés, envois coupés
Les pannes de cette pile tiennent en deux familles : la mémoire, quand Immich et un transcodage se disputent les mêmes gigaoctets, et les droits, quand un conteneur non root ne peut pas lire ou écrire un dossier monté. Pour la première, commencez par chercher une trace du noyau avec dmesg -T | grep -i "out of memory" : si un processus Immich y figure, le noyau l'a tué faute de mémoire, et le conteneur repart en boucle. Pour la seconde, comparez toujours l'identifiant de l'utilisateur du conteneur au propriétaire des dossiers montés.
Les erreurs rencontrées et leur remède
- Immich redémarre en boucle sur un petit plan — le noyau tue le conteneur d'apprentissage automatique (cherchez
out of memorydansdmesg). Désactivez la recherche intelligente et la reconnaissance faciale, ou passez à un plan avec au moins 8 Go. can't set healthcheck.start_interval as feature require Docker Engine v25 or later— votre Docker est trop ancien. Mettez-le à jour, ou commentez la lignestart_intervaldans la sectiondatabasedu compose, comme l'indique la documentation d'Immich.- Téléversements de vidéos coupés après une minute — la documentation d'Immich relève un code 499 derrière Traefik avec le délai de lecture par défaut de 60 secondes, et recommande 600 secondes. Vérifiez le délai de votre proxy.
- Navidrome :
unable to open database file— le dossier/datan'est pas accessible en écriture. Donnez-en la propriété à l'identifiant défini par la directiveuser. - Navidrome démarre mais la bibliothèque reste vide, avec
permission denieddans les journaux — le dossier de musique n'est pas lisible : appliquezchmod -R a+rXsur/srv/media/music. - Jellyfin ne voit pas les films — l'utilisateur 1000 du conteneur ne peut pas lire le dossier monté. Testez avec
docker exec jellyfin ls /mediaet corrigez les droits ;PUIDetPGIDne fonctionnent pas avec ces images, seule la directiveusercompte.
Quel plan pour quelle médiathèque
Faites défiler le tableau
| Profil de bibliothèque | Plan conseillé | Marge et limite |
|---|---|---|
| Musique, audiolivres et quelques films en lecture directe, Immich sans apprentissage automatique, un ou deux utilisateurs | VPS Start : 2 vCPU, 4 GB, 50 GB SSD, à 99 DH/mois | Mémoire juste : Immich reste sans ML et le transcodage est à éviter ; le disque limite à quelques films (≈ 7 Go pour un film de deux heures à 8 Mb/s) |
| Photothèque familiale d'environ 10 000 clichés (30 à 36 Go) avec ML actif, musique et audiolivres, lecture directe | VPS Power : 4 vCPU, 8 GB, 100 GB SSD, à 299 DH/mois | Atteint les 8 Go recommandés pour Immich seul ; l'indexation initiale ralentit le reste |
| Pile complète à quatre services, deux ou trois utilisateurs, un transcodage ponctuel | VPS Business : 8 vCPU, 16 GB, 200 GB SSD, à 499 DH/mois | Confortable ; le disque devient le plafond dès que la vidéo dépasse quelques centaines de Go |
| Plusieurs flux transcodés en même temps | VPS Business au minimum, et la conversion en amont des fichiers | Sans GPU, ajouter des vCPU ne suffit pas : mieux vaut convertir une fois que transcoder à chaque lecture |
Mesurer avant de payer plus
Commencez par le plan que le tableau indique, lancez l'indexation d'Immich et relevez la mémoire avec docker stats --no-stream pendant une journée de pointe. Si la marge dépasse 30 %, vous avez la bonne taille ; si le noyau tue un conteneur, montez le plan. La scalabilité verticale du VPS évite la réinstallation : RAM et disque augmentent, vos dossiers /srv et vos composes restent en place.
La documentation officielle et la suite
Les valeurs de ce guide viennent de la documentation des éditeurs : prérequis d'Immich, sauvegarde et restauration d'Immich, choix du matériel pour Jellyfin, transcodage Jellyfin, Navidrome avec Docker et le HTTPS automatique de Caddy.
Pour choisir un autre proxy que Caddy, lisez notre comparatif Caddy, Traefik et Nginx Proxy Manager. Si vous quittez Plex, la démarche est détaillée dans notre guide de migration vers Jellyfin et Navidrome.