Une médiathèque auto-hébergée sur Raspberry Pi : de la demande d'un film à sa lecture sous-titrée, sans intervention manuelle.
📖 Première installation ? Le guide pas à pas déroule la mise en place complète, de l'installation de Docker au premier film téléchargé automatiquement.
Dix services qui se passent le relais. On demande un film dans une interface, il arrive dans la médiathèque avec ses sous-titres.
flowchart LR
USER(["👤"])
subgraph req["Demande"]
SEERR["<b>Seerr</b><br/>:5055"]
end
subgraph orch["Orchestration"]
SONARR["<b>Sonarr</b><br/>séries · :8989"]
RADARR["<b>Radarr</b><br/>films · :7878"]
end
subgraph search["Recherche"]
PROW["<b>Prowlarr</b><br/>:9696"]
FLARE["FlareSolverr<br/>:8191"]
end
QBIT["<b>qBittorrent</b><br/>:8080"]
BAZ["<b>Bazarr</b><br/>sous-titres · :6767"]
JELLY["<b>Jellyfin</b><br/>:8096"]
MAINT["Maintainerr<br/>ménage · :6246"]
USER --> SEERR
SEERR --> SONARR & RADARR
SONARR & RADARR --> PROW
PROW <-.->|anti-Cloudflare| FLARE
PROW --> QBIT
QBIT -->|"/media"| JELLY
BAZ -->|"sous-titres"| JELLY
MAINT -.->|"purge"| JELLY
JELLY --> USER
Le fil complet :
- 📥 Seerr — on y demande un film ou une série, avec une interface de catalogue
- 🎯 Sonarr / Radarr — décident quoi chercher, à quelle qualité, et suivent l'avancement
- 🔍 Prowlarr — interroge les indexeurs (FlareSolverr passe les protections Cloudflare)
- ⬇️ qBittorrent — télécharge, puis range dans l'arborescence de la médiathèque
- 💬 Bazarr — va chercher les sous-titres correspondants
▶️ Jellyfin — sert le tout, sur la TV, le téléphone ou le navigateur- 🧹 Maintainerr — supprime ce qui n'est plus regardé, pour ne pas saturer le disque
- 🔐 Nginx Proxy Manager — expose ce qu'on veut, en HTTPS, avec des certificats Let's Encrypt
| Service | Rôle | Port | Image |
|---|---|---|---|
| Jellyfin | Serveur multimédia | 8096 |
jellyfin/jellyfin |
| Seerr | Interface de demandes | 5055 |
ghcr.io/seerr-team/seerr |
| Sonarr | Gestion des séries | 8989 |
lscr.io/linuxserver/sonarr |
| Radarr | Gestion des films | 7878 |
lscr.io/linuxserver/radarr |
| Prowlarr | Agrégateur d'indexeurs | 9696 |
lscr.io/linuxserver/prowlarr |
| Bazarr | Sous-titres automatiques | 6767 |
linuxserver/bazarr |
| qBittorrent | Client de téléchargement | 8080, 6881 |
lscr.io/linuxserver/qbittorrent |
| FlareSolverr | Contournement Cloudflare | 8191 |
ghcr.io/flaresolverr/flaresolverr |
| Maintainerr | Nettoyage de la médiathèque | 6246 |
jorenn92/maintainerr |
| Nginx Proxy Manager | Reverse proxy + HTTPS | 80, 81, 443 |
jc21/nginx-proxy-manager |
- Un Raspberry Pi (testé sur un Pi 5, 64 bits) ou toute machine Linux
- Docker et le plugin Docker Compose v2
- Un stockage pour les médias — un SSD ou un disque USB, pas la carte SD : les écritures permanentes d'un client BitTorrent l'useraient en quelques mois
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER # puis se reconnecterLe docker-compose.yml est publié tel qu'il tourne chez moi. Deux réglages sont donc à votre main :
| Réglage | Valeur dans le fichier | À faire |
|---|---|---|
| Chemin des médias | /mnt/ssd/jellyfin/media |
Remplacer par le point de montage de votre disque |
| Fuseau horaire | TZ=Asia/Kuala_Lumpur |
Mettre le vôtre — Europe/Paris par exemple |
PUID / PGID |
1000 |
Vérifier avec id -u et id -g |
git clone https://github.com/clemdepernet/media-stack-rpi.git
cd media-stack-rpi
# Adapter les chemins et le fuseau
sed -i 's|/mnt/ssd/jellyfin/media|/votre/chemin|g' docker-compose.yml
sed -i 's|TZ=Asia/Kuala_Lumpur|TZ=Europe/Paris|g' docker-compose.ymlSonarr et Radarr doivent voir le même chemin que qBittorrent, sinon ils ne retrouvent pas les fichiers téléchargés et les recopient au lieu de les déplacer.
sudo mkdir -p /votre/chemin/{Movies,tv,downloads}
sudo chown -R 1000:1000 /votre/chemindocker compose up -d
docker compose psLes dossiers de configuration (jellyfin/, sonarr/, radarr/…) sont créés automatiquement au premier lancement.
L'ordre compte : chaque service a besoin de la clé d'API du précédent. Ci-dessous l'essentiel ; le guide pas à pas complet détaille chaque écran, explique pourquoi l'arborescence doit être posée ainsi, et couvre le dépannage.
1. qBittorrent — :8080
Le mot de passe temporaire est affiché dans les logs au premier démarrage :
docker compose logs qbittorrent | grep -i passwordSe connecter en admin, changer le mot de passe immédiatement, puis régler le dossier de téléchargement sur /downloads.
2. Prowlarr — :9696
- Indexers → Add indexer : ajouter ses sources
- Settings → Indexers → FlareSolverr : URL
http://flaresolverr:8191, pour les indexeurs protégés par Cloudflare - Settings → Download Clients : ajouter qBittorrent, hôte
qbittorrent, port8080
3. Sonarr et Radarr — :8989 et :7878
- Settings → Media Management → Root Folder :
/media/tv(Sonarr) et/media/Movies(Radarr) - Settings → Download Clients : qBittorrent, hôte
qbittorrent, port8080 - Revenir dans Prowlarr → Settings → Apps pour les y déclarer : Sonarr
http://sonarr:8989, Radarrhttp://radarr:7878, avec leur clé d'API — Prowlarr y poussera alors tous ses indexeurs d'un coup
4. Bazarr — :6767
- Settings → Sonarr / Radarr : les connecter avec leurs clés d'API
- Settings → Providers : choisir ses fournisseurs de sous-titres (OpenSubtitles demande un compte)
- Settings → Languages : définir un profil de langues, puis l'appliquer aux séries et aux films
5. Jellyfin — :8096
Assistant de première configuration, puis ajouter deux médiathèques : Films sur /media/Movies et Séries sur /media/tv.
Sur un Pi 5, activer l'accélération matérielle dans Dashboard → Playback → Transcoding (V4L2 ou VA-API selon le noyau). Sans elle, le transcodage sature les quatre cœurs.
6. Seerr — :5055
Connecter Jellyfin, puis Sonarr et Radarr avec leurs clés d'API. C'est l'interface à partager avec les autres utilisateurs : ils demandent, la stack se débrouille.
7. Nginx Proxy Manager — :81
Identifiants par défaut : admin@example.com / changeme — à changer à la première connexion.
Créer ensuite un Proxy Host par service à exposer, et demander un certificat Let's Encrypt dans l'onglet SSL.
Ce dépôt ne contient que le docker-compose.yml. Tout le reste — bases de données, caches, clés d'API, clé privée de Nginx Proxy Manager, hash du mot de passe qBittorrent — est généré à l'exécution et exclu par le .gitignore, qui fonctionne en liste blanche : tout est ignoré, sauf les quelques fichiers explicitement autorisés.
Si vous forkez ou reprenez ce dépôt, vérifiez avant chaque commit :
git status --short # doit rester vide après un démarrage
git ls-files # doit lister 4 fichiers, pas davantageQuelques points à garder en tête :
- 🔑 Changer tous les mots de passe par défaut — qBittorrent et Nginx Proxy Manager en particulier
- 🚪 Ne pas exposer les interfaces d'administration sur Internet. Seuls Jellyfin et Seerr ont vocation à sortir ; Sonarr, Radarr, Prowlarr et qBittorrent restent sur le réseau local ou derrière un VPN
- 🌐 Le trafic de qBittorrent n'est pas tunnelisé dans cette configuration : il sort par l'IP de la connexion. Ceux qui veulent le faire passer par un VPN ajoutent généralement un conteneur type
gluetunet basculent qBittorrent sur son network stack - ⚖️ Ce dépôt ne fournit aucun contenu ni aucun indexeur. Ce que vous téléchargez et la légalité de ces téléchargements dans votre pays ne regardent que vous
docker compose ps # état des services
docker compose logs -f sonarr # suivre un service
docker compose pull && docker compose up -d # mettre à jour les images
docker compose restart qbittorrent # redémarrer un service
docker compose down # tout arrêterVérifier que deux services se voient bien sur le réseau interne :
docker compose exec sonarr curl -sI http://qbittorrent:8080 | head -1Sonarr ou Radarr ne récupèrent pas les fichiers téléchargés
C'est le problème le plus courant, et c'est presque toujours une histoire de chemins. qBittorrent doit écrire dans une arborescence que Sonarr et Radarr voient au même chemin. Ici, les trois montent /mnt/ssd/jellyfin/media — qBittorrent sur /downloads, les autres sur /media.
Comparer ce que chacun voit :
docker compose exec qbittorrent ls -la /downloads
docker compose exec sonarr ls -la /mediaDans Sonarr : Activity → Queue, le message d'erreur indique en général le chemin qui ne correspond pas.
Un indexeur renvoie une erreur Cloudflare
Vérifier que FlareSolverr est déclaré dans Prowlarr → Settings → Indexers, avec l'URL http://flaresolverr:8191, puis :
docker compose logs flaresolverr | tail -20FlareSolverr est gourmand en mémoire — il lance un navigateur headless. Sur un Pi, éviter de le solliciter en boucle.
Jellyfin saccade ou chauffe
C'est du transcodage logiciel. Activer l'accélération matérielle dans Dashboard → Playback → Transcoding, et vérifier pendant une lecture :
docker stats jellyfin --no-streamSi le CPU reste au plafond, le client force un transcodage : préférer des formats lus en direct play (H.264 en MP4/MKV).
Erreurs de permissions sur les fichiers
Les conteneurs LinuxServer écrivent avec PUID/PGID, fixés à 1000 dans le compose. Ils doivent correspondre au propriétaire du dossier de médias :
id -u && id -g
ls -ln /votre/chemin
sudo chown -R 1000:1000 /votre/cheminUn service ne joint pas un autre
Tous les services partagent le réseau medianet et s'adressent par leur nom de service — http://sonarr:8989, jamais localhost, qui désigne le conteneur lui-même.
Exception : nginx-proxy-manager n'est pas sur medianet. Pour qu'il puisse proxifier les autres services, l'y ajouter, ou viser l'IP de l'hôte.
- Sortir les chemins et le fuseau dans un fichier
.env - Faire passer qBittorrent par un conteneur VPN (
gluetun) - Épingler les tags d'images plutôt que
latest - Sauvegarder automatiquement les dossiers de configuration
- Brancher la stack sur Grafana-DockerPI pour la superviser
MIT — ne couvre que les fichiers de configuration de ce dépôt.