Installer medialab Server dans un conteneur

medialab Server est publié sous forme d’image conteneur pour linux/amd64 et linux/arm64 :

ghcr.io/cristiancasapu/medialab-server

L’image est construite à partir des mêmes paquets Debian signés que le dépôt apt (medialab-server, medialab-server-web, jellyfin-ffmpeg8) ; ses fichiers de construction sont publics sur github.com/CristianCasapu/medialab-server-docker (GPL-2.0).

Étiquettes :

Étiquette Signification
12.2-ml.10 une version ; recommandée si vous voulez choisir quand mettre à jour
12.2 la version la plus récente basée sur Jellyfin 12.2
latest la version la plus récente
12.2-ml10-deb12 la version apt exacte à l’intérieur de l’image

Ce qu’il vous faut

  • Docker (ou Podman, Unraid, Portainer, Kubernetes) sur une machine 64 bits x86 ou ARM.
  • Un dossier pour les paramètres (/config), un pour le cache (/cache) et votre dossier multimédia (/media).
  • L’identifiant numérique de l’utilisateur et du groupe qui doivent posséder les paramètres : id -u et id -g de ce compte (PUID, PGID).

docker run

docker run -d --name medialab-server --restart unless-stopped \
  -p 8096:8096 -p 7359:7359/udp \
  -v /srv/medialab/config:/config \
  -v /srv/medialab/cache:/cache \
  -v /srv/media:/media:ro \
  -e PUID=1000 -e PGID=1000 -e TZ=Europe/Bucharest \
  ghcr.io/cristiancasapu/medialab-server:latest

Ouvrez http://<server>:8096. Sur un nouveau serveur, l’assistant de configuration demande le premier administrateur, la langue et vos bibliothèques (ajoutez-les depuis /media).

Pour passer l’assistant, laissez le conteneur créer l’administrateur. Mettez le mot de passe dans un fichier, pas sur la ligne de commande :

printf '%s' 'a-long-password' > /srv/medialab/admin_password
docker run -d ... \
  -v /srv/medialab/admin_password:/run/secrets/admin_password:ro \
  -e MLW_ADMIN_USER=admin \
  -e MLW_ADMIN_PASSWORD_FILE=/run/secrets/admin_password \
  ghcr.io/cristiancasapu/medialab-server:latest

Cela ne fonctionne que sur un nouveau serveur ; sur un serveur déjà configuré, les variables sont ignorées. Le mot de passe n’apparaît jamais dans les journaux du conteneur.

Docker Compose

compose.yaml :

services:
  medialab-server:
    image: ghcr.io/cristiancasapu/medialab-server:12.2-ml.10
    container_name: medialab-server
    restart: unless-stopped
    ports:
      - "8096:8096"
      - "7359:7359/udp"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /srv/media:/media:ro
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Europe/Bucharest
      MLW_SERVER_NAME: Home media
      MLW_ADMIN_USER: admin
      MLW_ADMIN_PASSWORD_FILE: /run/secrets/admin_password
    secrets:
      - admin_password

secrets:
  admin_password:
    file: ./secrets/admin_password
mkdir -p secrets && printf '%s' 'a-long-password' > secrets/admin_password
docker compose up -d
docker compose logs -f

Un exemple complet avec un fichier .env se trouve dans le dépôt (examples/compose.yaml, examples/.env.example).

Unraid

  1. Dans l’onglet Docker, choisissez Add Container et définissez Template sur l’URL https://raw.githubusercontent.com/CristianCasapu/medialab-server-docker/main/examples/unraid/medialab-server.xml (ou copiez le fichier dans /boot/config/plugins/dockerMan/templates-user/).
  2. Vérifiez les chemins : /config → /mnt/user/appdata/medialab-server, /media → votre partage multimédia.
  3. PUID 99 et PGID 100 sont les valeurs Unraid habituelles (nobody / users).
  4. GPU Intel ou AMD : ajoutez --device=/dev/dri à Extra Parameters et définissez Hardware acceleration sur qsv ou vaapi. NVIDIA : installez le plugin Nvidia-Driver, ajoutez --runtime=nvidia et définissez-le sur nvenc.
  5. Cliquez sur Apply, puis ouvrez la WebUI.

Portainer

  1. Stacks → Add stack → Web editor, puis collez examples/portainer/stack.yml depuis le dépôt.
  2. Sous Environment variables, chargez examples/portainer/stack.env (ou ajoutez les variables à la main) et ajustez les chemins, PUID, PGID et TZ.
  3. Deploy the stack.

Les stacks Portainer ne peuvent pas utiliser les secrets Docker sur un hôte autonome : l’exemple transmet donc MLW_ADMIN_PASSWORD comme variable de stack. Elle n’est utilisée qu’une seule fois ; vous pouvez la supprimer après le premier démarrage.

Kubernetes

examples/kubernetes/medialab-server.yaml contient un ConfigMap, deux PersistentVolumeClaims, un Deployment (une réplique, stratégie Recreate, sondes de santé sur /health), un Service et un Ingress :

kubectl create namespace medialab
kubectl -n medialab create secret generic medialab-secrets \
  --from-literal=admin-password='a-long-password' --from-literal=license-key='' --from-literal=repo-key=''
kubectl -n medialab apply -f medialab-server.yaml

Ajustez d’abord les tailles de stockage, le volume multimédia (un exemple NFS est inclus) et le nom d’hôte. N’exécutez qu’une seule réplique : le serveur garde sa base de données dans /config.

Accélération matérielle

Intel (QSV / VAAPI) et AMD (VAAPI)

docker run ... --device /dev/dri:/dev/dri -e MLW_HW_ACCEL=qsv ...     # Intel
docker run ... --device /dev/dri:/dev/dri -e MLW_HW_ACCEL=vaapi ...   # AMD or older Intel

Le conteneur ajoute lui-même l’utilisateur du serveur aux groupes qui possèdent /dev/dri/* : inutile de chercher les numéros des groupes render et video. Les pilotes sont fournis avec jellyfin-ffmpeg8 ; l’image amd64 contient aussi le runtime OpenCL d’Intel depuis Debian 12 pour le mappage des tons HDR (les GPU Intel très récents peuvent nécessiter un runtime plus récent que celui de Debian 12).

NVIDIA (NVENC / NVDEC)

Installez le pilote NVIDIA et le NVIDIA Container Toolkit sur l’hôte, puis :

docker run ... --gpus all -e MLW_HW_ACCEL=nvenc ...

Avec Compose, ajoutez examples/compose.nvidia.yaml ; sur Kubernetes, demandez nvidia.com/gpu: 1.

Après le premier démarrage, vérifiez Dashboard → Playback → Transcoding et lisez une vidéo qui nécessite un transcodage ; le journal ffmpeg dans /config/log indique si le GPU a été utilisé.

Plugins, paramètres et licences depuis l’extérieur

Tout ce qui suit est facultatif ; la liste complète des variables se trouve dans docs/ENVIRONMENT.md du dépôt.

Paramètres du serveur. Par exemple :

-e MLW_PUBLISHED_URL=https://media.example.org \
-e MLW_KNOWN_PROXIES=172.16.0.0/12 \
-e MLW_UI_CULTURE=en-US -e MLW_METADATA_COUNTRY=US \
-e MLW_REMOTE_ACCESS=true

Ils sont écrits dans system.xml, network.xml et encoding.xml avant le démarrage du serveur. Avec la valeur par défaut MLW_CONFIG_MODE=first-run, une valeur est écrite sur un nouveau serveur, puis de nouveau uniquement quand vous changez la variable : ce que vous modifiez ensuite dans le tableau de bord est donc conservé. MLW_CONFIG_MODE=enforce les écrit à chaque démarrage. Toute autre propriété peut être définie avec MLW_SYSTEM__<Property>, MLW_NETWORK__<Property> et MLW_ENCODING__<Property>.

Catalogue de plugins. Le catalogue public medialab.works et le dépôt officiel de Jellyfin sont ajoutés par défaut (MLW_PLUGIN_REPOS=medialab,jellyfin). Si votre compte a une clé de dépôt, ajoutez-la avec MLW_REPO_KEY (ou MLW_REPO_KEY_FILE) ; elle est masquée dans les journaux.

Plugins. Listez-les dans MLW_PLUGINS ; ils sont installés avant le démarrage du serveur :

-e MLW_PLUGINS="jf-rosub,jf-registration@1.0.2"

Un plugin est trouvé par son slug (jf-rosub), son nom ou son GUID ; @version fixe une version. L’archive est vérifiée par rapport à l’empreinte du catalogue, et la signature medialab (.dll.sig) est conservée : le tableau de bord affiche donc le plugin comme vérifié. Les plugins déjà installés ne sont pas retéléchargés ; MLW_PLUGINS_UPDATE=true installe les versions plus récentes au démarrage.

Paramètres des plugins. Montez le fichier de configuration du plugin (/config/plugins/configurations/<Assembly>.xml, par ex. Rosub.xml) ou définissez des valeurs individuelles :

-e MLW_PLUGIN_ROSUB__ArchiveCacheDays=14

Clés de licence. MLW_LICENSE_KEY, MLW_LICENSE_KEY_<SLUG> (par ex. MLW_LICENSE_KEY_JF_ROSUB), leurs formes _FILE et les secrets Docker nommés mlw_license_key ou mlw_license_key_<slug> sont transmis tels quels au processus du serveur. Les plugins les y lisent dans les versions de plugin qui le prennent en charge ; avec une version plus ancienne, saisissez la clé sur la page du plugin dans le tableau de bord (elle est enregistrée dans /config).

Chaque variable accepte aussi <NAME>_FILE=/path/to/file, pour les secrets Docker et Kubernetes.

Mises à jour

Tirez la nouvelle image et recréez le conteneur ; les paramètres de /config sont conservés :

docker pull ghcr.io/cristiancasapu/medialab-server:12.2-ml.10
docker stop medialab-server && docker rm medialab-server
docker run -d ... ghcr.io/cristiancasapu/medialab-server:12.2-ml.10     # mêmes options qu’avant

Avec Compose : changez l’étiquette dans compose.yaml (ou gardez latest), puis docker compose pull && docker compose up -d. Sur Unraid : Check for Updates dans l’onglet Docker. Dans Portainer : Recreate avec Re-pull image.

Le programme de mise à jour intégré du paquet Debian ne fait pas partie de l’image. Self-Update by MediaLab affiche les versions disponibles dans un conteneur mais n’installe pas de paquets ; mettez à jour en tirant la nouvelle étiquette d’image (12.2-ml.N) et en recréant le conteneur.

Sauvegarde

/config contient tout ce qui compte (paramètres, utilisateurs, base de données, plugins, métadonnées). Arrêtez le conteneur et copiez-le :

docker stop medialab-server
tar -C /srv/medialab -czf medialab-config-$(date +%F).tar.gz config
docker start medialab-server

/cache peut être reconstruit et ne nécessite aucune sauvegarde. Pour restaurer, remettez config en place et démarrez la même étiquette d’image ou une plus récente.

Dépannage

  • Voir ce que le conteneur a fait : docker logs medialab-server. Les lignes commençant par [medialab] proviennent du script de démarrage du conteneur (paramètres écrits, plugins installés, administrateur créé).
  • Le conteneur s’arrête aussitôt avec [medialab] ERROR : une variable a une valeur invalide ; le message la nomme.
  • « Permission denied » : PUID/PGID ne correspondent pas au propriétaire des dossiers. Le conteneur corrige lui-même /config et /cache, jamais /media. Démarré avec --user, il ne change rien : les dossiers doivent déjà appartenir à cet utilisateur.
  • Un paramètre de l’environnement n’est pas appliqué : en mode first-run, une valeur est écrite sur un nouveau serveur ou quand elle change. Utilisez MLW_CONFIG_MODE=enforce pour l’imposer.
  • Un plugin n’est pas installé : le journal indique pourquoi (catalogue inaccessible, nom introuvable, empreinte différente, aucune version pour ce serveur). Le serveur démarre quand même, sauf si MLW_PLUGINS_STRICT=true.
  • Le conteneur est affiché comme unhealthy : la vérification de santé appelle /health sur le port 8096 (ou le port et l’URL de base de network.xml). Le premier démarrage peut prendre une à deux minutes.
  • Derrière un reverse proxy, les clients reçoivent la mauvaise adresse : définissez MLW_KNOWN_PROXIES sur l’adresse du proxy et MLW_PUBLISHED_URL sur l’URL publique.