← Blogue

Héberger MediaCMS soi-même pour l'hébergement vidéo

Railyard

16 septembre 2026 · 8 min de lecture

Suivez ça sur votre propre serveur. Commencer gratuitement, sans carte

Faire tourner votre propre portail vidéo veut habituellement dire choisir entre une mince enveloppe autour de la facture de stockage de quelqu’un d’autre et un vrai CMS média qui gère lui-même les téléversements, le transcodage et la lecture. MediaCMS est le deuxième type : une application Django open source qui ingère vidéo, audio et images, les transcode vers plusieurs résolutions avec des workers Celery qui tournent en arrière-plan, et sert un portail de marque avec sa propre recherche et ses propres listes de lecture. À la fin de ce guide, vous aurez l’application web, un worker de transcodage séparé, Postgres et Redis qui tournent ensemble derrière HTTPS, avec des sauvegardes et un vrai téléversement testé de bout en bout.

Ce qu’il vous faut

  • Un serveur avec Docker et le plugin Compose. Un Hetzner CX33 (4 vCPU, 8 Go de RAM, 80 Go NVMe, 8,99 €/mois hors TVA) est le plancher réaliste une fois le transcodage impliqué ; un CX23 fait techniquement tourner l’application web, mais les téléversements simultanés se disputent le même CPU limité avec la gestion de requêtes équivalente à Puma, dont un processus worker dédié a besoin d’espace.
  • Un nom de domaine vers lequel vous pouvez pointer un enregistrement A.
  • Une vraie planification de disque : MediaCMS garde le téléversement original plus chaque résolution transcodée plus les segments HLS pour le streaming, une règle empirique approximative du projet lui-même est trois fois la taille de ce que vous téléversez réellement, sur une année de téléversements à votre rythme prévu.
  • Un accès SSH au serveur.

Étape 1 : pointer le DNS et ouvrir le pare-feu

ufw allow OpenSSH
ufw allow 80
ufw allow 443
ufw --force enable

Créez un enregistrement A pour votre domaine pointant vers l’IP publique du serveur, et laissez-lui quelques minutes avant l’étape 5.

Étape 2 : générer les secrets

openssl rand -hex 24   # POSTGRES_PASSWORD
openssl rand -hex 24   # ADMIN_PASSWORD
openssl rand -hex 32   # SECRET_KEY
mkdir -p /opt/mediacms
cat > /opt/mediacms/.env <<'EOF'
POSTGRES_PASSWORD=paste-the-first-value-here
ADMIN_PASSWORD=paste-the-second-value-here
SECRET_KEY=paste-the-third-value-here
EOF
chmod 600 /opt/mediacms/.env

SECRET_KEY compte plus ici que dans une application Django typique : laissé non défini, le propre local_settings.py de MediaCMS retombe sur une valeur par défaut codée en dur dans chaque copie de l’image, ce qui permettrait à n’importe qui de forger des cookies signés ou des jetons de réinitialisation de mot de passe contre tout déploiement qui l’aurait laissé non défini. Le définir explicitement, et partager la même valeur entre les processus web et worker, n’est pas optionnel.

Étape 3 : écrire le fichier Compose

MediaCMS a en fait besoin de quatre processus qui lisent tous le même environnement : l’application web, un worker Celery pour le transcodage, un planificateur Celery beat pour les tâches périodiques, et la base de données et le cache qu’ils partagent.

services:
  mediacms:
    image: mediacms/mediacms:7.2.0
    restart: unless-stopped
    env_file: .env
    command: ./deploy/docker/prestart.sh
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    environment:
      FRONTEND_HOST: https://videos.yourdomain.com
      REDIS_LOCATION: redis://redis:6379/1
      POSTGRES_HOST: db
      POSTGRES_NAME: mediacms
      POSTGRES_USER: mediacms
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      ENABLE_CELERY_SHORT: "no"
      ENABLE_CELERY_LONG: "no"
      ENABLE_CELERY_BEAT: "no"
      ADMIN_USER: admin
      ADMIN_EMAIL: admin@yourdomain.com
      ADMIN_PASSWORD: ${ADMIN_PASSWORD}
      SECRET_KEY: ${SECRET_KEY}
    volumes:
      - mediacms_media:/home/mediacms.io/mediacms/media_files
    expose:
      - "80"

  worker:
    image: mediacms/mediacms:7.2.0
    restart: unless-stopped
    env_file: .env
    depends_on:
      - mediacms
    environment:
      REDIS_LOCATION: redis://redis:6379/1
      POSTGRES_HOST: db
      POSTGRES_NAME: mediacms
      POSTGRES_USER: mediacms
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      SECRET_KEY: ${SECRET_KEY}
      ENABLE_UWSGI: "no"
      ENABLE_NGINX: "no"
      ENABLE_CELERY_BEAT: "no"
      ENABLE_MIGRATIONS: "no"
    volumes:
      - mediacms_media:/home/mediacms.io/mediacms/media_files

  beat:
    image: mediacms/mediacms:7.2.0
    restart: unless-stopped
    env_file: .env
    depends_on:
      - mediacms
    environment:
      REDIS_LOCATION: redis://redis:6379/1
      POSTGRES_HOST: db
      POSTGRES_NAME: mediacms
      POSTGRES_USER: mediacms
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      SECRET_KEY: ${SECRET_KEY}
      ENABLE_UWSGI: "no"
      ENABLE_NGINX: "no"
      ENABLE_CELERY_SHORT: "no"
      ENABLE_CELERY_LONG: "no"
      ENABLE_MIGRATIONS: "no"

  db:
    image: postgres:17.2-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: mediacms
      POSTGRES_DB: mediacms
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - mediacms_db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mediacms"]
      interval: 5s
      timeout: 5s
      retries: 10

  redis:
    image: redis:7.2.5-alpine
    restart: unless-stopped
    volumes:
      - mediacms_redis_data:/data

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - mediacms

volumes:
  mediacms_media:
  mediacms_db_data:
  mediacms_redis_data:
  caddy_data:
  caddy_config:

Ce guide fixe 7.2.0, la version stable actuelle au moment de l’écriture. Le service mediacms exécute prestart.sh, le propre script d’entrée de MediaCMS qui applique les migrations et démarre le vrai serveur web, ce qui explique pourquoi ENABLE_MIGRATIONS y est laissé non défini mais explicitement à "no" sur worker et beat, exécuter les migrations depuis trois processus à la fois à chaque démarrage est une vraie façon de provoquer une situation de concurrence. ENABLE_CELERY_SHORT, ENABLE_CELERY_LONG et ENABLE_CELERY_BEAT sont tous à "no" sur le service mediacms spécifiquement pour que le conteneur web n’essaie pas aussi de faire tourner Celery lui-même ; ces trois rôles sont plutôt répartis entre worker et beat, chacun désactivant à son tour le rôle qu’il ne possède pas. mediacms_media est un volume unique partagé entre mediacms et worker, puisque le worker lit ce que le processus web a accepté et écrit la sortie transcodée que les deux ont besoin de voir.

Vérifiez que le fichier s’analyse :

docker compose config

Étape 4 : ajouter Caddy et démarrer la pile

videos.yourdomain.com {
	reverse_proxy mediacms:80
}
docker compose up -d
docker compose ps
curl -I https://videos.yourdomain.com

Vous devriez voir chaque service à l’état Up (db à l’état healthy) et le curl retourner HTTP/2 200.

Étape 5 : se connecter et téléverser une vidéo de test

Visitez https://videos.yourdomain.com et connectez-vous avec admin et le ADMIN_PASSWORD de l’étape 2. Téléversez une courte vidéo de test depuis l’interface, puis vérifiez qu’elle a réellement été transcodée, pas seulement téléversée :

docker compose logs -f worker

Vous devriez voir la sortie de tâche Celery référencer l’ID du nouveau média, se terminant dans un état complété, et la vidéo elle-même devrait être lisible dans le navigateur une minute ou deux plus tard une fois que le worker a rattrapé son retard, plus longtemps pour un fichier plus gros.

Étape 6 : sauvegarder Postgres et le volume de médias

cat > /opt/mediacms/backup.sh <<'EOF'
#!/bin/sh
cd /opt/mediacms
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
docker compose exec -T db pg_dump -U mediacms mediacms | gzip > backups/db-$TIMESTAMP.sql.gz
find backups -mtime +14 -delete
EOF
mkdir -p /opt/mediacms/backups
chmod +x /opt/mediacms/backup.sh
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/mediacms/backup.sh") | crontab -

L’export de la base de données couvre les métadonnées, les comptes et les listes de lecture, pas les vrais fichiers vidéo sur mediacms_media, qui est presque certainement la partie la plus grosse et la plus précieuse de cette installation. Sauvegardez ce volume avec une capture de disque complet de votre fournisseur de serveur, ou un rsync planifié vers une autre machine ; lancer un tar sur des médias actifs pendant que des téléversements sont en cours risque une archive incohérente, planifiez-le donc pour une période calme de la même façon que l’étape 6 d’autres guides gère une base de données active.

Étape 7 : mettre à niveau

docker compose pull
docker compose up -d

Le prestart.sh du service mediacms réapplique automatiquement les migrations au redémarrage ; worker et beat récupèrent aussi la nouvelle image puisqu’ils la partagent, mais sautent intentionnellement les migrations eux-mêmes, comme défini à l’étape 3. Vérifiez docker compose logs mediacms pour un démarrage propre avant de considérer la mise à niveau comme terminée.

Le raccourci : avec Railyard

Tout ce qui précède, Postgres et Redis branchés aux trois processus, les rôles worker et beat correctement séparés pour qu’ils ne fassent pas tourner Celery en double ou n’entrent pas en concurrence sur les migrations, un volume de médias partagé, est aussi ce que le modèle de pile MediaCMS de Railyard configure pour vous. Connectez un serveur, puis choisissez MediaCMS dans le catalogue de modèles : app.railyard.run/deploy?stack=mediacms. SECRET_KEY et ADMIN_PASSWORD sont générés pour vous plutôt que laissés comme espaces réservés, le mot de passe administrateur généré apparaît sur le tableau de bord de l’application au lieu de n’être affiché qu’une seule fois dans un journal comme le fait le propre prestart.sh de MediaCMS quand il est laissé non défini.

Voyez déployer avec un bouton et bases de données et sauvegardes pour savoir comment les modèles et les données persistantes fonctionnent sur la plateforme de façon plus générale.

Dépannage

Les téléversements réussissent mais les vidéos ne finissent jamais de se traiter. Vérifiez docker compose logs worker en premier ; un worker qui boucle en plantant ou qui est tué par manque de mémoire se manifeste par un redémarrage du conteneur plutôt qu’une erreur claire dans le journal, auquel cas la solution est plus de mémoire ou de CPU pour la machine, pas un changement de configuration.

La connexion administrateur rejette un mot de passe dont vous êtes certain qu’il est correct. Confirmez que ADMIN_PASSWORD dans .env correspond exactement à ce que vous tapez ; si la pile tournait déjà avant que vous le définissiez, le compte a été créé avec la valeur présente au premier démarrage, changez-le depuis l’admin Django plutôt que de rééditer .env après coup.

Les migrations semblent s’exécuter deux fois ou entrer en conflit au démarrage. Confirmez que ENABLE_MIGRATIONS: "no" est bien présent sur worker et beat dans votre fichier compose ; si c’est manquant sur l’un ou l’autre, vous verrez des erreurs de migration intermittentes qui semblent sans rapport avec la vraie cause.

Le HTTPS ne s’émet pas. docker compose logs caddy montrant des erreurs ACME répétées signifie presque toujours que le DNS de l’étape 1 ne s’est pas propagé ou pointe vers la mauvaise IP.

Le disque se remplit beaucoup plus vite que prévu. MediaCMS garde le téléversement original, les versions transcodées et les segments HLS côte à côte ; du -sh contre le volume de médias montre l’usage réel, et la règle empirique de trois fois la taille des téléversements de « Ce qu’il vous faut » vaut la peine d’être revue par rapport à votre propre rythme réel de téléversement plutôt que supposée une fois et oubliée.

FAQ

Puis-je désactiver le transcodage et simplement servir le fichier original ? Pas vraiment, le streaming adaptatif (servir la bonne résolution selon la connexion du spectateur) est une fonctionnalité centrale, pas un ajout ; si vous n’avez besoin d’héberger qu’une poignée de fichiers pré-encodés sans transcodage, un simple hébergeur de fichiers statiques convient mieux que MediaCMS.

MediaCMS a-t-il besoin d’un fournisseur SMTP ? Seulement pour des fonctionnalités optionnelles comme les notifications de courriel sur les commentaires ; la création de compte et l’hébergement vidéo de base fonctionnent tous les deux sans ça, moins strict que les applications qui exigent le SMTP pour confirmer un nouveau compte.

Le worker peut-il tourner sur un serveur séparé, moins cher, que le processus web ? Oui, tant qu’il peut joindre les mêmes Postgres, Redis et stockage de médias partagé, séparer le worker sur sa propre machine est une prochaine étape raisonnable une fois que la charge de transcodage entre réellement en concurrence avec le trafic web pour le CPU.

Quels formats vidéo accepte-t-il ? MediaCMS accepte des formats courants comme MP4, MOV, MKV, AVI, WebM et plus au téléversement, et les transcode vers une sortie standard adaptée au web peu importe le format source.

Y a-t-il une limite de taille sur les téléversements ? Le défaut propre à MediaCMS est généreux mais configurable ; l’espace disque d’un petit serveur est la limite la plus pratique dans une configuration auto-hébergée que quoi que ce soit que MediaCMS impose par défaut.

Une fois Postgres, Redis et le worker tous branchés aux mêmes secrets, téléverser et transcoder une vidéo, c’est les mêmes quelques clics que ce serait sur une plateforme hébergée. Le vrai travail continu, c’est l’habitude de sauvegarde de l’étape 6 et garder la croissance du disque en avance sur ce que le serveur a réellement.

Pourquoi les gens choisissent Railyard pour ça

  • Votre propre compte infonuagique. Déployez sur DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, ou n'importe quel serveur Linux par SSH, facturé directement par votre fournisseur, sans majoration.
  • Un prix fixe par équipe. L'offre gratuite est gratuite pour toujours : un serveur plus un serveur de base de données, trois applications, sans carte. Pro coûte 19 $ par mois pour jusqu'à cinq serveurs et un nombre illimité d'applications. Team coûte 49 $ par mois avec des serveurs illimités. Aucuns frais par application, par déploiement, par siège ou par gigaoctet.
  • Des gabarits en un clic. Déployez des applications open source, comme des bases de données, des outils d'analyse et des outils de développement, sur votre propre serveur en un clic.
  • Des bases de données gérées. Postgres, MySQL et Redis, avec des sauvegardes planifiées, vérifiées par restauration, et la récupération à un point dans le temps.
  • Déploiement par push. Déployez depuis GitHub, GitLab ou la CLI, avec HTTPS automatique et des mises en production sans interruption.

Déployez MediaCMS en un clic

Choisissez MediaCMS dans le catalogue de modèles de Railyard et obtenez Postgres, Redis et le worker de transcodage déjà branchés.

Offre gratuite, sans carte, et 14 jours de Pro pour chaque nouvelle équipe. Prix fixe par équipe.