Sommaire
Avec les différentes affaires qui secouent Twitter, comme beaucoup, j'ai souhaité sauter le pas vers Mastodon. Pour le meilleur (un réseau fédéré) et pour le pire (un réseau fédéré).
J'ai eu un peu (beaucoup) de mal avec la documentation technique de l'outil, alors je me suis dit qu'un article francophone sur ce sujet ne serait pas de trop. Si le sous-jacent protocolaire vous intéresse, je vous invite à lire mon article sur ActivityPub.
Bien que très mis en avant ces dernières semaines, hélas, Mastodon n'est pas exempt des problématiques de vie privée, de sécurité, de censure ou simplement d'administrateurs peu scrupuleux. Du financement des instances, de leur gouvernance et plus généralement, de la gouvernance au sens large de tout la fédération qui gravite autour du Fediverse.
Au choix d'avoir un compte sur une instance Mastodon connue, j'ai préféré mon propre hébergement. Cela n'est pas sans conséquence pour moi et indirectement pour toute la communauté, malgré l'aspect minuscule de ma goutte d'eau - voir la conclusion.
Je vous propose ici une version simplifiée d'une "vraie" version de production (notamment l'usage Certbot, d'avoir des réseaux internes distincts pour la pile de conteneurs de Docker Compose, etc.). L'idée est de se mettre le pied à l'étrier et de chevaucher un énorme mammouth laineux…
Pré-requis
Vous trouverez un fichier docker-compose.yml
et un exemple de fichier d'environnement .env.production.sample
à la racine du dépôt Github de Mastodon.
Attention : ce dernier n'est pas directement "opérationnel" pour un usage en production (notamment parce que les bases ne sont pas instanciées). De plus pour notre cas, nous ne produirons pas localement les images (nous utiliserons celles en lignes tootsuite
).
Si vous êtes en mode "hors ligne" durant l'installation, pensez à télécharger les fichiers avec le combo docker pull
/ docker export
.
Voici les images utilisées durant l'installation (ma version exacte entre parenthèse, mais cela devrait fonctionner en _lastest₎, provenant de docker.io :
- postgres:14-alpine
(:14.6
) ;
- redis:7-alpine
;
- tootsuite/mastodon
(:v4.0.2
) ;
- adminer
(image optionnelle, si vous souhaitez accéder à vos bases de données en mode Web).
J'ai gardé Docker Compose pour l'exploitation des images - mais rien d'impossible sur un MicroK8s ou tout autre Kx par exemple. Idem pour l'usage de volumes.
J'ai écrit ce tutoriel depuis ma machine de dév (une Ubuntu 22.04) dotée de Docker mais le propos vaut pour toutes les distributions générales. Pensez à Podman pour un usage de production et des comptes sans privilège système / accès SSH.
Partie 1 : installation de la base de données
Je considère que vous êtes dans votre dossier de travail (~/Developpement/mastodon/article
pour ma part).
Nous allons initialiser une base Postgres et faire le nécessaire pour que Mastodon soit en capacité de créer sa base durant sa phase d’installation. Comme nous utiliserons dans l'exemple un point de montage, créez le dossier nécessaire :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ mkdir ./postgres14
Pour éviter des mots de passes qui se baladent dans l'historique Bash, mettons cela dans une variable :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ read -s mastodon_mdp # taper le mot de passe suivi de la touche entrée ; dans mon cas "3f5z8BEByTf5"
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ echo $mastodon_mdp
3f5z8BEByTf5
Créez un réseau Docker pour les prochaines étapes :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker network create mastodon
98ed9d69e697abc1990c8a4d3319120fc9fb58f4f6be1e18bc87a391f9a7ce2b
Puis lancez un conteneur jetable Postgres :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker run --rm --network=mastodon --name=mastodon_db -d -v "`pwd`/postgres14:/var/lib/postgresql/data" -e "POSTGRES_USER=mastodon" -e "POSTGRES_PASSWORD=$mastodon_mdp" postgres:14-alpine
d4e1d6b7be250dc56dda4a896d1b980e9b39234c93e2470e1ac23dff60af9984
Maintenant nous allons corriger la base créée avec le nom d'utilisateur (le comportement par défaut du conteneur). Mais Postgres ne nous autorise pas sa suppression si elle est connectée (cas par défaut) :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker run --rm --network=mastodon -it postgres:14-alpine bash
83f69d649625:/# psql -h mastodon_db --user mastodon
Password for user mastodon:
psql (14.6)
Type "help" for help.
mastodon=# select 1+1;
?column?
----------
2
(1 row)
mastodon=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
mastodon | mastodon | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | mastodon | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | mastodon | UTF8 | en_US.utf8 | en_US.utf8 | =c/mastodon +
| | | | | mastodon=CTc/mastodon
template1 | mastodon | UTF8 | en_US.utf8 | en_US.utf8 | =c/mastodon +
| | | | | mastodon=CTc/mastodon
(4 rows)
mastodon=# drop database mastodon;
ERROR: cannot drop the currently open database
mastodon=# \c postgres
You are now connected to database "postgres" as user "mastodon".
postgres=# drop database mastodon;
DROP DATABASE
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
postgres | mastodon | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | mastodon | UTF8 | en_US.utf8 | en_US.utf8 | =c/mastodon +
| | | | | mastodon=CTc/mastodon
template1 | mastodon | UTF8 | en_US.utf8 | en_US.utf8 | =c/mastodon +
| | | | | mastodon=CTc/mastodon
(3 rows)
mastodon=# ^D\q
83f69d649625:/#
exit
Vous pouvez désormais lancer la création de votre base de données Mastodon avec un autre conteneur jetable :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker run --rm --network=mastodon tootsuite/mastodon bash -c "DB_HOST=mastodon_db DB_USER=mastodon DB_NAME=mastodon DB_PASS=$mastodon_mdp DB_PORT=5432 SECRET_KEY_BASE=JL89YrRmt2c3 OTP_SECRET=BQy6Qivd96G2 RAILS_ENV=production bundle exec rails db:setup"
Created database 'mastodon'
Notre base est prête dans le dossier local. Arrêtons le conteneur Postgres ainsi que le réseau local :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker stop mastodon_db
mastodon_db
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker network rm mastodon
mastodon
Partie 2 : création du Docker Compose final
Mastodon requiert du TLS pour l'usage du Web. Créez tout d'abord un certificat et sa clé privée avec OpenSSL :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout ./cert-mastodon.key -out ./cert-mastodon.crt
...+...+....+...+.....+.......+...+...++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++(...)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:fr
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:mastodon.local
Email Address []:admin@mastodon.local
Ajouter maintenant un fichier nginx.conf
, en prenant garde aux valeurs utilisées dans "add_header Content-Security-Policy" : tout doit être aligné sur ce que vous allez utiliser (mastodon.local
dans notre cas).
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/ssl/certs/mastodon.crt;
ssl_certificate_key /etc/ssl/private/mastodon.key;
location / {
tcp_nodelay on;
proxy_set_header Host "mastodon.local";
proxy_set_header Origin "";
proxy_set_header Referer "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_pass_header Server;
proxy_pass http://web:3000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
add_header Strict-Transport-Security "max-age=31536000";
add_header Content-Security-Policy "base-uri 'none'; default-src 'none'; frame-ancestors 'none'; font-src 'self' http://mastodon.local; img-src 'self' http: data: blob: http://mastodon.local; style-src 'self' http://mastodon.local 'nonce-5AF868cpzAN4XYtUIsLI2A=='; media-src 'self' http: data: http://mastodon.local; frame-src 'self' http:; manifest-src 'self' http://mastodon.local; form-action 'self'; connect-src 'self' data: blob: http://mastodon.local http://mastodon.local wss://mastodon.local; script-src 'self' http://mastodon.local 'wasm-unsafe-eval'; child-src 'self' blob: http://mastodon.local; worker-src 'self' blob: http://mastodon.local";
}
}
}
Maintenant, il s'agit d'avoir un fichier .env.production
qui contiendra les valeurs partagées entre les conteneurs (ne faites pas ça dans une vraie production et éclatez votre fichiers en plusieurs !) :
LOCAL_DOMAIN=mastodon.local
REDIS_HOST=redis
REDIS_PORT=6379
DB_HOST=db
POSTGRES_USER=mastodon
DB_USER=mastodon
DB_NAME=mastodon
POSTGRES_PASSWORD=3f5z8BEByTf5 # générez un mot de passe fort
DB_PASS=3f5z8BEByTf5 # le même que celui de "POSTGRES_PASSWORD"
DB_PORT=5432
SECRET_KEY_BASE=JL89YrRmt2c3 # générez un mot de passe fort
OTP_SECRET=BQy6Qivd96G2 # générez un mot de passe fort
VAPID_PRIVATE_KEY=62S8wFzazA6K # générez un mot de passe fort
VAPID_PUBLIC_KEY=8h3aiGB8NrW5 # générez un mot de passe fort
SMTP_SERVER=
SMTP_PORT=587
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=notifications@example.com
S3_ENABLED=false
IP_RETENTION_PERIOD=31556952
SESSION_RETENTION_PERIOD=31556952
Il ne nous reste plus qu'à créer le fichier docker-compose.yml
. Notez le conteneur sidekiq
qui fera office de superviseur des traitements. La partie Web de instance peut fonctionner sans… mais vous n'auriez alors qu'aucune mise à jour d'aucune sorte avec l'extérieur (ni même l'ajout de vos abonnements) !
version: '3'
services:
frontal:
container_name: frontal
image: nginx
depends_on:
- web
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./mastodon.crt:/etc/ssl/certs/mastodon.crt
- ./mastodon.key:/etc/ssl/private/mastodon.key
ports:
- 443:443
db:
container_name: db
image: postgres:14-alpine
shm_size: 256mb
env_file: .env.production
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'postgres']
volumes:
- ./postgres14:/var/lib/postgresql/data
redis:
container_name: redis
image: redis:7-alpine
env_file: .env.production
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
volumes:
- ./redis:/data
web:
container_name: web
image: tootsuite/mastodon
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
depends_on:
- db
- redis
healthcheck:
test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1']
volumes:
- ./mastodon:/mastodon/public/system
sidekiq:
container_name: sidekiq
image: tootsuite/mastodon
env_file: .env.production
command: bundle exec sidekiq
depends_on:
- web
volumes:
- ./mastodon:/mastodon/public/system
healthcheck:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
Votre pile est désormais prête, lancez-là :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker compose up -d
[+] Running 6/6
⠿ Network article_default Created 0.0s
⠿ Container redis Started 0.8s
⠿ Container db Started 0.9s
⠿ Container web Started 1.3s
⠿ Container sidekiq Started 1.7s
⠿ Container frontal Started 1.9s
Partie 3 : compte d'administration et configuration applicative
Nous allons modifier notre fichier /etc/hosts
pour ajouter la résolution DNS fixe suivante : 127.0.0.1 mastodon.local
.
Vous pouvez désormais accéder à l'interface d'accueil : https://mastodon.local, bravo !
… Mais il reste la problématique du premier compte, qui devra aussi être celui "propriétaire" de l'instance (un administrateur est davantage "limité" en droits qu'un propriétaire d'instance). C'est assez simple :
julien@julien-Vostro-7580:~/Developpement/mastodon/article$ docker exec -u root web bash -c "RAILS_ENV=production bin/tootctl accounts create nothus --email julien.garderon@gmail.com --confirmed --force --role Owner"
OK
New password: c0f372ee29bf5f693f5a53c28013ddcd
Voilà, votre instance est prête à être utilisée.
Conclusions
Après plusieurs jours d'usage, rien de notable à signaler. J'ai rajouté quelques coups de tournevis par-ci par-là pour optimiser le tout. L'occupation mémoire est peu importante malgré la taille modeste de ma machine (à peine 1 Go de RAM pour l'ensemble des conteneurs en usage et moins d'1 vCPU au total). Je prépare par ailleurs un script "RSS vers Mastodon" pour retrouver sur mon instance, les sites habituels que je visite sous le format de profils indépendants (bots
) ; j'aurais peut-être l'occasion d'en parler ici.
Évidemment tout n'est pas rose. D'abord sur la taille occupée sur le disque : je compte pour mon seul compte et moins d'une centaine d'abonnements, une sauvegarde (non-compressée) qui progresse d'1 Mo par jour. C'est énorme (imaginez une centaine de profils avec une centaine d’abonnements en moyenne…). En prévision d'une utilisation plus poussée, j'ai rajouté 100 Go sur mon LV /var
- je vous conseille donc de prévoir "large".
Autre point noir : mon instance est nouvelle, ne pèse rien et je perds donc une "fonctionnalité" de synchronisation plus efficaces via le principe des relais. On n’y pense pas immédiatement : vous pouvez demander à d'autres de devenir un relais (bidirectionnel) auprès d'autres serveurs, pour faciliter la diffusion des inbox
des utilisateurs. Pour l'instant aucun n'a répondu positivement (https://oc.todon.fr ; https://piaille.fr ; https://framapiaf.org ; https://mastodon.social ; https://h4.io).
Cela se comprend : une instance à 1 utilisateur ne pèse rien en public potentiel et devenir un relais dans les deux sens pour une instance Mastodon exposée, est une charge constante. Si chaque instance est à utilisateur unique, la charge totale est colossale si votre propre instance devient un relais indirect pour des centaines / milliers d'autres instances individuelles (plutôt que quelques dizaines ou centaines contenant des centaines ou milliers de profils). Cette "charge de l’unité"" vaut alors donc bien pour toute la communauté.
Ne pas être relais ne veut pas dire pour autant que vous êtes coupé de la fédération ActivityPub / Mastodon : simplement, vous devez récupérer chaque profil que vous suivez individuellement, plutôt qu'avoir à rythme régulier des échanges en masse. Au niveau de Sidekiq, la charge se ressent rapidement si on démultiplie les abonnements vers une même instance. Dit autrement : j'ai davantage de connexions vers ces sites que si nous étions des relais entre nous car je fais des synchronisations individuelles de profils ; mais je ne pèse pas assez pour que cela leur donne de l'intérêt de me mettre comme relais. Ainsi comment mesurer concrément l'effort que demande mon hébergement d'instance individuelle face à un profil sur une plateforme déjà richement dotée en profils… ?
Bref, à mon sens Mastodon dans son fonctionnement, pousse tout de même naturellement la communauté à trouver les voix et moyens d'avoir plutôt des rassemblements de taille raisonnable (= à une relative "centralisation") plutôt qu'une approche strictement "individualiste". Il y a des mécaniques de confiance qui s'acquiert par la taille, comme beaucoup de réseaux sociaux. On aime ce constat ou pas, mais difficile de ne pas comprendre qu'il y a aussi des enjeux de charge système (et réseaux) qui viennent rapidement. Qui dit charge système dit ressources humaines, dit charges financières, dit sources de financement… Imaginer un réseau social totalement horizontal et unitaire me semble lointain si vraiment des centaines de millions de personnes basculent dans le "Fédivers" et décident d'avoir toute une instance individuelle. A l'inverse, n'avoir que quelques grands sites, risquent de faire basculer la logique fédérée dans une version trop centralisées, sujette à davantage de risques de dérives.
Mastodon n'est donc pas une panacée pour tous les sujets. Sa diffusion n'est pas automatiquement un avenir meilleur et profitable à tous.
Avoir sa propre instance offre des libertés et des protections de matière de vie privée (si vous faites réellement de l’auto-hébergement), mais représente aussi (beaucoup) de connexions supplémentaires pour les autres serveurs, notamment les plus exposés. Plus les systèmes "grands publics" seront "chargés" pour offrir leur contenu comme devenir des relais, plus la tentation de la publicité reviendra pour garder l'aspect "gratuit". Certaines instances pourraient devenir alors encore moins vertueuses encore que Twitter sauce Musk - poussées par la popularité, l'absence de formation des administrateurs et le besoin de survivre. Avec des problématiques de territorialité légale (l'instance est hébergée hors d'Union Européenne par exemple).
D'autant que la sécurité et la performance en soi, ne sont pas neutres en coût horaire d'entretien. Il faut aussi avoir un peu de connaissances, pas seulement de la bonne volonté. On peut vite perdre sa vie privée et numérique sociale si on ne maîtrise pas son instance individuelle.
Mastodon est un début de réponse à une problématique qui me semble bien vaste et protéiforme, qui n'est certainement pas un gage automatique de "c'est mieux que Twitter" - quand bien même je m'inscris dans une démarche pour quitter ce réseau.
Alors vient naturellement la question : vais-je ouvrir mon instance à d'autres, pour ne pas "être juste un poids" pour les autres et faire profiter d'une instance "qui tourne" ? La réponse penche aujourd'hui plutôt vers le non : c'est un engagement juridique fort (respect du droit car on agit comme alors comme diffuseur pour d'autres) et du temps pour fournir un service de qualité et fiable. Avoir quelques personnes supplémentaires pourquoi pas, mais je ne peux donner aucune garantie. Cela reposerait en outre sur une confiance mutuelle. J'ai conscience que cela peut paraître égoïste, mais beaucoup dans ceux qui montrons des instances autonomes, se poseront la question. Si l'on veut que Mastodon garde une image de liberté et de sérieux, il faut que ce qui se lancent dans l'aventure ne se comportent pas comme des idiots du temps du far west. Je préfère pour ma part afficher peu d'ambitions et s'inscrire dans une démarche raisonnable.
Aller au-delà impose a minima une structure associative pour collecter des fonds pour l'achat et l'entretien de matériels, du temps à passer pour les mises à jour, une gouvernance sur la question des limites à la liberté de parole (des limites nécessaires en démocratie, dans le respect d'une vision politique partagée, tant comme groupe qu'au sein de la société).
Ce ne sont là que quelques sujets qui émergent et doivent nous faire (en tout cas me font) réfléchir à ce que recouvrent la très large et composite notion de "régulation des réseaux sociaux" et de leur administration. Non Mastodon n'est pas la panacée pour résoudre d'un coup de baguette technique magique, les maux d'Internet et de son sous-ensemble Web. Le diable est dans les détails. Mais qu'est-ce que c'est passionnant !
# J'ai même pas mis le lien vers ma propre instance...
Posté par JulienG . Évalué à 5.
Pour me suivre : https://mastodon.nothus.fr.
# Instance n'est pas relais
Posté par tcit (site web personnel, Mastodon) . Évalué à 2.
Les instances Mastodon ne peuvent pas être utilisées comme relais, les relais sont des logiciels dédiés. Pour ma part, je ne connais aucune instance d'un relais encore active.
Exemple d'un tel logiciel : https://git.pleroma.social/pleroma/relay
[^] # Re: Instance n'est pas relais
Posté par JulienG . Évalué à 2.
En effet, après approfondissement, erreur de ma part :
https://github.com/mastodon/mastodon/discussions/17187#discussioncomment-1868314
# Alternative
Posté par Maclag . Évalué à 6.
Sinon, il y a Yunohost et au choix: le paquet Mastodon ou le paquet Pleroma.
Ça s'installe en quelques clics, et ça vient en bonus avec un serveur mail et un serveur XMPP.
[^] # Re: Alternative
Posté par Albirew (site web personnel, Mastodon) . Évalué à 1.
personnellement, j'ai choisi Misskey pour mon instance.
Avec ActivityPub d'activé, ça me prends dans les 700Mo de ram.
EFBBBFE297AFE2978EE297AF0D0AE297AFE297AFE2978E0D0AE2978EE2978EE2978E
# Merci !
Posté par Phil3556 . Évalué à 0.
Bonjour,
Merci pour cet article, l'éclairage et les détails apportés sur la mise en oeuvre d'une instance Mastodon sont très intéressants !
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.