Héberger un serveur Mastodon soi-même
Suivez ça sur votre propre serveur. Commencer gratuitement, sans carte
Faire tourner votre propre coin du fédivers veut dire faire tourner cinq choses qui doivent toutes s’accorder entre elles : un processus web Rails, un serveur de diffusion séparé pour la ligne temporelle en temps réel, un worker Sidekiq pour la fédération et les notifications, Postgres, et Redis. Un seul domaine mal configuré dans l’une d’elles et vous obtenez une instance qui se charge à moitié ou qui arrête silencieusement de fédérer. À la fin de ce guide, vous aurez une vraie instance Mastodon à serveur unique qui fait tourner les cinq, derrière HTTPS, avec des sauvegardes et un regard honnête sur ce que ça coûte réellement de bien la faire tourner.
Ce qu’il vous faut
- Un serveur avec au moins 4 vCPU et 8 Go de RAM pour une petite instance ; ce guide fait tourner les cinq services sur une seule machine, ce qui dépasse largement ce dont le processus web seul a besoin. Un Hetzner CX33 (4 vCPU, 8 Go de RAM, 80 Go NVMe, 8,99 €/mois hors TVA) est le point de départ réaliste une fois que Postgres, Redis, le serveur de diffusion et Sidekiq se disputent tous des ressources sur la même machine ; dépasser quelques centaines d’utilisateurs actifs, c’est le moment où séparer Postgres sur sa propre machine commence à compter.
- Un nom de domaine vers lequel vous pouvez pointer un enregistrement A. Mastodon lie vos identifiants de compte à ce domaine de façon permanente ; il n’y a aucune façon prise en charge de déplacer une instance existante vers un nouveau domaine plus tard sans tout recommencer.
- Un fournisseur SMTP. Ce n’est pas optionnel : Mastodon exige une livraison de courriel fonctionnelle pour la confirmation de compte, les réinitialisations de mot de passe et les avis de modération, et il est livré sans rien de configuré par défaut. N’importe quel fournisseur de courriel transactionnel fonctionne.
- 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. Laissez-lui le temps de se propager avant l’étape 6.
Étape 2 : générer chaque secret à l’avance
Mastodon a besoin de six valeurs secrètes distinctes avant de pouvoir démarrer : une clé secrète de base Rails, des clés VAPID pour les notifications push, et trois clés de chiffrement Active Record. Chacune a sa propre commande de génération, exécutée via l’image elle-même une fois récupérée :
mkdir -p /opt/mastodon && cd /opt/mastodon
docker pull ghcr.io/mastodon/mastodon:v4.7.3
docker run --rm ghcr.io/mastodon/mastodon:v4.7.3 bundle exec rails secret
docker run --rm ghcr.io/mastodon/mastodon:v4.7.3 bundle exec rake mastodon:webpush:generate_vapid_key
docker run --rm ghcr.io/mastodon/mastodon:v4.7.3 bundle exec rake db:encryption:init
La première commande affiche SECRET_KEY_BASE. La deuxième affiche une paire VAPID_PRIVATE_KEY et VAPID_PUBLIC_KEY. La troisième affiche les trois valeurs ACTIVE_RECORD_ENCRYPTION_* d’un coup. Conservez chacune d’elles :
cat > .env <<'EOF'
POSTGRES_PASSWORD=generate-with-openssl-rand-hex-24
REDIS_PASSWORD=generate-with-openssl-rand-hex-24
SECRET_KEY_BASE=paste-from-rails-secret
VAPID_PRIVATE_KEY=paste-from-generate-vapid-key
VAPID_PUBLIC_KEY=paste-from-generate-vapid-key
AR_ENCRYPTION_PRIMARY_KEY=paste-from-db-encryption-init
AR_ENCRYPTION_DETERMINISTIC_KEY=paste-from-db-encryption-init
AR_ENCRYPTION_KEY_DERIVATION_SALT=paste-from-db-encryption-init
SMTP_SERVER=smtp.your-provider.com
SMTP_LOGIN=your-smtp-username
SMTP_PASSWORD=your-smtp-password
EOF
chmod 600 .env
Étape 3 : écrire le fichier Compose
services:
mastodon:
image: ghcr.io/mastodon/mastodon:v4.7.3
restart: unless-stopped
command: bash -c "bundle exec rails db:prepare && bundle exec puma -C config/puma.rb"
env_file: .env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
environment:
LOCAL_DOMAIN: social.yourdomain.com
DB_HOST: db
DB_PORT: "5432"
DB_NAME: mastodon
DB_USER: mastodon
DB_PASS: ${POSTGRES_PASSWORD}
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD}
STREAMING_API_BASE_URL: wss://social.yourdomain.com
SMTP_FROM_ADDRESS: notifications@yourdomain.com
volumes:
- mastodon_system:/mastodon/public/system
expose:
- "3000"
streaming:
image: ghcr.io/mastodon/mastodon-streaming:v4.7.3
restart: unless-stopped
command: node ./streaming/index.js
env_file: .env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
environment:
PORT: "4000"
LOCAL_DOMAIN: social.yourdomain.com
DB_HOST: db
DB_PORT: "5432"
DB_NAME: mastodon
DB_USER: mastodon
DB_PASS: ${POSTGRES_PASSWORD}
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD}
expose:
- "4000"
sidekiq:
image: ghcr.io/mastodon/mastodon:v4.7.3
restart: unless-stopped
command: bundle exec sidekiq
env_file: .env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
environment:
LOCAL_DOMAIN: social.yourdomain.com
DB_HOST: db
DB_PORT: "5432"
DB_NAME: mastodon
DB_USER: mastodon
DB_PASS: ${POSTGRES_PASSWORD}
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD}
SMTP_FROM_ADDRESS: notifications@yourdomain.com
volumes:
- mastodon_system:/mastodon/public/system
db:
image: postgres:16.4-alpine
restart: unless-stopped
environment:
POSTGRES_USER: mastodon
POSTGRES_DB: mastodon
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- mastodon_db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mastodon"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7.2.5-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
env_file: .env
volumes:
- mastodon_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:
- mastodon
- streaming
volumes:
mastodon_system:
mastodon_db_data:
mastodon_redis_data:
caddy_data:
caddy_config:
Ce guide fixe v4.7.3 sur les trois images Mastodon, la version stable actuelle au moment de l’écriture. La commande du service mastodon exécute rails db:prepare avant que Puma démarre, le même motif qu’utilisent généralement les applications Rails, donc la configuration du schéma se fait automatiquement au premier démarrage et à chaque mise à niveau suivante. streaming est un processus Node.js réellement séparé, pas un fil d’exécution à l’intérieur de l’application Rails, ce qui explique pourquoi il a sa propre image et son propre STREAMING_API_BASE_URL pointé depuis le service principal. mastodon_system est un volume partagé entre mastodon et sidekiq spécifiquement, puisque Sidekiq est ce qui traite réellement les téléversements de médias en arrière-plan ; les deux ont besoin de voir les mêmes fichiers.
Vérifiez que le fichier s’analyse :
docker compose config
Étape 4 : ajouter Caddy, y compris le chemin de diffusion
social.yourdomain.com {
@streaming path /api/v1/streaming*
reverse_proxy @streaming streaming:4000
reverse_proxy mastodon:3000
}
Le client web de Mastodon appelle /api/v1/streaming pour sa ligne temporelle en temps réel, qui doit joindre le service streaming séparé, pas le processus Rails principal ; tout le reste va vers mastodon:3000. Validez que le Caddyfile se lit correctement avant de vous y fier :
docker run --rm -v "$PWD/Caddyfile:/etc/caddy/Caddyfile" caddy:2 caddy validate --config /etc/caddy/Caddyfile
Étape 5 : démarrer la pile et créer un compte administrateur
docker compose up -d
docker compose ps
curl -I https://social.yourdomain.com
Vous devriez voir chaque service à l’état Up (db à l’état healthy) et le curl retourner HTTP/2 200. Créez le premier compte depuis la ligne de commande, avec des privilèges d’administrateur :
docker compose exec mastodon bin/tootctl accounts create admin \
--email admin@yourdomain.com --confirmed --role Owner
Ça affiche un mot de passe généré ; connectez-vous avec et changez-le immédiatement depuis l’interface web.
Étape 6 : sauvegarder Postgres et le volume de médias
cat > /opt/mastodon/backup.sh <<'EOF'
#!/bin/sh
cd /opt/mastodon
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
docker compose exec -T db pg_dump -U mastodon mastodon | gzip > backups/db-$TIMESTAMP.sql.gz
find backups -mtime +14 -delete
EOF
mkdir -p /opt/mastodon/backups
chmod +x /opt/mastodon/backup.sh
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/mastodon/backup.sh") | crontab -
Le volume mastodon_system contient chaque pièce jointe média téléversée et grandit sans limite à mesure que les gens publient ; sauvegardez-le séparément avec l’outillage de capture de disque complet ou de volume qu’offre votre fournisseur de serveur, un pg_dump seul ne le couvre pas. Lancez le script une fois à la main et vérifiez que ls -lh backups montre le fichier du jour.
Étape 7 : mettre à niveau
docker compose pull
docker compose up -d
db:prepare dans la commande du service mastodon s’exécute à nouveau à chaque redémarrage, appliquant toute migration livrée avec la nouvelle version. Lisez les propres notes de version de Mastodon avant un saut de plusieurs versions ; le projet signale parfois une version intermédiaire requise pour des changements de schéma plus importants.
Le raccourci : avec Railyard
Tout ce qui précède, Postgres et Redis branchés aux trois processus basés sur Rails, le service de diffusion séparé avec son propre routage, Sidekiq qui partage le volume de médias, est aussi ce que le modèle de pile Mastodon de Railyard configure pour vous. Connectez un serveur, puis choisissez Mastodon dans le catalogue de modèles : app.railyard.run/deploy?stack=mastodon-stack. Railyard génère chaque secret de l’étape 2 pour vous et branche automatiquement les URL de la base de données, de Redis et de diffusion ; vous ajoutez quand même votre propre fournisseur SMTP par la suite, comme à l’étape 2 ci-dessus, Railyard n’en configure pas un pour vous non plus, et les médias téléversés restent par défaut sur un volume local partagé à moins que vous les pointiez vous-même vers du stockage objet.
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
La ligne temporelle en temps réel ne se met jamais à jour, mais publier et parcourir fonctionnent bien. Le Caddyfile ne route pas /api/v1/streaming vers le service streaming ; vérifiez la correspondance de chemin à l’étape 4 contre ce que l’onglet réseau de votre navigateur demande réellement.
Aucun courriel de confirmation n’arrive jamais pour une nouvelle inscription. Le SMTP n’est pas configuré ou les identifiants sont erronés ; vérifiez docker compose logs mastodon pour une erreur SMTP au moment où l’inscription a été tentée. Il n’y a aucun moyen de contourner cette exigence, Mastodon ne confirmera pas un compte sans ça.
Sidekiq prend du retard, les publications d’autres instances arrivent en retard. Vérifiez docker compose logs sidekiq pour des échecs de tâches répétés ou un redémarrage par manque de mémoire ; sur un CX33, c’est habituellement une contention de ressources avec Postgres et le processus web pendant un pic de trafic, le moment où séparer Postgres sur son propre serveur commence à valoir le coût.
Le HTTPS ne s’émet pas. docker compose logs caddy montrant des erreurs ACME répétées signifie presque toujours que l’enregistrement DNS de l’étape 1 ne s’est pas propagé ou pointe vers la mauvaise IP.
Le disque se remplit à cause du volume de médias. Mastodon met en cache localement les médias distants (images et vidéos d’autres instances) par défaut ; tootctl media remove --days 30 depuis l’intérieur du conteneur mastodon nettoie les médias distants mis en cache plus vieux qu’une fenêtre donnée sans toucher aux publications de vos propres utilisateurs.
FAQ
Puis-je changer le domaine de mon instance plus tard ? Non, les identifiants de compte sont liés au domaine de façon permanente ; c’est une contrainte à l’échelle du fédivers, pas quelque chose que la configuration propre de Mastodon peut contourner, décidez du vrai domaine avant d’inviter qui que ce soit.
Ai-je vraiment besoin de 8 Go de RAM pour une toute petite instance avec une poignée d’utilisateurs ? Le plancher est plus bas, mais une fois que Postgres, Redis, le serveur de diffusion et Sidekiq tournent tous sur une seule machine, 8 Go est le point où les choses cessent d’être serrées ; un CX23 avec 4 Go démarrera techniquement cette pile mais laisse très peu de marge pour les pics de trafic ou les tempêtes de fédération.
Quelle est la différence entre ça et rejoindre une instance Mastodon existante ? Faire tourner la vôtre vous donne votre propre politique de modération, votre propre domaine, et le contrôle complet sur la rétention des données ; rejoindre une instance existante échange ce contrôle contre zéro travail opérationnel.
Le stockage objet peut-il remplacer le volume de médias local ? Oui, Mastodon prend en charge le stockage compatible S3 pour les médias via sa propre configuration ; ce guide le garde local pour une première configuration simple, ça vaut la peine d’y revenir une fois que le volume de médias devient le principal consommateur de disque.
La fédération est-elle désactivée par défaut dans certains cas ? Non, une instance neuve fédère avec le réseau plus large dès qu’elle est joignable en HTTPS ; il existe un mode de liste d’autorisation séparé si vous voulez une instance fermée à la place, non couvert ici.
Une instance Mastodon qui fonctionne correctement, ce sont cinq services qui s’accordent sur un domaine et un ensemble d’identifiants, pas une seule chose compliquée. Une fois le DNS, la route de diffusion et le SMTP bien en place, le travail continu, c’est les sauvegardes, la mise à niveau occasionnelle, et garder un œil sur Sidekiq sous un vrai trafic.
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.