Mastodon

Mastodon ist eine Ruby on Rails-Applikation.

Links

Installation

Frei nach https://docs.joinmastodon.org/admin/install/, aber für RHEL 9, Stand Mastodon 4.2.10:

hostnamectl set-hostname social.example.com
dnf -y install epel-release

C-Compiler, Tools und Development-Libraries installieren, damit später Ruby und Mastodon compiliert werden kann:

# enable CodeReady Linux Builder repository that contains additional packages for use by devs
crb enable

dnf -y install git tar
dnf -y install gcc g++ libicu-devel zlib-devel openssl-devel libidn-devel
dnf -y install jemalloc-devel readline-devel libedit libffi-devel libyaml-devel

NodeJS v16 und Paketmanager Yarn v22:

dnf -y install nodejs yarnpkg

Mastodon-Benutzer anlegen:

useradd --shell /sbin/nologin mastodon

In den „mastodon“-Benutzer wechseln, und Ruby 3.2.3 inkl. rbenv installieren:

su - mastodon --shell /bin/bash
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

exec bash

git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

# takes ca. 8 minutes
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 3.2.3
rbenv global 3.2.3

gem install bundler --no-document

SELinux-Berechtigungen fixen:

chcon --recursive --reference /bin /home/mastodon/.rbenv/shims/bundle

Weiter unter dem root-User:

exit

Redis v6:

dnf -y install redis
systemctl enable --now redis.service

Bild- und Videoverarbeitung:

dnf -y install ImageMagick ffmpeg-free

Mastodon bevorzugt PostgreSQL - hier kommt PostgreSQL v13 auf die Platte:

dnf -y install postgresql postgresql-server libpq-devel

PostgreSQL initialisieren:

postgresql-setup --initdb
systemctl enable --now postgresql.service

PostgreSQL-Benutzer und DB anlegen:

sudo -u postgres psql --command="CREATE USER mastodon CREATEDB;"

In den „mastodon“-Benutzer wechseln, und das Mastodon Git-Repo clonen:

su - mastodon --shell /bin/bash
git clone https://github.com/mastodon/mastodon.git live
cd live
git checkout $(git tag -l | grep '^v[0-9.]*$' | sort -V | tail -n 1)

Mit Ruby compilieren:

bundle config deployment 'true'
bundle config without 'development test'

# takes ca. 5 minutes
bundle install -j$(getconf _NPROCESSORS_ONLN)

Yarn:

# takes ca. 2 minutes
yarn install --pure-lockfile

Tipp

Falls vor der Installation die Datenbank geleert werden soll:

export DISABLE_DATABASE_ENVIRONMENT_CHECK=1

Ruby-Environment fix auf „Production“ festlegen:

echo "export RAILS_ENV=production" >> ~/.bashrc
exec bash

Die eigentliche Mastodon-Installation ist interaktiv:

export NODE_OPTIONS=--openssl-legacy-provider
bundle exec rake mastodon:setup
Your instance is identified by its domain name. Changing it afterward will break things.
Domain name: social.example.com

Single user mode disables registrations and redirects the landing page to your public profile.
Do you want to enable single user mode? yes

Are you using Docker to run Mastodon? no

PostgreSQL host: /var/run/postgresql
PostgreSQL port: 5432
Name of PostgreSQL database: mastodon
Name of PostgreSQL user: mastodon
Password of PostgreSQL user:
Database configuration works! 🎆

Redis host: localhost
Redis port: 6379
Redis password:
Redis configuration works! 🎆

Do you want to store uploaded files on the cloud? No

Do you want to send e-mails from localhost? yes
E-mail address to send e-mails "from": noreply@example.com
Send a test e-mail with this configuration right now? no

Do you want Mastodon to periodically check for important updates and notify you? (Recommended) Yes

This configuration will be written to .env.production
Save configuration? Yes

Now that configuration is saved, the database schema must be loaded.
If the database already exists, this will erase its contents.
Prepare the database now? Yes
Running `RAILS_ENV=production rails db:setup` ...

Created database 'mastodon'
Done!

The final step is compiling CSS/JS assets.
This may take a while and consume a lot of RAM.
Compile the assets now? Yes

Dauert ca. 4 Minuten. Dann:

Do you want to create an admin user straight away? Yes
Username: admin
E-mail: admin@example.com
You can login with the password: 21580289-3d83-4dff-b75f-0814b9777efc
You can change your password once you login.

Elemente wie CSS, Bilder usw. finden sich anschliessend unter /home/mastodon/live/public.

Wechsel zum root-User:

exit

Systemd-Services kopieren und aktivieren:

cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/

systemctl daemon-reload

# listens on port 3000 (main application, Ruby/Puma-Prozess)
systemctl enable --now mastodon-web.service

systemctl enable --now mastodon-sidekiq.service

# listens port 4000 (/api/v1/streaming, Node.js-Prozess)
systemctl enable --now mastodon-streaming.service

Mastodon benötigt einen lokalen Reverse Proxy, da es beispielsweise statische Dateien nicht selbst ausliefert. Hier wird der Einsatz von Nginx empfohlen:

dnf -y install nginx
/etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    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;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/default.d/*.conf;
}
cp /home/mastodon/live/dist/nginx.conf /etc/nginx/default.d/mastodon.conf

/etc/nginx/default.d/mastodon.conf muss an die eigene Maschine angepasst werden. Wichtig: Das Zertifikat für die Domain muss ebenfalls auf der Mastodon-Maschine abgelegt werden, und die Chain muss zuerst das Server-, dann die CA-Zertifikate aufweisen:

/etc/nginx/default.d/mastodon.conf
# replace all example.com

ssl_certificate     /etc/pki/tls/certs/social.example.com-chain.crt;
ssl_certificate_key /etc/pki/tls/private/social.example.com.key;

Dann:

systemctl enable --now nginx.service

Firewall anpassen, Inbound Port 80 und 443 freigeben.

Konfiguration

Konfigurationsanpassungen (https://docs.joinmastodon.org/admin/config/):

  • entweder in der /home/mastodon/live/.env.production

  • oder in in einer Systemd-Overwrite-Datei, beispielsweise /etc/systemd/system/mastodon-web.service.d/override.conf und Einträgen wie Environment="BIND=192.2.0.8"

Non-interactive Setup

Dafür wird eine vorausgefüllte /home/mastodon/live/.env.production benötigt (siehe https://docs.joinmastodon.org/admin/config/). Die Schritte, mastodon:setup ausführt, müssen manuell durchgeführt werden.

/home/mastodon/live/.env.production
# This is a sample configuration file. You can generate your configuration
# with the `rake mastodon:setup` interactive setup wizard, but to customize
# your setup even further, you'll need to edit it manually. This sample does
# not demonstrate all available configuration options. Please look at
# https://docs.joinmastodon.org/admin/config/ for the full documentation.

# Note that this file accepts slightly different syntax depending on whether
# you are using `docker-compose` or not. In particular, if you use
# `docker-compose`, the value of each declared variable will be taken verbatim,
# including surrounding quotes.
# See: https://github.com/mastodon/mastodon/issues/16895

# Federation
# ----------
# This identifies your server and cannot be changed safely later
# ----------
LOCAL_DOMAIN=social.example.com

SINGLE_USER_MODE=true

# Redis
# -----
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=

# PostgreSQL
# ----------
DB_HOST=/var/run/postgresql
DB_USER=mastodon
DB_NAME=mastodon
DB_PASS=
DB_PORT=5432

# Elasticsearch (optional)
# ------------------------
ES_ENABLED=true
ES_HOST=localhost
ES_PORT=9200
# Authentication for ES (optional)
ES_USER=elastic
ES_PASS=password

# Secrets
# -------
# Make sure to use `rake secret` to generate secrets
# -------
SECRET_KEY_BASE=301a839e72f6613195f9706d73c7587e3a78dad8e78263d074214729c573f84de332ccbe7bdd2708adcb03fd1d80c00a0e1700447c5257cbd1d3200469a76fe2
OTP_SECRET=54ff0d3a9101bed287ac0ad61808fee331fe42a8921a0ebc926abb006d47a5986a784f53ac42d5df1cf8b6181e0bd610296b74d1b8572c0b188fd903928b1f71

# Web Push
# --------
# Generate with `rake mastodon:webpush:generate_vapid_key`
# --------
VAPID_PRIVATE_KEY=-ruXWh6nFNXuchhHl_gwhp85li6cdm02UFYijLMjK3M=
VAPID_PUBLIC_KEY=BM4HxCQtnhA5t5sLqDmteJmLMf75epzESHJZKqEQ3pzCS44P-b3gTqTrrfHE_UJUYQlR7YhdIK6-yuhDixl3MkY=

# Sending mail
# ------------
SMTP_SERVER=localhost
SMTP_PORT=25
SMTP_AUTH_METHOD=none
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=noreply@example.com
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_ENABLE_STARTTLS=auto

# File storage (optional)
# -----------------------
S3_ENABLED=false
S3_BUCKET=files.example.com
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
S3_ALIAS_HOST=files.example.com

# IP and session retention
# -----------------------
# Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml
# to be less than daily if you lower IP_RETENTION_PERIOD below two days (172800).
# -----------------------
IP_RETENTION_PERIOD=31556952
SESSION_RETENTION_PERIOD=31556952

Apache vHost-Config

Mögliche Konfiguration eines Apache vHosts, inkl. Reverse Proxy-Funktionalität:

<VirtualHost *:80>
    ServerName social.example.com

    <Location /.well-known/acme-challenge/>
        Allow from all
    </Location>

    <Location />
        Redirect permanent / https://social.example.com/
    </Location>
</VirtualHost>

<VirtualHost *:443>
    ServerName social.example.com
    DocumentRoot /home/mastodon/live/public

    SSLCertificateFile /etc/letsencrypt/live/social.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/social.example.com/privkey.pem

    KeepAliveTimeout 70
    EnableSendfile on
    LimitRequestBody 104857600

    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml image/x-icon
        DeflateCompressionLevel 6
        DeflateBuffersize 8096
        DeflateFilterNote Input instream
        DeflateFilterNote Output outstream
    </IfModule>

    <Location />
        ProxyPass http://127.0.0.1:3000/
        ProxyPassReverse http://127.0.0.1:3000/
        ProxyPreserveHost On
    </Location>

    <Location "/sw.js">
        Header set Cache-Control "public, max-age=604800, must-revalidate"
        Header set Strict-Transport-Security "max-age=63072000; includeSubDomains"
        RewriteEngine On
        RewriteRule ^ - [L,R=404]
    </Location>

    <LocationMatch "^/assets/|^/avatars/|^/emoji/|^/headers/|^/packs/|^/shortcuts/|^/sounds/">
        Header set Cache-Control "public, max-age=2419200, must-revalidate"
        Header set Strict-Transport-Security "max-age=63072000; includeSubDomains"
        RewriteEngine On
        RewriteRule ^ - [L,R=404]
    </LocationMatch>

    <LocationMatch "^/system/">
        Header set Cache-Control "public, max-age=2419200, immutable"
        Header set Strict-Transport-Security "max-age=63072000; includeSubDomains"
        Header set X-Content-Type-Options nosniff
        Header set Content-Security-Policy "default-src 'none'; form-action 'none'"
        RewriteEngine On
        RewriteRule ^ - [L,R=404]
    </LocationMatch>

    <Location "/api/v1/streaming">
        ProxyPass http://127.0.0.1:4000/
        ProxyPassReverse http://127.0.0.1:4000/
        ProxyPreserveHost On
        ProxyAddHeaders On
        RequestHeader set Connection "upgrade"
        RequestHeader set Upgrade "http_upgrade"

        Header set Strict-Transport-Security "max-age=63072000; includeSubDomains"
        SetEnvIf Request_URI "^/api/v1/streaming" connection_upgrade=Upgrade
    </Location>
</VirtualHost>

toolctl

Mit toolctl wird Mastodon auf der Kommandozeile administriert. Das Tool ist nicht das schnellste und benötigt knapp 8 Sekunden, um allein seine Hilfe-Seite anzuzeigen.

su - mastodon --shell /bin/bash
live/bin/tootctl help

toolctl Cheat Sheet:

Commands:
  tootctl accounts SUBCOMMAND ...ARGS                # Manage accounts
  tootctl cache SUBCOMMAND ...ARGS                   # Manage cache
  tootctl canonical_email_blocks SUBCOMMAND ...ARGS  # Manage canonical e-mail blocks
  tootctl domains SUBCOMMAND ...ARGS                 # Manage account domains
  tootctl email_domain_blocks SUBCOMMAND ...ARGS     # Manage e-mail domain blocks
  tootctl emoji SUBCOMMAND ...ARGS                   # Manage custom emoji
  tootctl feeds SUBCOMMAND ...ARGS                   # Manage feeds
  tootctl help [COMMAND]                             # Describe available commands or one specific command
  tootctl ip_blocks SUBCOMMAND ...ARGS               # Manage IP blocks
  tootctl maintenance SUBCOMMAND ...ARGS             # Various maintenance utilities
  tootctl media SUBCOMMAND ...ARGS                   # Manage media files
  tootctl preview_cards SUBCOMMAND ...ARGS           # Manage preview cards
  tootctl search SUBCOMMAND ...ARGS                  # Manage the search engine
  tootctl self-destruct                              # Erase the server from the federation
  tootctl settings SUBCOMMAND ...ARGS                # Manage dynamic settings
  tootctl statuses SUBCOMMAND ...ARGS                # Manage statuses
  tootctl upgrade SUBCOMMAND ...ARGS                 # Various version upgrade utilities
  tootctl version                                    # Show version

Mastodon updaten

TODO

Troubleshooting

journalctl -feu mastodon-*.service

Built on 2024-09-16