Aller au contenu
Perfect Homelab [E09] : LXC-Mediaserver(140) - Déployer une Stack Mediaserver complète avec Docker Compose (Jellyfin, Jellystat, Navidrome, Maloja, Music-Assistant, BookLore)
  1. Posts/

Perfect Homelab [E09] : LXC-Mediaserver(140) - Déployer une Stack Mediaserver complète avec Docker Compose (Jellyfin, Jellystat, Navidrome, Maloja, Music-Assistant, BookLore)

Fabien ALLAMANCHE
Auteur
Fabien ALLAMANCHE
Géomaticien @ Vienne Condrieu Agglomération
Sommaire
Perfect Homelab - Cet article fait partie d'une série.
Partie 9: Cet article

Perfect Homelab

Introduction
#

À l’heure où les services de streaming se multiplient et fragmentent vos bibliothèques multimédia, reprendre le contrôle de vos contenus numériques devient un enjeu majeur. Entre les abonnements coûteux, les restrictions géographiques et la dépendance aux plateformes, l’auto-hébergement d’un serveur multimédia offre une alternative séduisante : liberté totale, confidentialité garantie et coûts maîtrisés.

Dans cet article, nous allons apprendre à déployer une stack mediaserver complète et moderne qui combine streaming vidéo, streaming musical, gestion d’ebooks et analytics d’écoute. Nous allons couvrir l’installation de Jellyfin (serveur de streaming vidéo avec transcodage matériel iGPU Intel), Tiny Media Manager (gestion des métadonnées vidéo), Jellystat (statistiques et analytics Jellyfin), Navidrome (serveur de streaming musical compatible Subsonic), BookLore (gestion d’ebooks), Maloja (analytics d’écoute type Last.fm), Multi-Scrobbler (synchronisation des écoutes) et Music Assistant (contrôle multi-room et intégration Home Assistant).

Ce tutoriel suppose que vous avez déjà des connaissances en Docker et Docker Compose, un serveur Linux fonctionnel (VM ou conteneur LXC sous Proxmox par exemple), et une bibliothèque multimédia organisée (vidéos, musique et/ou livres).

L’architecture proposée s’intègre parfaitement dans un environnement homelab tel que présenté dans les articles précédents de cette série.

Table des matières
#

🖥️ Préparation du conteneur LXC Proxmox
#

Avant de déployer la stack mediaserver, créons un conteneur LXC dédié sous Debian 13 optimisé pour Docker.

Création du conteneur LXC en ligne de commande
#

Téléchargement du template Debian 13
#

Connectez-vous à votre serveur Proxmox via SSH et téléchargez le template Debian 13 :

# Télécharge le template Debian 13 dans le stockage local
pveam update
pveam download local debian-13-standard_13.0-1_amd64.tar.zst
Info : Le template Debian 13 est la dernière version stable de Debian, optimale pour Docker et les conteneurs.

Création du conteneur
#

Créez le conteneur LXC avec la commande pct create :

pct create 140 iso-morpheus:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst \
  --hostname mediaserver \
  --memory 8086 \
  --cores 4 \
  --rootfs datastore-zfs:64 \
  --net0 name=eth0,bridge=vmbr0,firewall=1,gw=10.10.20.1,ip=10.10.20.40/24,tag=20,type=veth \
  --nameserver 192.168.0.53 \
  --searchdomain home.allfabox.fr \
  --password \
  --unprivileged 0 \
  --features nesting=1,keyctl=1 \
  --onboot 1 \
  --startup order=4

Explication des paramètres :

Paramètre Valeur Description
ID 140 Identifiant unique du conteneur dans Proxmox
--hostname frontend Nom d’hôte du conteneur
--memory 8086 RAM allouée en MB (≈8 Go - dimensionnement pour Music Assistant + base de données)
--cores 2 Nombre de cœurs CPU dédiés
--rootfs datastore-zfs:32 Disque système de 32 GB sur le stockage ZFS datastore-zfs
--net0 Configuration réseau détaillée ci-dessous
--searchdomain home.allfabox.fr Domaine de recherche DNS local
--unprivileged 0 Conteneur privilégié (voir avertissement de sécurité)
--features nesting=1,keyctl=1 Nécessaire pour Docker dans LXC
--onboot 1 Démarre automatiquement au boot de Proxmox
--startup order=4 Ordre de démarrage (après les services réseau)

Détail de la configuration réseau (--net0) :

Paramètre Valeur Description
name eth0 Nom de l’interface réseau
bridge vmbr0 Bridge réseau Proxmox
firewall 1 Firewall activé
gw 10.10.20.1 Passerelle par défaut
ip 10.10.20.40/24 Adresse IP statique avec masque /24
tag 20 VLAN 20 (réseau Proxmox)
type veth Type d’interface réseau virtuelle

Attention : Les paramètres nesting=1 et keyctl=1 sont indispensables pour exécuter Docker dans un conteneur LXC. Sans ces options, Docker ne démarrera pas correctement.

Avertissement de sécurité : Conteneur LXC privilégié

Le paramètre --unprivileged 0 crée un conteneur privilégié, ce qui signifie que :

Risques de sécurité importants :

  • L’utilisateur root dans le conteneur correspond à l’utilisateur root de l’hôte Proxmox
  • Une compromission du conteneur peut entraîner une compromission complète de l’hôte Proxmox
  • Les processus du conteneur ont un accès quasi-illimité aux ressources système de l’hôte
  • En cas de faille de sécurité (CVE Docker, vulnérabilité applicative), un attaquant pourrait s’échapper du conteneur LXC

Pourquoi utiliser un conteneur privilégié ici ?

Dans certains cas, Docker dans un conteneur LXC non-privilégié peut rencontrer des problèmes de :

  • Mapping des UID/GID complexe
  • Permissions sur les volumes montés
  • Compatibilité avec certaines images Docker (notamment Music Assistant en mode host)

Recommandations de sécurité :

  1. Isolation réseau : Ce conteneur est placé dans le VLAN 20 (réseau Proxmox), séparé du réseau de confiance
  2. Pare-feu strict : N’autorisez que les ports nécessaires (4533, 6060, 42010, etc.)
  3. Mises à jour régulières : Appliquez systématiquement les mises à jour de sécurité (Debian, Docker, images)
  4. Monitoring actif : Surveillez les logs système et les comportements anormaux
  5. Snapshots réguliers : Effectuez des sauvegardes fréquentes avec vzdump avant toute modification
  6. Limitez l’accès SSH : Restreignez l’accès root au conteneur et utilisez des clés SSH plutôt que des mots de passe
  7. Principe du moindre privilège : N’exposez que les services strictement nécessaires

Alternative plus sécurisée :

Si votre environnement le permet, envisagez d’utiliser un conteneur non-privilégié (--unprivileged 1) avec un mapping d’UID/GID correct :

# Dans /etc/pve/lxc/140.conf (après création)
lxc.idmap: u 0 100000 1000
lxc.idmap: g 0 100000 1000
lxc.idmap: u 1000 1000 1
lxc.idmap: g 1000 1000 1
lxc.idmap: u 1001 101001 64535
lxc.idmap: g 1001 101001 64535

Cependant, cette configuration nécessite des ajustements supplémentaires pour Docker et peut compliquer le déploiement, notamment avec Music Assistant qui utilise network_mode: host.

Pour un environnement de production critique, privilégiez :

  • Une VM complète (plutôt qu’un conteneur LXC) avec isolation matérielle renforcée

Configuration avancée du conteneur LXC
#

Avant de démarrer le conteneur, configurons les points de montage et le transcodage matériel pour Jellyfin :

Ajout des points de montage (bind mounts)
#

Caractéristique clé de l’architecture Perfect Homelab

Les bind mounts LXC permettent de monter directement des répertoires de l’hôte Proxmox dans le conteneur. Cette approche est fondamentale dans l’architecture Perfect Homelab car elle permet :

Avantages des bind mounts vs NFS/SMB :

  • Performance native : Accès disque direct sans overhead réseau
  • Latence minimale : Pas de stack TCP/IP à traverser
  • Simplicité : Aucune configuration réseau ou firewall supplémentaire
  • Fiabilité : Pas de dépendance à un service réseau qui pourrait tomber
  • Permissions simplifiées : Mapping direct des UID/GID

Architecture MergerFS : Le pool /mnt/storage sur l’hôte Proxmox agrège plusieurs disques physiques en un système de fichiers unifié (voir Perfect Homelab E06). Les conteneurs LXC y accèdent directement comme s’il s’agissait d’un disque local.

Bind mounts depuis l’hôte Proxmox
#

# Monte le stockage média principal (pool MergerFS)
pct set 140 -mp0 /mnt/storage/media,mp=/mnt/media

# Monte le dossier de sauvegardes Restic
pct set 140 -mp1 /mnt/fast2/backups/restic/docker/appdata,mp=/mnt/backups/restic

Explication des paramètres :

Paramètre Description
-mp0 Numéro du mount point (0, 1, 2, etc.)
/mnt/storage/media Chemin source sur l’hôte Proxmox (pool MergerFS)
mp=/mnt/media Chemin destination dans le conteneur LXC

Astuce : Les bind mounts sont configurés dans /etc/pve/lxc/140.conf et persistent aux redémarrages. Vous pouvez les visualiser avec :

cat /etc/pve/lxc/140.conf | grep mp0

Transcodage matériel (iGPU Intel)
#

Pour permettre à Jellyfin d’utiliser le GPU Intel pour le transcodage matériel, nous devons passer les périphériques /dev/dri au conteneur :

# Vérification du GID du groupe render (doit être 104)
cat /etc/group | grep render

Sortie attendue : render:x:104:

Important : Le GID 104 est mappé dans la configuration Jellyfin (group_add: - 104) pour autoriser l’accès au GPU. Si votre système utilise un GID différent, ajustez le fichier docker-compose.yml de Jellyfin en conséquence.

Ajoutez les périphériques GPU au fichier de configuration du conteneur LXC :

# Ajoute les périphériques de transcodage iGPU Intel
cat >> /etc/pve/lxc/140.conf << 'EOF'
lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create=file
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
EOF

Explication des permissions :

Périphérique Description Permissions
c 226:0 /dev/dri/card0 - Contrôleur GPU principal rwm (read/write/mknod)
c 226:128 /dev/dri/renderD128 - Interface de rendu GPU rwm (read/write/mknod)
Astuce : Le paramètre optional dans lxc.mount.entry empêche le conteneur de crasher si le périphérique GPU n’est pas disponible (utile pour les migrations ou tests).

Ajout des tags Proxmox
#

Pour organiser vos conteneurs dans l’interface Proxmox, ajoutez des tags descriptifs :

# Ajoute les tags pour identification rapide
cat >> /etc/pve/lxc/140.conf << 'EOF'
tags: mediaserver;jellies;prod
EOF

Tags utilisés :

  • mediaserver : Indique que c’est un serveur multimédia
  • jellies : Référence à Jellyfin (nom du projet)
  • prod : Environnement de production

Démarrage du conteneur
#

# Démarre le conteneur
pct start 140

# Vérifie le statut
pct status 140

# Entre dans le conteneur
pct enter 140

Sortie attendue :

starting container...
container started
Vérification du transcodage matériel
#

Une fois dans le conteneur, vérifiez que les périphériques GPU sont bien montés :

# Vérifie la présence des périphériques DRI
ls -la /dev/dri/

# Vérifie que le groupe render est accessible
getent group render

Sortie attendue :

drwxr-xr-x 2 root root       100 Dec  5 10:00 .
drwxr-xr-x 5 root root       340 Dec  5 10:00 ..
crw-rw---- 1 root render 226,   0 Dec  5 10:00 card0
crw-rw---- 1 root render 226, 128 Dec  5 10:00 renderD128
Succès : Si vous voyez card0 et renderD128 avec les bonnes permissions (groupe render), le transcodage matériel Jellyfin est prêt !

Configuration initiale du conteneur
#

Une fois dans le conteneur, effectuez la configuration de base :

Mise à jour du système
#

# Met à jour les dépôts et le système
apt update
apt upgrade -y
Astuce : Cette opération peut prendre quelques minutes lors de la première mise à jour. Profitez-en pour vérifier la connectivité réseau avec ping google.com.

Installation de Docker et Docker Compose
#

# Installe les dépendances
apt install -y ca-certificates curl gnupg lsb-release

# Ajoute la clé GPG officielle de Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

# Ajoute le dépôt Docker aux sources Apt
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

apt update

# Installation des paquets Docker
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Vérifie l'installation
systemctl status docker
docker --version
docker compose version

Versions attendues :

Docker version 27.x.x
Docker Compose version 2.x.x
Succès : Si Docker affiche active (running) et que les versions s’affichent correctement, l’installation est réussie !

Création de l’utilisateur pour la stack
#

Créez un utilisateur dédié (UID 1000) pour gérer la stack mediaserver :

# Crée l'utilisateur avec UID 1000
useradd -m -u 1000 -s /bin/bash mediaserver

# Définit un mot de passe
passwd mediaserver

# Ajoute l'utilisateur au groupe docker
usermod -aG docker mediaserver

# Ajoute l'utilisateur au groupe sudo (optionnel)
usermod -aG sudo mediaserver
Astuce : L’UID 1000 est important car il correspond généralement au premier utilisateur non-root sur les systèmes Linux, facilitant la gestion des permissions sur les volumes Docker.

Création de la structure de dossiers
#

# Crée le répertoire de travail principal
mkdir -p /opt/docker/mediaserver-stack

# Donne les droits à l'utilisateur (UID 1000)
chown -R 1000:1000 /opt/docker
chmod -R 755 /opt/docker
Rappel : Tous les fichiers de la stack mediaserver seront stockés dans /opt/docker/mediaserver-stack.

Vérification des montages de médias (bind mounts LXC)
#

Architecture Perfect Homelab : Stockage unifié MergerFS

Dans l’architecture Perfect Homelab, les médias sont stockés sur un pool MergerFS unifié directement monté sur l’hôte Proxmox (voir Perfect Homelab E06 : Post-Installation [Données et stockage]).

Avantage clé : Les conteneurs LXC peuvent accéder directement à ce stockage via bind mounts (montages directs depuis l’hôte), éliminant :

  • La latence réseau du NFS/SMB
  • La complexité de configuration réseau
  • Les problèmes de permissions
  • Le overhead protocole

Les montages ont été configurés lors de la création du conteneur LXC :

pct set 140 -mp0 /mnt/storage/media,mp=/mnt/media

Cette approche offre des performances natives (accès disque direct) tout en conservant la flexibilité de MergerFS pour étendre le stockage.

Vérifiez que les montages bind sont actifs dans le conteneur :

# Vérifie les points de montage
df -h | grep media

# Vérifie l'accès aux médias
ls -lah /mnt/media/
ls -lah /mnt/media/musics/
ls -lah /mnt/media/books/
ls -lah /mnt/media/videos/

Sortie attendue :

/mnt/media            4.0T  2.1T  1.9T  53% /mnt/media
Succès : Si vous voyez le pool MergerFS monté et pouvez lister vos fichiers, le bind mount fonctionne correctement !

Rappel architecture : Le pool /mnt/storage sur l’hôte Proxmox agrège plusieurs disques physiques via MergerFS, offrant :

  • Extensibilité : Ajoutez des disques à la volée sans réorganiser les données
  • Flexibilité : Mélangez tailles et systèmes de fichiers (ext4, xfs)
  • Simplicité : Vu comme un seul système de fichiers par les conteneurs LXC
  • Performance : Accès direct sans couche réseau

Pour plus de détails sur la configuration MergerFS, consultez l’article Perfect Homelab E06.

Vérification finale de la configuration
#

# Vérifie que Docker fonctionne avec l'utilisateur non-root
su - mediaserver
docker run --rm hello-world

Sortie attendue :

Hello from Docker!
This message shows that your installation appears to be working correctly.
Conteneur LXC prêt ! Vous pouvez maintenant passer au déploiement de la stack mediaserver.

🔭 Vue d’ensemble de l’architecture
#

Cette stack mediaserver compose un écosystème multimédia complet et autonome, intégrant streaming vidéo et musical, gestion de livres numériques, analytics de vue et d’écoute et contrôle multi-room dans une architecture Docker unifiée.

Schéma de l’architecture
#

graph TB
    subgraph streaming[Streaming Musical]
        NAV["Navidrome
Serveur Subsonic"] MA["Music Assistant
Multi-room"] MR["Metadata Remote
Contrôle distant"] end subgraph video[Streaming Vidéo] JF["Jellyfin
Serveur Média + iGPU"] TMM["Tiny Media Manager
Gestion métadonnées"] JFS["Jellystat
Statistiques"] end subgraph livres[Gestion Livres] BL["BookLore
Lecteur moderne"] BLDB[("MariaDB
Base BookLore")] end subgraph analytics[Analytics & Scrobbling] MS["Multi-Scrobbler
Collecteur"] MAL["Maloja
Analytics"] end subgraph stockage[Stockage] MUSIC["/mnt/media/musics"] BOOKS["/mnt/media/books"] VIDEOS["/mnt/media/videos"] end NAV -.->|Scrobble| MS MS -->|Store| MAL BL -->|Database| BLDB JFS -.->|Stats API| JF NAV -->|Read| MUSIC MR -->|Read| MUSIC BL -->|Read| BOOKS JF -->|Stream| VIDEOS TMM -->|Manage| VIDEOS style NAV fill:#bbdefb,stroke:#1976d2,stroke-width:2px,color:#000 style MA fill:#c5e1a5,stroke:#689f38,stroke-width:2px,color:#000 style BL fill:#fff9c4,stroke:#fbc02d,stroke-width:2px,color:#000 style MAL fill:#f8bbd0,stroke:#c2185b,stroke-width:2px,color:#000 style BLDB fill:#b2dfdb,stroke:#00796b,stroke-width:2px,color:#000 style JF fill:#d1c4e9,stroke:#673ab7,stroke-width:2px,color:#000 style TMM fill:#e1bee7,stroke:#9c27b0,stroke-width:2px,color:#000 style JFS fill:#b3e5fc,stroke:#0288d1,stroke-width:2px,color:#000

Légende :

  • Navidrome : Serveur de streaming musical compatible protocole Subsonic
  • Music Assistant : Hub musical multi-room avec intégration Home Assistant (automatisations, contrôle vocal)
  • Jellyfin : Serveur de streaming vidéo avec transcodage matériel iGPU Intel
  • Tiny Media Manager : Gestionnaire de métadonnées pour films et séries TV
  • Jellystat : Outil d’analyse et de statistiques pour Jellyfin
  • BookLore : Gestionnaire et lecteur d’ebooks moderne avec base de données
  • Maloja : Analytics d’écoute type Last.fm auto-hébergé
  • Multi-Scrobbler : Pont de synchronisation entre Navidrome et Maloja

Services composant la stack
#

Service Rôle Port(s) Image Docker
Navidrome Serveur de streaming musical (Subsonic API) 4533 deluan/navidrome:latest
Music Assistant Hub musical multi-room + intégration Home Assistant 8095 ghcr.io/music-assistant/server:latest
Jellyfin Serveur de streaming vidéo (transcodage iGPU) 8096, 7359/udp jellyfin/jellyfin
Tiny Media Manager Gestion métadonnées films/séries 5900 (VNC), 4000 tinymediamanager/tinymediamanager:latest
Jellystat Statistiques et analytics Jellyfin 3000 cyfershepard/jellystat:latest
BookLore Gestionnaire et lecteur d’ebooks 6060 booklore/booklore:latest
BookLore-DB Base de données MariaDB pour BookLore - lscr.io/linuxserver/mariadb:11.4.5
Maloja Analytics et statistiques d’écoute 42010 krateng/maloja:latest
Multi-Scrobbler Synchronisation scrobbling Navidrome → Maloja 9078 foxxmd/multi-scrobbler
Metadata Remote Contrôle distant des métadonnées musicales 8338 ghcr.io/wow-signal-dev/metadata-remote:latest

Architecture de stockage (Perfect Homelab)
#

L’architecture Perfect Homelab utilise MergerFS sur l’hôte Proxmox pour créer un pool de stockage unifié, accessible directement par les conteneurs LXC via bind mounts.
graph TB
    subgraph proxmox["Hote Proxmox"]
        DISK1["Disque 1
/mnt/data01"] DISK2["Disque 2
/mnt/data02"] DISK3["Disque 3
/mnt/data03"] DISK1 --> MFS["MergerFS Pool
/mnt/storage"] DISK2 --> MFS DISK3 --> MFS MFS --> MEDIA["/mnt/storage/media"] end subgraph lxc["Conteneur LXC 140"] BIND["Bind Mount
/mnt/media"] BIND --> MUSICS["/mnt/media/musics"] BIND --> BOOKS["/mnt/media/books"] BIND --> VIDEOS["/mnt/media/videos"] MUSICS --> NAV["Navidrome"] BOOKS --> BL["BookLore"] VIDEOS --> JF["Jellyfin"] end MEDIA -.->|"pct set 140 -mp0"| BIND style proxmox fill:#e3f2fd,stroke:#1976d2,stroke-width:3px,color:#000 style lxc fill:#f1f8e9,stroke:#689f38,stroke-width:3px,color:#000 style MFS fill:#fff9c4,stroke:#f57c00,stroke-width:2px,color:#000 style BIND fill:#ffe0b2,stroke:#e64a19,stroke-width:2px,color:#000 style MEDIA fill:#fff3e0,stroke:#ff6f00,stroke-width:2px,color:#000

Avantages de cette architecture :

Caractéristique Bénéfice
Bind mounts LXC Accès disque direct = performance native
Pool MergerFS Agrégation flexible de plusieurs disques
Pas de NFS/SMB Élimination de la latence réseau
Extensibilité Ajoutez des disques sans réorganiser les données
Simplicité Un seul point de montage /mnt/media dans le conteneur

Référence : Cette architecture de stockage a été détaillée dans Perfect Homelab E06 : Post-Installation [Données et stockage], où MergerFS et SnapRAID sont configurés sur l’hôte Proxmox en baremetal.

Le bind mount pct set 140 -mp0 /mnt/storage/media,mp=/mnt/media configure un montage transparent : le conteneur LXC voit /mnt/media comme un système de fichiers local, alors qu’il accède directement au pool MergerFS de l’hôte.

Flux de données
#

sequenceDiagram
    participant User as Utilisateur
    participant Client as Client Subsonic
    participant NAV as Navidrome
    participant MS as Multi-Scrobbler
    participant MAL as Maloja
    participant MUSIC as Stockage Musical

    User->>Client: Lecture d'un titre
    Client->>NAV: Requête API Subsonic
    NAV->>MUSIC: Récupération fichier audio
    MUSIC-->>NAV: Stream audio
    NAV-->>Client: Flux audio
    NAV->>MS: Notification lecture
    MS->>MAL: Scrobble écoute
    MAL-->>MS: Confirmation
    MS-->>NAV: OK

Le flux de données suit un parcours optimisé : l’utilisateur accède à sa musique via un client compatible Subsonic (mobile ou web), Navidrome diffuse le contenu depuis le pool MergerFS (monté via bind mount), et chaque écoute est automatiquement enregistrée dans Maloja via Multi-Scrobbler pour générer des statistiques détaillées. De même, Jellyfin accède aux vidéos et BookLore aux livres numériques directement depuis ce stockage unifié, garantissant des performances optimales grâce à l’accès disque direct sans couche réseau.

📋 Prérequis techniques
#

Logiciels requis
#

Assurez-vous d’avoir installé les outils suivants avant de commencer.
  • Docker : version 24.0+ Installer Docker
  • Docker Compose : version 2.0+ (inclus avec Docker Desktop)
  • Git : pour récupérer les fichiers de configuration (optionnel)
  • Proxmox avec MergerFS : pool de stockage unifié configuré sur l’hôte (voir Perfect Homelab E06)

Connaissances recommandées
#

Docker & conteneurs
Administration Linux
Gestion de fichiers
YAML et configuration

Configuration minimale
#

Composant Spécification
CPU 2 cœurs (4 cœurs recommandés pour le transcodage)
RAM 2 Go minimum (4 Go recommandés)
Disque 10 Go pour les conteneurs + espace pour vos médias
Système Linux (Ubuntu 20.04+, Debian 11+) ou système compatible Docker
Attention : Le stockage de vos médias (musique et livres) doit être accessible depuis l’hôte Docker. Prévoyez l’espace nécessaire selon la taille de votre bibliothèque.

Préparation du stockage
#

Vous devez disposer de :

  • Un répertoire contenant vos fichiers musicaux : /mnt/media/musics (à adapter)
  • Un répertoire contenant vos livres numériques : /mnt/media/books (à adapter)
  • Un répertoire contenant vos films et séries : /mnt/media/videos (à adapter)
Architecture Perfect Homelab : Ces chemins correspondent au pool MergerFS (/mnt/storage/media) de l’hôte Proxmox, monté dans le conteneur LXC via bind mount. Les médias sont directement accessibles depuis le stockage unifié sans passer par NFS/SMB.

📁 Structure du projet
#

Découvrez l’organisation des fichiers et dossiers du projet mediaserver.

Voici l’arborescence complète du projet :

mediaserver-stack/
├── docker-compose.yml          # Orchestration principale (include)
├── .env                        # Variables d'environnement
│
├── navidrome/
│   ├── docker-compose.yml     # Configuration Navidrome
│   └── data/                  # Base de données Navidrome
│       └── .gitkeep
│
├── music-assistant/
│   ├── docker-compose.yml     # Configuration Music Assistant
│   └── data/                  # Données Music Assistant
│       └── .gitkeep
│
├── jellyfin/
│   ├── docker-compose.yml     # Configuration Jellyfin
│   ├── config/                # Configuration et bibliothèques
│   └── cache/                 # Cache métadonnées
│       └── .gitkeep
│
├── tinymediamanager/
│   ├── docker-compose.yml     # Configuration Tiny Media Manager
│   └── data/                  # Configuration et cache TMM
│       └── .gitkeep
│
├── jellystat/
│   ├── docker-compose.yml     # Configuration Jellystat
│   └── data/                  # Sauvegardes base de données
│       └── .gitkeep
│
├── booklore/
│   ├── docker-compose.yml     # Configuration BookLore + MariaDB
│   ├── data/                  # Données BookLore
│   ├── bookdrop/              # Dépôt de livres à importer
│   └── mariadb/               # Base de données MariaDB
│       └── .gitkeep
│
├── scrobbler-analytics/
│   ├── docker-compose.yml     # Multi-Scrobbler + Maloja
│   ├── multi-scrobbler/
│   │   └── config.json        # Configuration du scrobbling
│   └── maloja/                # Données Maloja
│       └── .gitkeep
│
└── metadata-remote/
    └── docker-compose.yml     # Configuration Metadata Remote

Fichiers clés
#

Fichier Description
docker-compose.yml Fichier principal orchestrant tous les sous-stacks via include
.env Variables d’environnement (mots de passe, clés API)
navidrome/docker-compose.yml Configuration du serveur de streaming musical
booklore/docker-compose.yml Configuration du gestionnaire d’ebooks et sa base MariaDB
scrobbler-analytics/docker-compose.yml Configuration du système de scrobbling et analytics
scrobbler-analytics/multi-scrobbler/config.json Connexion Navidrome ↔ Maloja
Note : Les dossiers data/, mariadb/ et maloja/ sont exclus du versioning Git (fichiers .gitkeep uniquement). Vos données personnelles et configurations sensibles restent locales.

⚙️ Configuration des services
#

Service 1 : Navidrome - Serveur de streaming musical
#

Navidrome est un serveur de streaming musical open-source compatible avec l’API Subsonic, permettant d’écouter votre musique partout via des clients mobiles et web.

Rôle et responsabilités
#

Navidrome indexe votre bibliothèque musicale, extrait les métadonnées (tags ID3, pochettes), organise votre collection par artistes/albums/genres et diffuse vos morceaux à la demande. Compatible avec l’écosystème Subsonic, il fonctionne avec une large gamme de clients (DSub, Symfonium, Sonixd, Play:Sub, etc.). Il intègre également le transcodage à la volée pour adapter le débit selon la connexion.

Configuration Docker Compose
#

services:
  navidrome:
    container_name: navidrome
    image: deluan/navidrome:latest
    user: 1000:1000              # UID:GID de l'utilisateur hôte
    restart: unless-stopped
    ports:
      - 4533:4533                # Port web et API Subsonic
    volumes:
      - ./data:/data             # Base de données et cache
      - /mnt/media/musics:/music:ro  # Bibliothèque musicale (lecture seule)
    environment:
      - ND_SCANSCHEDULE=1h       # Scan automatique toutes les heures
      - ND_LOGLEVEL=info
      - ND_SESSIONTIMEOUT=24h    # Durée de session 24h
      - ND_DEFAULTLANGUAGE=fr    # Interface en français
      - ND_DEFAULTTHEME=Spotify-ish
      - ND_ENABLEDOWNLOADS=false # Désactive les téléchargements
      - ND_ENABLETRANSCODINGCONFIG=true
      - ND_TRANSCODINGCACHESIZE=1024MB
      - ND_AUTOIMPORTPLAYLISTS=false
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
ND_SCANSCHEDULE Fréquence du scan de la bibliothèque 1h Non
ND_LOGLEVEL Niveau de log (error, info, debug) info Non
ND_SESSIONTIMEOUT Durée de validité de la session 24h Non
ND_DEFAULTLANGUAGE Langue de l’interface en Non
ND_ENABLETRANSCODINGCONFIG Active la configuration du transcodage true Non
ND_TRANSCODINGCACHESIZE Taille du cache de transcodage 1024MB Non
Astuce : Pour économiser des ressources, vous pouvez désactiver le transcodage si vous écoutez uniquement depuis votre réseau local avec ND_ENABLETRANSCODINGCONFIG=false.

Volumes et persistance
#

  • ./data : Contient la base de données SQLite de Navidrome (artistes, albums, playlists, utilisateurs)
  • /mnt/media/musics : Montage en lecture seule de votre bibliothèque musicale (adapté au chemin de votre stockage)

Dépendances
#

Navidrome fonctionne de manière autonome et n’a pas de dépendances directes. Il peut cependant être couplé avec Multi-Scrobbler pour le tracking des écoutes.


Service 2 : Music Assistant - Contrôle multi-room et intégration Home Assistant
#

Music Assistant est une solution de contrôle multi-room moderne qui agrège plusieurs sources musicales (Navidrome, Spotify, Tidal, etc.) et diffuse sur plusieurs systèmes audio, avec une intégration native Home Assistant.

Rôle et responsabilités
#

Music Assistant agit comme un hub central pour gérer et diffuser votre musique sur différents équipements : enceintes connectées (Chromecast, AirPlay, Sonos), serveurs audio (Snapcast, DLNA), ou intégrations domotiques. Son rôle principal dans cette stack est de faciliter l’accès à la bibliothèque musicale Navidrome et piloter l’écoute de la musique via Home Assistant.

Il supporte le streaming haute résolution et le regroupement d’enceintes en zones synchronisées.

Intégration Home Assistant : Music Assistant s’intègre nativement avec Home Assistant pour créer des automatisations musicales avancées : réveil en musique, ambiances selon les scénarios, contrôle vocal via Alexa/Google Assistant, etc.

L’intégration complète de Music Assistant avec Home Assistant fera l’objet d’un prochain article de la série Perfect Homelab, détaillant la configuration des automatisations, des lecteurs multi-room et des scénarios domotiques musicaux.

Configuration Docker Compose
#

services:
  music-assistant:
    container_name: music-assistant
    image: ghcr.io/music-assistant/server:latest
    restart: unless-stopped
    network_mode: host          # Nécessaire pour la découverte réseau (mDNS)
    volumes:
      - ./data:/data/           # Configuration et cache
    environment:
      - LOG_LEVEL=info

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
LOG_LEVEL Niveau de log info Non
Attention : Music Assistant utilise network_mode: host pour permettre la découverte automatique des équipements réseau (mDNS, SSDP). Ce mode expose tous les ports de l’hôte, pensez à sécuriser l’accès avec un firewall.

Volumes et persistance
#

  • ./data : Configuration de Music Assistant, cache des pochettes et métadonnées

Service 3 : BookLore - Gestionnaire d’ebooks moderne
#

BookLore est un gestionnaire d’ebooks moderne avec lecteur intégré, support de multiples formats et interface responsive.

Rôle et responsabilités
#

BookLore offre une interface web élégante pour gérer et lire vos livres numériques. Il supporte EPUB, PDF, MOBI, CBZ/CBR et intègre un lecteur web performant avec sauvegarde de progression, annotations et personnalisation. Il utilise une base de données MariaDB pour stocker les métadonnées et l’historique de lecture.

Configuration Docker Compose
#

services:
  booklore:
    container_name: booklore
    image: booklore/booklore:latest
    restart: unless-stopped
    ports:
      - 6060:6060              # Interface web BookLore
    depends_on:
      booklore-db:
        condition: service_healthy  # Attend que MariaDB soit prêt
    volumes:
      - ./data:/app/data       # Données BookLore
      - ./bookdrop:/bookdrop   # Dossier de dépôt pour import automatique
      - /mnt/media/books:/books  # Bibliothèque de livres
    environment:
      - BOOKLORE_PORT=6060
      - DATABASE_URL=${DATABASE_URL}
      - DATABASE_USERNAME=${DB_USER}
      - DATABASE_PASSWORD=${DB_PASSWORD}
      - USER_ID=1000
      - GROUP_ID=1000
      - TZ=Europe/Paris
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
BOOKLORE_PORT Port d’écoute de l’application 6060 Non
DATABASE_URL URL JDBC de connexion MariaDB - Oui
DATABASE_USERNAME Utilisateur de la base - Oui
DATABASE_PASSWORD Mot de passe de la base - Oui
USER_ID / GROUP_ID UID/GID pour les permissions fichiers 1000 Non
TZ Fuseau horaire Europe/Paris Non
Attention : Les variables de connexion à la base de données doivent correspondre exactement à celles définies dans le service booklore-db.

Volumes et persistance
#

  • ./data : Données applicatives BookLore
  • ./bookdrop : Dossier de dépôt pour importer automatiquement de nouveaux livres
  • /mnt/media/books : Bibliothèque de livres numériques

Service 4 : BookLore-DB - Base de données MariaDB
#

Base de données relationnelle MariaDB dédiée au stockage des métadonnées et de l’historique de lecture de BookLore.

Rôle et responsabilités
#

Ce conteneur MariaDB (version 11.4.5) stocke toutes les données structurées de BookLore : catalogue des livres, métadonnées extraites, progression de lecture, annotations utilisateurs et configuration applicative. Un healthcheck garantit que la base est opérationnelle avant le démarrage de BookLore.

Configuration Docker Compose
#

services:
  booklore-db:
    container_name: booklore-db
    image: lscr.io/linuxserver/mariadb:11.4.5
    restart: unless-stopped
    volumes:
      - ./mariadb/config:/config  # Données MariaDB
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
    healthcheck:
      test: [ "CMD", "mariadb-admin", "ping", "-h", "localhost" ]
      interval: 5s
      timeout: 5s
      retries: 10
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
MYSQL_ROOT_PASSWORD Mot de passe root MariaDB - Oui
MYSQL_DATABASE Nom de la base à créer - Oui
MYSQL_USER Utilisateur applicatif - Oui
MYSQL_PASSWORD Mot de passe utilisateur - Oui
Astuce : Utilisez des mots de passe robustes générés aléatoirement pour sécuriser l’accès à la base de données.

Volumes et persistance
#

  • ./mariadb/config : Fichiers de configuration et données MariaDB (bases, tables, index)

Service 5 : Maloja - Analytics d’écoute
#

Maloja est un serveur d’analytics musical auto-hébergé, alternative open-source à Last.fm pour tracker vos habitudes d’écoute.

Rôle et responsabilités
#

Maloja enregistre toutes vos écoutes musicales (scrobbles) et génère des statistiques détaillées : tops artistes/albums/titres, graphiques d’écoute, découvertes musicales, etc. Il offre une API compatible avec les clients Last.fm tout en préservant votre vie privée puisque les données restent sur votre serveur.

Configuration Docker Compose
#

services:
  maloja:
    container_name: maloja
    image: krateng/maloja:latest
    restart: unless-stopped
    ports:
      - 42010:42010            # Interface web Maloja
    volumes:
      - ./maloja:/data         # Base de données Maloja
    environment:
      - MALOJA_FORCE_PASSWORD=${MALOJA_FORCE_PASSWORD}
      - MALOJA_DATA_DIRECTORY=/data
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
MALOJA_FORCE_PASSWORD Mot de passe d’administration - Oui
MALOJA_DATA_DIRECTORY Répertoire de données /data Non
Attention : Définissez un mot de passe robuste pour protéger l’accès à vos statistiques personnelles.

Volumes et persistance
#

  • ./maloja : Base de données des scrobbles et configuration

Service 6 : Multi-Scrobbler - Synchronisation des écoutes
#

Multi-Scrobbler fait le pont entre Navidrome et Maloja pour enregistrer automatiquement vos écoutes musicales.

Rôle et responsabilités
#

Multi-Scrobbler surveille vos écoutes sur Navidrome (via l’API Subsonic) et les transmet à Maloja pour archivage et génération de statistiques. Il supporte plusieurs sources et destinations simultanément, permettant de centraliser le tracking depuis différents lecteurs vers plusieurs services d’analytics.

Configuration Docker Compose
#

services:
  multi-scrobbler:
    container_name: multi-scrobbler
    image: foxxmd/multi-scrobbler
    restart: unless-stopped
    ports:
      - 9078:9078              # Interface web de monitoring
    volumes:
      - ./multi-scrobbler:/config  # Configuration JSON
    environment:
      - BASE_URL=http://10.10.20.41:9078  # URL publique du scrobbler
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
BASE_URL URL d’accès au scrobbler - Non
PUID / PGID UID/GID pour permissions 1000 Non
TZ Fuseau horaire Europe/Paris Non
Astuce : L’URL BASE_URL doit être accessible depuis Navidrome si vous utilisez les webhooks. Sinon, le polling API Subsonic est utilisé.

Configuration du scrobbling
#

Le fichier ./multi-scrobbler/config.json configure les sources (Navidrome) et destinations (Maloja) :

{
  "sources": [
    {
      "type": "subsonic",
      "name": "Navidrome",
      "data": {
        "url": "http://navidrome:4533",
        "user": "navidrome_user",
        "password": "navidrome_password"
      }
    }
  ],
  "clients": [
    {
      "type": "maloja",
      "name": "Allfabox Maloja",
      "data": {
        "url": "http://maloja:42010",
        "apiKey": "maloja_api_key_here"
      }
    }
  ]
}
Attention : Remplacez navidrome_user, navidrome_password et maloja_api_key_here par vos vraies informations d’authentification.

Volumes et persistance
#

  • ./multi-scrobbler : Fichier de configuration config.json

Service 7 : Metadata Remote - Contrôle distant des métadonnées
#

Metadata Remote permet de contrôler et modifier les métadonnées musicales à distance via une interface web.

Rôle et responsabilités
#

Ce service expose une API web permettant de visualiser et éditer les tags ID3 de votre bibliothèque musicale depuis n’importe quel navigateur. Utile pour corriger des métadonnées sans accéder directement au serveur ou utiliser un logiciel lourd.

Configuration Docker Compose
#

services:
  metadata-remote:
    container_name: metadata-remote
    image: ghcr.io/wow-signal-dev/metadata-remote:latest
    restart: unless-stopped
    ports:
      - 8338:8338              # Interface web
    volumes:
      - /mnt/media/musics:/music  # Bibliothèque musicale
    environment:
      - PUID=1000
      - PGID=1000
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
PUID / PGID UID/GID pour permissions 1000 Non

Volumes et persistance
#

  • /mnt/media/musics : Bibliothèque musicale (montage en lecture/écriture pour édition des tags)
Info : Contrairement à Navidrome qui monte la bibliothèque en lecture seule, Metadata Remote nécessite l’accès en écriture pour modifier les tags.

Service 8 : Jellyfin - Serveur de streaming vidéo
#

Jellyfin est un serveur multimédia open-source offrant streaming vidéo, audio et photos avec transcodage matériel et applications clients multiplateformes.

Rôle et responsabilités
#

Jellyfin transforme votre bibliothèque de films et séries en plateforme de streaming personnelle, alternative libre à Plex ou Emby. Il organise automatiquement vos médias, récupère les métadonnées et pochettes depuis TMDB/TheTVDB, et transcode à la volée pour s’adapter à vos appareils. Dans cette configuration, le transcodage matériel via iGPU Intel permet de gérer plusieurs flux simultanés sans saturer le CPU.

Configuration Docker Compose
#

services:
  jellyfin:
    container_name: jellyfin
    image: jellyfin/jellyfin
    network_mode: host              # Nécessaire pour découverte DLNA/UPnP
    restart: unless-stopped
    group_add:
      - 104                         # Groupe render pour accès GPU
    devices:
      - /dev/dri/renderD128:/dev/dri/renderD128  # iGPU Intel
    volumes:
      - ./config:/config            # Configuration Jellyfin
      - ./cache:/cache              # Cache métadonnées
      - /mnt/media/videos:/media    # Bibliothèque vidéo
      - /dev/shm/transcodes:/cache/transcodes  # Transcodage en RAM
    environment:
      - JELLYFIN_PublishedServerUrl=http://jellyfin.mydomain.com
    extra_hosts:
      - host.docker.internal:host-gateway

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
JELLYFIN_PublishedServerUrl URL publique du serveur - Non (recommandé)

Important - Configuration iGPU :

  • Le paramètre group_add: - 104 correspond au GID du groupe render vérifié lors de la configuration LXC
  • Le périphérique /dev/dri/renderD128 est monté depuis l’hôte Proxmox via la configuration LXC
  • Si votre système utilise un GID différent, ajustez cette valeur après avoir vérifié avec getent group render

Volumes et persistance
#

  • ./config : Configuration Jellyfin (utilisateurs, bibliothèques, plugins)
  • ./cache : Cache des métadonnées et images
  • /mnt/media/videos : Bibliothèque vidéo (films, séries, etc.)
  • /dev/shm/transcodes : Stockage temporaire en RAM pour transcodage (améliore les performances et réduit l’usure SSD)
Astuce - Transcodage en RAM : Le montage /dev/shm utilise la RAM comme stockage temporaire pour les fichiers transcodés, éliminant les I/O disque et accélérant significativement le transcodage. Assurez-vous d’avoir suffisamment de RAM (8 Go recommandés).

Configuration du transcodage matériel
#

Une fois Jellyfin démarré, activez le transcodage iGPU :

  1. Accédez à Dashboard → Playback → Transcoding
  2. Sélectionnez Hardware acceleration : Intel Quick Sync (QSV)
  3. Cochez les codecs supportés : H.264, HEVC (H.265), VP9
  4. Appliquez et redémarrez Jellyfin

Vérification :

Prérequis : Installez d’abord l’outil intel-gpu-tools :

Dans le conteneur LXC :

apt install intel-gpu-tools

Sur l’hôte Proxmox (recommandé) :

apt install intel-gpu-tools

Vérifier l’utilisation GPU pendant un transcodage actif :

# Depuis le conteneur LXC
docker exec jellyfin intel_gpu_top

# OU depuis l'hôte Proxmox (fonctionne également)
intel_gpu_top
Astuce : Comme le conteneur LXC utilise directement les ressources de l’hôte Proxmox (pas de virtualisation matérielle), vous pouvez exécuter intel_gpu_top depuis l’hôte Proxmox pour monitorer l’utilisation GPU de Jellyfin. Cela évite d’installer le paquet dans le conteneur et permet de surveiller tous les conteneurs LXC utilisant l’iGPU simultanément.

Codecs supportés par iGPU Intel (génération 7+) :

  • Décodage : H.264, HEVC, VP9, AV1 (gen 11+)
  • Encodage : H.264, HEVC

Dépendances et notes
#

  • Jellyfin fonctionne en mode network_mode: host pour la découverte réseau (DLNA, Chromecast)
  • Les ports principaux sont 8096 (HTTP) et 7359/udp (découverte)
  • Aucune dépendance avec les autres services de la stack (fonctionne de manière autonome)

Service 9 : Tiny Media Manager - Gestion des métadonnées
#

Tiny Media Manager est un gestionnaire de bibliothèque vidéo qui récupère et organise automatiquement les métadonnées, pochettes et fanarts pour vos films et séries.

Rôle et responsabilités
#

TMM (Tiny Media Manager) scanne votre bibliothèque vidéo, identifie automatiquement les films et séries via leurs noms de fichiers, puis récupère les métadonnées complètes depuis TMDB, IMDB, TheTVDB, etc. Il génère les fichiers .nfo compatibles avec Jellyfin/Kodi et télécharge les visuels (posters, fanarts, logos). L’interface est accessible via VNC ou navigateur web.

Configuration Docker Compose
#

services:
  tinymediamanager:
    container_name: tinymediamanager
    image: tinymediamanager/tinymediamanager:latest
    restart: unless-stopped
    ports:
      - 5900:5900                   # VNC (accès distant)
      - 4000:4000                   # Interface web
    volumes:
      - ./data:/data                # Configuration TMM
      - /mnt/media/videos/movies:/media/movies
      - /mnt/media/videos/tvshows:/media/tv_shows
      - /mnt/media/videos/kids:/media/kids
    environment:
      - USER_ID=1000
      - GROUP_ID=1000
      - ALLOW_DIRECT_VNC=true
      - LC_ALL=fr_FR.UTF-8          # Interface en français
      - LANG=fr_FR.UTF-8
      - LC_TIME=C.UTF-8
      - TZ=Europe/Paris
      - PASSWORD=${VNC_PASSWORD}    # Mot de passe VNC
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
USER_ID / GROUP_ID UID/GID pour permissions fichiers 1000 Non
ALLOW_DIRECT_VNC Active l’accès VNC direct false Non
LC_ALL / LANG Localisation interface en_US.UTF-8 Non
PASSWORD Mot de passe VNC - Oui
TZ Fuseau horaire UTC Non
Attention : Définissez un mot de passe robuste pour VNC_PASSWORD dans le fichier .env pour sécuriser l’accès distant.

Volumes et persistance
#

  • ./data : Configuration TMM (sources, scrapers, cache)
  • /mnt/media/videos/movies : Bibliothèque de films
  • /mnt/media/videos/tvshows : Bibliothèque de séries TV
  • /mnt/media/videos/kids : Bibliothèque contenu jeunesse
Info : TMM nécessite un accès en lecture/écriture sur les bibliothèques vidéo pour créer les fichiers .nfo et télécharger les visuels. Assurez-vous que l’UID 1000 a les permissions appropriées.

Accès à l’interface
#

Via navigateur web (recommandé) :

http://10.10.20.40:4000

Via client VNC :

# Exemple avec TigerVNC
vncviewer 10.10.20.40:5900

Workflow typique
#

  1. Ajoutez les sources : Configurez les chemins /media/movies, /media/tv_shows dans TMM
  2. Scannez la bibliothèque : TMM détecte les nouveaux fichiers
  3. Récupération métadonnées : Sélectionnez les médias et lancez le scraping (TMDB, IMDB)
  4. Génération NFO : TMM crée les fichiers .nfo et télécharge les visuels
  5. Refresh Jellyfin : Actualisez la bibliothèque Jellyfin pour intégrer les nouvelles métadonnées

Astuce : Organisez vos fichiers selon la convention de nommage Jellyfin/Kodi :

/movies/Film (2023)/Film (2023).mkv
/tvshows/Serie/Season 01/Serie - S01E01.mkv

TMM reconnaîtra automatiquement la structure et remplira les métadonnées correctement.

Dépendances
#

  • Aucune dépendance directe avec Jellyfin, mais fonctionne en complémentarité
  • TMM prépare les métadonnées que Jellyfin consomme ensuite

Service 10 : Jellystat - Statistiques Jellyfin
#

Jellystat est un outil d’analyse et de statistiques pour Jellyfin qui collecte et visualise les données d’utilisation de votre serveur multimédia.

Rôle et responsabilités
#

Jellystat se connecte à votre serveur Jellyfin pour collecter les données de lecture (films visionnés, séries regardées, utilisateurs actifs, tendances de visionnage). Il offre une interface web moderne avec tableaux de bord, graphiques et rapports détaillés sur l’activité de votre bibliothèque vidéo. Contrairement aux statistiques natives de Jellyfin, Jellystat conserve un historique complet et propose des visualisations avancées.

Configuration Docker Compose
#

services:
  jellystat:
    container_name: jellystat
    image: cyfershepard/jellystat:latest
    restart: unless-stopped
    ports:
      - 3000:3000                      # Interface web Jellystat
    volumes:
      - ./data:/app/backend/backup-data  # Sauvegardes base de données
    environment:
      - POSTGRES_DB=jfstat             # Base de données PostgreSQL
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_IP=10.10.20.20        # IP du serveur PostgreSQL
      - POSTGRES_PORT=5432
      - JWT_SECRET=${JELLYSTAT_JWT_SECRET}  # Clé secrète JWT
      - TZ=Europe/Paris
    networks:
      - mediaserver

Variables d’environnement principales
#

Variable Description Valeur par défaut Obligatoire
POSTGRES_DB Nom de la base de données jfstat Non
POSTGRES_USER Utilisateur PostgreSQL - Oui
POSTGRES_PASSWORD Mot de passe PostgreSQL - Oui
POSTGRES_IP Adresse IP du serveur PostgreSQL - Oui
POSTGRES_PORT Port PostgreSQL 5432 Non
JWT_SECRET Clé secrète pour authentification JWT - Oui
TZ Fuseau horaire UTC Non
Attention : Jellystat nécessite une base de données PostgreSQL externe. Vous devez disposer d’un serveur PostgreSQL accessible (sur l’hôte Proxmox, un autre conteneur LXC, ou un service existant) avant de déployer Jellystat.
Info : Dans cet exemple, PostgreSQL est accessible sur 10.10.20.20:5432. Adaptez POSTGRES_IP selon votre configuration. Si vous n’avez pas de serveur PostgreSQL, déployez-en un via Docker Compose ou utilisez une instance existante de votre infrastructure.

Volumes et persistance
#

  • ./data : Sauvegardes automatiques de la base de données PostgreSQL
Astuce : Les données principales sont stockées dans PostgreSQL. Le volume ./data contient uniquement les backups générés par Jellystat pour récupération en cas de problème.

Accès à l’interface
#

http://10.10.20.40:3000

Configuration initiale :

  1. Créer un compte administrateur Jellystat

    • Lors de la première connexion à http://10.10.20.40:3000, créez un compte administrateur
  2. Générer une clé API dans Jellyfin (prérequis obligatoire)

    Important : Jellystat a besoin d’une clé API Jellyfin pour accéder aux données du serveur. Cette clé doit être générée depuis l’interface d’administration de Jellyfin.
    • Connectez-vous à Jellyfin en tant qu’administrateur : http://10.10.20.40:8096
    • Accédez au Dashboard (coin supérieur droit → icône engrenage)
    • Cliquez sur Advanced (Avancé) dans le menu de gauche
    • Sélectionnez API Keys (Clés API)
    • Cliquez sur + (Ajouter) pour créer une nouvelle clé
    • Donnez un nom descriptif : Jellystat
    • Copiez la clé générée
  3. Connecter Jellystat à Jellyfin

    • Retournez dans l’interface Jellystat
    • Ajoutez votre serveur Jellyfin avec les informations suivantes :
      • URL Jellyfin : http://10.10.20.40:8096 (ou http://jellyfin:8096 si utilisation du réseau Docker bridge)
      • Clé API : Collez la clé API générée à l’étape 2
    • Cliquez sur Connecter ou Valider
  4. Vérification

    • Jellystat commence immédiatement à collecter les données d’activité
    • Les statistiques des lectures passées sont importées
    • Les nouveaux visionnages sont synchronisés automatiquement toutes les heures

Workflow typique
#

  1. Installation et configuration : Première connexion et ajout du serveur Jellyfin
  2. Collecte automatique : Jellystat synchronise les données toutes les heures
  3. Consultation dashboards : Visualisez les films/séries populaires, temps de visionnage, utilisateurs actifs
  4. Rapports personnalisés : Créez des rapports sur périodes spécifiques (mois, année)
Astuce : Jellystat est idéal pour identifier quel contenu intéresse le plus vos utilisateurs, planifier la rotation de stockage (supprimer les médias jamais regardés), ou simplement suivre vos propres habitudes de visionnage !

Dépendances
#

graph LR
    A[Jellystat] --> B[Jellyfin]
    A --> C[(PostgreSQL)]

    style A fill:#e1f5ff,stroke:#0288d1,stroke-width:2px,color:#000
    style B fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#000
    style C fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#000
  • Jellyfin : Source des données de visionnage (connexion via API)
  • PostgreSQL : Stockage des statistiques et historique (externe requis)
Info : Jellystat ne modifie jamais les données de Jellyfin, il ne fait que les lire via l’API. Votre bibliothèque Jellyfin reste intacte.

🚀 Déploiement étape par étape
#

Étape 1 : Préparation de l’environnement
#

1.1 Créer la structure de dossiers
#

# Crée la structure complète du projet
mkdir -p mediaserver-stack/{navidrome,music-assistant,jellyfin,tinymediamanager,jellystat,booklore,scrobbler-analytics,metadata-remote}
mkdir -p mediaserver-stack/navidrome/data
mkdir -p mediaserver-stack/music-assistant/data
mkdir -p mediaserver-stack/jellyfin/{config,cache}
mkdir -p mediaserver-stack/tinymediamanager/data
mkdir -p mediaserver-stack/jellystat/data
mkdir -p mediaserver-stack/booklore/{data,bookdrop,mariadb}
mkdir -p mediaserver-stack/scrobbler-analytics/{maloja,multi-scrobbler}
cd mediaserver-stack

1.2 Vérifier les montages de médias
#

# Vérifie que les répertoires de médias sont accessibles
ls -lh /mnt/media/musics
ls -lh /mnt/media/books
ls -lh /mnt/media/videos
Attention : Si ces répertoires n’existent pas dans le conteneur LXC, vérifiez que les bind mounts ont été correctement configurés lors de la création du conteneur (section “Configuration avancée du conteneur LXC”). Les montages doivent pointer vers /mnt/storage/media sur l’hôte Proxmox.

1.3 Configuration des variables d’environnement
#

# Crée le fichier .env depuis l'exemple
cat > .env << 'EOF'
COMPOSE_PROJECT_NAME=mediaserver

# MALOJA
MALOJA_FORCE_PASSWORD="VotreMotDePasseSecurisé"
MALOJA_API_KEY="VotreCléAPIAleatoire"

# TINYMEDIAMANAGER
VNC_PASSWORD="MotDePasseVNCSecurisé"

# JELLYSTAT
POSTGRES_USER=jellystat
POSTGRES_PASSWORD="MotDePassePostgreSQLSecurisé"
JELLYSTAT_JWT_SECRET="CléSecrèteJWTAleatoire"

# BOOKLORE
# Database Connection (BookLore)
DATABASE_URL=jdbc:mariadb://booklore-db:3306/booklore
DB_USER=booklore
DB_PASSWORD="MotDePasseBookLoreSecurisé"

# MariaDB Container Settings
MYSQL_ROOT_PASSWORD="MotDePasseRootMariaDB"
MYSQL_DATABASE=booklore
EOF

Variables à personnaliser obligatoirement :

Les variables suivantes doivent être modifiées avant le déploiement :
  • MALOJA_FORCE_PASSWORD : Mot de passe d’administration de Maloja
  • MALOJA_API_KEY : Clé API pour le scrobbling (à générer aléatoirement)
  • VNC_PASSWORD : Mot de passe pour accéder à Tiny Media Manager via VNC
  • POSTGRES_PASSWORD : Mot de passe de l’utilisateur PostgreSQL pour Jellystat
  • JELLYSTAT_JWT_SECRET : Clé secrète JWT pour l’authentification Jellystat (à générer aléatoirement)
  • DB_PASSWORD : Mot de passe de l’utilisateur BookLore dans MariaDB
  • MYSQL_ROOT_PASSWORD : Mot de passe root de MariaDB
Astuce : Générez des mots de passe robustes avec openssl rand -base64 32

1.4 Créer les fichiers docker-compose.yml
#

Créez chaque fichier docker-compose.yml dans son sous-répertoire respectif en reprenant les configurations détaillées dans la section précédente. Commencez par le fichier principal :

# Fichier principal d'orchestration
cat > docker-compose.yml << 'EOF'
---
include:
  - ./navidrome/docker-compose.yml
  - ./music-assistant/docker-compose.yml
  - ./jellyfin/docker-compose.yml
  - ./tinymediamanager/docker-compose.yml
  - ./jellystat/docker-compose.yml
  - ./scrobbler-analytics/docker-compose.yml
  - ./metadata-remote/docker-compose.yml
  - ./booklore/docker-compose.yml

networks:
  mediaserver:
    name: mediaserver
    driver: bridge
    ipam:
      config:
        - subnet: 172.18.0.0/16
          gateway: 172.18.0.1
EOF

1.5 Configuration Multi-Scrobbler
#

# Crée la configuration du scrobbling Navidrome → Maloja
cat > scrobbler-analytics/multi-scrobbler/config.json << 'EOF'
{
  "sources": [
    {
      "type": "subsonic",
      "name": "Navidrome",
      "data": {
        "url": "http://navidrome:4533",
        "user": "votre_utilisateur_navidrome",
        "password": "votre_mot_de_passe_navidrome"
      }
    }
  ],
  "clients": [
    {
      "type": "maloja",
      "name": "Maloja Analytics",
      "data": {
        "url": "http://maloja:42010",
        "apiKey": "VotreCléAPIAleatoire"
      }
    }
  ]
}
EOF
Important : L’utilisateur et le mot de passe Navidrome seront créés lors du premier accès à l’interface web (étape suivante). Vous devrez ensuite mettre à jour ce fichier.

Étape 2 : Lancement de la stack
#

# Lance tous les services en arrière-plan
docker compose up -d

Que se passe-t-il ?

graph TD
    A[docker compose up -d] --> B[Création réseau mediaserver]
    B --> C[Pull des images Docker]
    C --> D[Démarrage booklore-db]
    D --> E{Healthcheck MariaDB}
    E -->|OK| F[Démarrage booklore]
    E -->|Attente| E
    C --> G[Démarrage services parallèles]
    G --> H[navidrome]
    G --> I[maloja]
    G --> J[multi-scrobbler]
    G --> L[music-assistant]
    G --> M[metadata-remote]
    G --> O[jellyfin]
    G --> P[tinymediamanager]
    F --> N[Stack opérationnelle]
    H --> N
    I --> N
    J --> N
    L --> N
    M --> N
    O --> N
    P --> N
    style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#000
    style E fill:#fff9c4,stroke:#f57c00,stroke-width:2px,color:#000
    style N fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,color:#000
  1. Docker crée le réseau mediaserver (172.18.0.0/16)
  2. Les images Docker sont téléchargées si nécessaire
  3. MariaDB démarre en premier (dépendance de BookLore)
  4. Le healthcheck vérifie que MariaDB est prêt (jusqu’à 10 tentatives)
  5. BookLore démarre une fois la base disponible
  6. Les autres services démarrent en parallèle
  7. Multi-Scrobbler établit la connexion avec Navidrome et Maloja

Étape 3 : Configuration initiale des services
#

3.1 Navidrome - Premier accès
#

# Accédez à l'interface web Navidrome
# URL : http://10.10.20.41:4533

Lors du premier accès :

  1. Créez un compte administrateur (notez bien ces identifiants)
  2. Navidrome scanne automatiquement /music
  3. Patientez pendant l’indexation initiale (durée selon la taille de votre bibliothèque)
Astuce : Surveillez la progression du scan dans les logs : docker compose logs -f navidrome

3.2 Maloja - Configuration
#

# Accédez à Maloja
# URL : http://10.10.20.41:42010
  1. Connectez-vous avec le mot de passe défini dans MALOJA_FORCE_PASSWORD
  2. Naviguez dans Settings → API Keys
  3. Générez une clé API (ou vérifiez que celle du .env est active)
  4. Copiez cette clé pour la configuration Multi-Scrobbler

3.3 Multi-Scrobbler - Finalisation
#

Maintenant que vous avez créé votre compte Navidrome et récupéré la clé API Maloja :

# Édite la configuration du scrobbler
nano scrobbler-analytics/multi-scrobbler/config.json

Mettez à jour avec vos vraies informations :

{
  "sources": [
    {
      "type": "subsonic",
      "name": "Navidrome",
      "data": {
        "url": "http://navidrome:4533",
        "user": "admin",                    #  Votre utilisateur Navidrome
        "password": "votre_mot_de_passe"    #  Votre mot de passe Navidrome
      }
    }
  ],
  "clients": [
    {
      "type": "maloja",
      "name": "Maloja Analytics",
      "data": {
        "url": "http://maloja:42010",
        "apiKey": "votre_vraie_clé_api"     #  Clé API Maloja
      }
    }
  ]
}

Redémarrez Multi-Scrobbler pour appliquer :

docker compose restart multi-scrobbler

3.4 BookLore - Premier accès
#

# URL : http://10.10.20.41:6060
  1. Créez un compte administrateur
  2. Scannez votre bibliothèque /books
  3. Déposez de nouveaux livres dans booklore/bookdrop/ pour import automatique

Étape 4 : Vérification de la communication inter-services
#

4.1 Test du scrobbling
#

# Vérifiez les logs de Multi-Scrobbler
docker compose logs -f multi-scrobbler

Lancez une écoute depuis Navidrome et vérifiez que :

  1. Multi-Scrobbler détecte l’écoute (log : Now Playing detected)
  2. Le scrobble est envoyé à Maloja après ~50% du morceau
  3. L’écoute apparaît dans Maloja (interface web)
Succès : Si vous voyez vos écoutes dans Maloja, la chaîne Navidrome → Multi-Scrobbler → Maloja fonctionne correctement !

✅ Vérification et tests
#

Vérifier que tous les services sont démarrés
#

# Liste tous les conteneurs de la stack
docker compose ps

Sortie attendue :

NAME                IMAGE                                    STATUS          PORTS
booklore            booklore/booklore:latest                 Up 5 minutes    0.0.0.0:6060->6060/tcp
booklore-db         lscr.io/linuxserver/mariadb:11.4.5      Up 5 minutes
jellyfin            jellyfin/jellyfin                        Up 5 minutes
jellystat           cyfershepard/jellystat:latest            Up 5 minutes    0.0.0.0:3000->3000/tcp
maloja              krateng/maloja:latest                    Up 5 minutes    0.0.0.0:42010->42010/tcp
metadata-remote     ghcr.io/wow-signal-dev/metadata-remote   Up 5 minutes    0.0.0.0:8338->8338/tcp
multi-scrobbler     foxxmd/multi-scrobbler                   Up 5 minutes    0.0.0.0:9078->9078/tcp
music-assistant     ghcr.io/music-assistant/server:latest    Up 5 minutes
navidrome           deluan/navidrome:latest                  Up 5 minutes    0.0.0.0:4533->4533/tcp
tinymediamanager    tinymediamanager/tinymediamanager:latest Up 5 minutes    0.0.0.0:4000->4000/tcp, 0.0.0.0:5900->5900/tcp
Tous les services doivent afficher le statut “Up” pour confirmer un démarrage réussi.

Tests fonctionnels
#

Test 1 : Streaming musical via Navidrome
#

# Teste l'API Subsonic (authentification)
curl -u "admin:password" "http://10.10.20.41:4533/rest/ping?v=1.16.1&c=test"

Résultat attendu : Réponse XML contenant <subsonic-response status="ok">

Astuce : Installez un client Subsonic mobile (Symfonium, DSub) pour tester le streaming en mobilité.

Test 2 : Accès à BookLore
#

curl -I http://10.10.20.41:6060

Résultat attendu : HTTP/1.1 200 OK

Test 3 : Accès à Jellyfin
#

# Teste l'accès à l'interface web Jellyfin
curl -I http://10.10.20.40:8096

Résultat attendu : HTTP/1.1 200 OK ou redirection 302 Found

Astuce : Lors du premier accès à Jellyfin (http://10.10.20.40:8096), l’assistant de configuration s’affiche. Créez un compte administrateur et ajoutez votre bibliothèque /media avec les sous-dossiers appropriés (movies, tvshows, etc.).

Test 4 : Accès à Jellystat
#

# Teste l'accès à l'interface web Jellystat
curl -I http://10.10.20.40:3000

Résultat attendu : HTTP/1.1 200 OK

Configuration Jellystat : Lors de la première connexion à Jellystat (http://10.10.20.40:3000) :

  1. Créez un compte administrateur Jellystat
  2. Générez une clé API dans Jellyfin :
    • Connectez-vous à Jellyfin : http://10.10.20.40:8096
    • Dashboard → Advanced (Avancé) → API Keys (Clés API)
    • Cliquez sur + pour créer une nouvelle clé nommée Jellystat
    • Copiez la clé (elle ne sera plus visible après fermeture)
  3. Connectez Jellystat à Jellyfin :
    • URL Jellyfin : http://10.10.20.40:8096 (ou http://jellyfin:8096 si réseau bridge)
    • Collez la clé API générée à l’étape 2
  4. La collecte des statistiques démarre automatiquement après connexion

Test 5 : Vérification du scrobbling
#

  1. Lancez une lecture depuis Navidrome
  2. Attendez 30 secondes minimum
  3. Vérifiez dans Maloja (http://10.10.20.41:42010) que l’écoute apparaît

Vérification des logs
#

# Logs de tous les services (mode suivi)
docker compose logs -f

# Logs d'un service spécifique
docker compose logs -f navidrome
docker compose logs -f multi-scrobbler
docker compose logs -f booklore

Signaux d’alerte :

  • Connection refused → Vérifier que le service cible est démarré
  • Authentication failed → Vérifier les identifiants dans les configurations
  • Permission denied → Vérifier les UID/GID et permissions des volumes

Test d’import de livre dans BookLore
#

# Copie un livre de test dans le bookdrop
cp /chemin/vers/livre.epub booklore/bookdrop/

# Vérifie les logs d'import
docker compose logs -f booklore

Le livre devrait être automatiquement importé et visible dans l’interface BookLore.


🔧 Maintenance et monitoring
#

Commandes utiles au quotidien
#

Redémarrer un service
#

# Redémarre un service spécifique
docker compose restart navidrome

# Redémarre tous les services
docker compose restart

Mettre à jour la stack
#

# Récupère les dernières images
docker compose pull

# Reconstruit et redémarre avec les nouvelles images
docker compose up -d --force-recreate

Sauvegarder les données
#

# Script de sauvegarde simple
#!/bin/bash
BACKUP_DIR="/backup/mediaserver-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# Arrête les services pour cohérence des données
cd ~/mediaserver-stack
docker compose stop

# Sauvegarde les volumes de données
tar -czf "$BACKUP_DIR/navidrome-data.tar.gz" navidrome/data
tar -czf "$BACKUP_DIR/booklore-data.tar.gz" booklore/data booklore/mariadb
tar -czf "$BACKUP_DIR/maloja-data.tar.gz" scrobbler-analytics/maloja

# Sauvegarde la configuration
cp .env "$BACKUP_DIR/"
cp scrobbler-analytics/multi-scrobbler/config.json "$BACKUP_DIR/"

# Redémarre les services
docker compose start

echo "Sauvegarde terminée dans $BACKUP_DIR"
Bonne pratique : Automatisez cette sauvegarde avec un cron quotidien et synchronisez vers un stockage distant.

Monitoring des ressources
#

# Utilisation CPU/RAM en temps réel
docker stats

# Espace disque des volumes
docker system df -v

Nettoyage et maintenance
#

# Supprime les conteneurs arrêtés et images inutilisées
docker system prune -a

Attention : La commande suivante supprime aussi les volumes non utilisés. Utilisez-la avec précaution !

docker system prune -a --volumes

Surveillance de la santé des services
#

# Vérification de l'état de santé de MariaDB
docker inspect booklore-db --format='{{.State.Health.Status}}'

Résultat attendu : healthy


🔍 Troubleshooting
#

Problème 1 : Navidrome ne trouve pas les fichiers musicaux
#

Symptômes :

  • Bibliothèque vide dans Navidrome
  • Logs : No music files found ou Permission denied

Causes probables :

  • Le montage /mnt/media/musics n’est pas accessible
  • Permissions incorrectes (l’utilisateur 1000:1000 ne peut pas lire les fichiers)
  • Aucun fichier musical avec extensions reconnues (.mp3, .flac, .ogg, etc.)

Solutions :

# Vérifiez que le montage existe et contient des fichiers
ls -lah /mnt/media/musics

# Vérifiez les permissions
namei -l /mnt/media/musics

# Ajustez les permissions si nécessaire (exemple)
sudo chown -R 1000:1000 /mnt/media/musics
sudo chmod -R 755 /mnt/media/musics

# Forcez un nouveau scan
docker compose restart navidrome
Comment éviter ce problème : Assurez-vous que l’utilisateur Docker (UID 1000) a les droits de lecture sur l’arborescence complète des médias.

Problème 2 : BookLore ne se connecte pas à MariaDB
#

Symptômes :

  • BookLore redémarre en boucle
  • Logs : Connection refused ou Access denied for user 'booklore'@'...'

Cause probable : Les variables d’environnement de connexion à la base ne correspondent pas entre BookLore et MariaDB.

Solution :

# Vérifiez les variables dans .env
cat .env | grep -E 'DB_|MYSQL_'

# Vérifiez que booklore-db est healthy
docker inspect booklore-db --format='{{.State.Health.Status}}'

# Si unhealthy, consultez les logs MariaDB
docker compose logs booklore-db

# Vérifiez la connexion manuelle
docker compose exec booklore-db mariadb -u booklore -p booklore
# Entrez le mot de passe DB_PASSWORD

Si la connexion manuelle échoue, recréez l’utilisateur :

docker compose exec booklore-db mariadb -u root -p
# Entrez MYSQL_ROOT_PASSWORD

# Dans le shell MariaDB
CREATE USER IF NOT EXISTS 'booklore'@'%' IDENTIFIED BY 'votre_mot_de_passe';
GRANT ALL PRIVILEGES ON booklore.* TO 'booklore'@'%';
FLUSH PRIVILEGES;
EXIT;

# Redémarrez BookLore
docker compose restart booklore

Problème 3 : Multi-Scrobbler ne scrobble pas les écoutes
#

Symptômes :

  • Écoutes dans Navidrome mais rien dans Maloja
  • Logs Multi-Scrobbler : Authentication failed ou Connection timeout

Causes probables :

  • Identifiants Navidrome incorrects dans config.json
  • Clé API Maloja incorrecte ou expirée
  • Services Navidrome/Maloja inaccessibles depuis Multi-Scrobbler

Solutions :

# Vérifiez la configuration
cat scrobbler-analytics/multi-scrobbler/config.json

# Testez la connexion à Navidrome depuis le conteneur
docker compose exec multi-scrobbler curl http://navidrome:4533

# Testez la connexion à Maloja
docker compose exec multi-scrobbler curl http://maloja:42010

# Si les connexions échouent, vérifiez le réseau
docker network inspect mediaserver

# Vérifiez les logs en temps réel
docker compose logs -f multi-scrobbler
Astuce : Activez le mode debug dans Multi-Scrobbler en ajoutant "logLevel": "debug" dans config.json puis redémarrez.

Problème 4 : Music Assistant ne découvre pas les équipements
#

Symptômes :

  • Aucune enceinte Chromecast/AirPlay détectée
  • Logs : mDNS discovery failed

Cause probable : Le mode network_mode: host est requis pour la découverte mDNS, mais peut être bloqué par le firewall.

Solution :

# Vérifiez que Music Assistant est bien en mode host
docker inspect music-assistant --format='{{.HostConfig.NetworkMode}}'
# Résultat attendu : host

# Vérifiez que le firewall autorise mDNS (port UDP 5353)
sudo ufw allow 5353/udp

# Redémarrez le service
docker compose restart music-assistant

Problème 5 : Jellystat ne démarre pas (erreur PostgreSQL)
#

Symptômes :

  • Jellystat redémarre en boucle
  • Logs : Connection refused ou could not connect to server

Cause probable : PostgreSQL n’est pas installé ou n’est pas accessible depuis le conteneur Jellystat.

Solutions :

Important : Jellystat nécessite une base de données PostgreSQL externe. Contrairement à BookLore qui embarque MariaDB dans le docker-compose, Jellystat attend une instance PostgreSQL déjà existante.

Option 1 : Installer PostgreSQL sur l’hôte Proxmox

# Sur l'hôte Proxmox, installez PostgreSQL
apt update && apt install postgresql postgresql-contrib

# Créez la base de données et l'utilisateur
sudo -u postgres psql
CREATE DATABASE jfstat;
CREATE USER jellystat WITH PASSWORD 'votre_mot_de_passe';
GRANT ALL PRIVILEGES ON DATABASE jfstat TO jellystat;
\q

# Autorisez les connexions depuis le réseau Docker
# Éditez /etc/postgresql/*/main/pg_hba.conf et ajoutez :
host    jfstat    jellystat    172.18.0.0/16    md5

# Éditez /etc/postgresql/*/main/postgresql.conf
listen_addresses = '*'

# Redémarrez PostgreSQL
systemctl restart postgresql

Option 2 : Ajouter PostgreSQL au docker-compose

# Ajoutez dans jellystat/docker-compose.yml
services:
  jellystat-db:
    container_name: jellystat-db
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_DB=jfstat
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - mediaserver

  jellystat:
    # ... configuration existante
    environment:
      - POSTGRES_IP=jellystat-db  # Modifiez cette ligne
      # ... autres variables
    depends_on:
      - jellystat-db
Astuce : L’option 2 (PostgreSQL dans Docker Compose) est recommandée pour un déploiement autonome de la stack, sans dépendance externe.

Diagramme de débogage
#

flowchart TD
    A[Service ne démarre pas] --> B{Vérifier les logs}
    B -->|Port déjà utilisé| C[Port en conflit]
    B -->|Permission denied| D[Permissions incorrectes]
    B -->|Connection refused| E[Dépendance non démarrée]
    B -->|Authentication failed| F[Identifiants incorrects]
    C --> G[Modifier le port dans docker-compose.yml]
    D --> H[Ajuster UID/GID et permissions volumes]
    E --> I[Vérifier depends_on et healthcheck]
    F --> J[Corriger .env ou config.json]

    G --> K[Redémarrer la stack]
    H --> K
    I --> K
    J --> K
    K --> L{Service démarre ?}
    L -->|Oui| M[Problème résolu]
    L -->|Non| N[Consulter les logs détaillés]
    N --> O[Demander de l'aide sur GitHub/forum]

    style C fill:#ffcdd2,color:#000
    style D fill:#fff3cd,color:#000
    style E fill:#ffe0b2,color:#000
    style F fill:#f8bbd0,color:#000
    style M fill:#c8e6c9,color:#000

FAQ
#

Q : Puis-je utiliser une base PostgreSQL au lieu de MariaDB pour BookLore ? R : BookLore supporte PostgreSQL. Modifiez simplement DATABASE_URL en JDBC PostgreSQL : jdbc:postgresql://booklore-db:5432/booklore et remplacez l’image MariaDB par une image PostgreSQL.
Q : Comment activer le transcodage dans Navidrome pour économiser de la bande passante mobile ? R : Le transcodage est activé par défaut (ND_ENABLETRANSCODINGCONFIG=true). Configurez les profils dans l’interface web (Settings → Transcoding) pour définir les débits selon les clients.
Q : Maloja peut-il être utilisé avec d’autres lecteurs que Navidrome ? R : Oui, Maloja dispose d’une API compatible Last.fm. De nombreux lecteurs supportent le scrobbling Last.fm et peuvent être configurés pour pointer vers votre instance Maloja.
Q : Comment ajouter un reverse proxy (Traefik, Nginx) devant cette stack ? R : Placez tous les services dans un réseau commun avec votre reverse proxy et configurez les routes selon vos besoins. Retirez les publications de ports (ports:) des services qui ne doivent plus être exposés directement.

⚡ Optimisations et bonnes pratiques
#

Sécurité
#

Sécuriser votre stack mediaserver protège vos données personnelles et empêche les accès non autorisés.

1. Gestion des secrets
#

À faire : Utiliser des variables d’environnement pour les mots de passe et ne jamais les committer dans Git
À éviter : Mettre des mots de passe en clair directement dans docker-compose.yml
# Exemple : générer des secrets robustes
openssl rand -base64 32 > secrets/db_password.txt
openssl rand -base64 32 > secrets/maloja_api_key.txt

# Protéger les fichiers de secrets
chmod 600 secrets/*

Ajoutez secrets/ à .gitignore pour éviter toute fuite.

2. Isolation réseau
#

Séparez les services selon leur niveau de confiance :

networks:
  frontend:
    # Services exposés (reverse proxy)
  backend:
    # Services internes uniquement
Astuce : Seul le reverse proxy devrait être dans le réseau frontend, tous les autres services dans backend.

3. Mise à jour régulière
#

# Automatisez les mises à jour avec un cron hebdomadaire
0 3 * * 0 cd /home/user/mediaserver-stack && docker compose pull && docker compose up -d

4. Restrictions d’accès
#

  • Activez l’authentification forte sur tous les services
  • Utilisez un reverse proxy avec authentification (Authelia, Authentik)
  • Limitez l’accès réseau avec un firewall (UFW, iptables)

Performance
#

1. Optimisation du transcodage Navidrome
#

environment:
  - ND_TRANSCODINGCACHESIZE=2048MB  # Augmentez selon RAM disponible
  - ND_IMAGECACHESIZE=512MB

Le cache de transcodage évite de re-encoder les mêmes fichiers, économisant CPU et latence.

2. Indexation optimisée
#

environment:
  - ND_SCANSCHEDULE=1h              # Scan fréquent si ajouts réguliers
  # OU
  - ND_SCANSCHEDULE=@daily          # Scan quotidien si bibliothèque stable

Réduisez la fréquence de scan si votre bibliothèque change peu pour économiser des ressources.

3. Optimisation MariaDB
#

Ajoutez des paramètres de performance pour MariaDB :

booklore-db:
  command:
    - --innodb-buffer-pool-size=256M
    - --max-connections=50

4. Limitation des logs
#

logging:
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

Appliquez cette configuration à tous les services pour éviter la saturation du disque.

Astuce : Limitez la taille des logs pour éviter de saturer votre disque. Les logs Docker peuvent croître rapidement.

Haute disponibilité
#

Pour un environnement de production critique, envisagez :

graph LR
    LB["Reverse Proxy
Load Balancer"] --> N1["Navidrome
Instance 1"] LB --> N2["Navidrome
Instance 2"] N1 --> DB[("MariaDB
Master")] N2 --> DB DB -.Réplication.-> DBR[("MariaDB
Replica")] style LB fill:#e1f5ff,stroke:#01579b,stroke-width:2px,color:#000 style N1 fill:#bbdefb,stroke:#1976d2,stroke-width:2px,color:#000 style N2 fill:#bbdefb,stroke:#1976d2,stroke-width:2px,color:#000 style DB fill:#b2dfdb,stroke:#00796b,stroke-width:2px,color:#000 style DBR fill:#b2dfdb,stroke:#00796b,stroke-width:2px,stroke-dasharray: 5 5,color:#000

Composants pour la HA :

  • Load Balancer : HAProxy, Nginx, Traefik avec plusieurs backends Navidrome
  • Réplication base de données : MariaDB Master-Slave ou Galera Cluster
  • Stockage unifié : MergerFS avec SnapRAID pour protection des données (architecture Perfect Homelab)

Logs et observabilité
#

Intégrez un système de monitoring centralisé :

# Exemple avec Loki pour l'agrégation de logs
services:
  loki:
    image: grafana/loki:latest
    # Configuration Loki...

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
    # Configuration Promtail...

Stack d’observabilité recommandée :

  • Prometheus : métriques système et applicatives
  • Grafana : dashboards de visualisation
  • Loki : agrégation et recherche de logs
  • Promtail : collecteur de logs Docker

🎯 Conclusion
#

Vous disposez maintenant d’une stack mediaserver complète et auto-hébergée, offrant streaming vidéo, streaming musical, gestion d’ebooks et analytics d’écoute dans un environnement unifié !

Dans cet article, vous avez appris à :

  • Déployer une infrastructure multimédia complète avec Docker Compose
  • Exploiter l’architecture de stockage MergerFS + bind mounts LXC pour des performances optimales
  • Configurer un conteneur LXC Proxmox optimisé avec transcodage matériel iGPU Intel
  • Déployer Jellyfin pour le streaming vidéo avec accélération matérielle
  • Utiliser Tiny Media Manager pour gérer les métadonnées de vos films et séries
  • Installer Jellystat pour suivre les statistiques de visionnage Jellyfin
  • Configurer Navidrome pour le streaming musical compatible Subsonic
  • Déployer Music Assistant pour faciliter l’accès à la bibliothèque musicale via Home Assistant
  • Mettre en place BookLore pour gérer vos livres numériques
  • Implémenter un système d’analytics d’écoute auto-hébergé avec Maloja
  • Synchroniser automatiquement vos écoutes avec Multi-Scrobbler
  • Sécuriser et optimiser votre stack pour un usage quotidien

Cette stack est maintenant prête pour un usage personnel ou familial. Elle offre une alternative libre et respectueuse de la vie privée aux services de streaming propriétaires (Netflix, Spotify, Audible), tout en conservant le confort d’usage d’une plateforme moderne avec transcodage matériel et applications clients multiplateformes.

Pour aller plus loin
#

Suggestions d’amélioration :

  • Ajoutez un reverse proxy (Traefik, Caddy) avec HTTPS automatique via Let’s Encrypt
  • Intégrez Music Assistant à Home Assistant pour créer des automatisations musicales (réveil en musique, ambiances, contrôle vocal) - Article à paraître dans la série Perfect Homelab
  • Déployez Sonarr/Radarr/Lidarr pour automatiser la gestion de votre bibliothèque
  • Configurez des sauvegardes automatiques vers un stockage distant (rclone, restic)
  • Ajoutez Jellyseerr pour gérer les demandes de médias avec interface utilisateur moderne
  • Configurez des sous-titres automatiques avec Bazarr

Ressources complémentaires
#

Besoin d’aide ?
#

N’hésitez pas à commenter cet article ou à rejoindre les communautés Discord/Matrix des projets respectifs pour obtenir de l’aide.

Cet article vous a été utile ? Partagez-le et laissez un commentaire avec vos questions ou retours d’expérience sur votre propre mediaserver !
Perfect Homelab - Cet article fait partie d'une série.
Partie 9: Cet article

Articles connexes