Mastodon Operations - esslingen.social

Hier landen Infos und „learnings“ zu Installation, Betrieb und Administration der Mastodon Instanz esslingen.social

Basis Setup - dockerized

Diese Instanz läuft als Gruppe von Docker Containern mit docker compose. Die postgresql Datenbank ist normalerweise ein eigener Container (mastodon-db), hier aber auf einen zentralen Datenbank-Server ausgelagert. Der optionale elasticsearch Service (für Volltextsuche) läuft ebenfalls nicht als Docker Container, sondern als Service auf dem Host. Da elasticsearch ziemlich speicherhungrig ist, kann man ihn ggf. später auf eine eigene Maschine umlagern. Der fertige Container Cluster besteht aus

  • mastodon-sidekiq-1
  • mastodon-streaming-1
  • mastodon-web-1
  • mastodon-redis-1

Vor den Containern läuft ein Load Balancer, der auch das https Protokoll beisteuert (zur Zeit haproxy). Hier einige zentrale Informationsquellen, aus denen die Installationsschritte zusammengesucht wurden:

Weitere Doku

Diskussion

Bisher leider nur auf mastodon/mastodon · Discussions · GitHub

Initialer Setup

Dies erzeugt die Werte für die Umgebungsvariablen in der Datei .env.production

docker run -it --rm tootsuite/mastodon bundle exec rake mastodon:setup

.env.production

Federation  
# ----------  
# This identifies your server and cannot be changed safely later  
# ----------  
LOCAL_DOMAIN=esslingen.social  
  
# Redis  
# -----  
REDIS_HOST=x.x.x.x
REDIS_PORT=6379  
REDIS_PASSWORD=xxxx

# PostgreSQL  
# ----------  
DB_HOST=x.x.x.x
DB_USER=mastodon  
DB_NAME=mastodon  
DB_PASS=xxxx
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 `bundle exec rails secret` to generate secrets  
# -------  
SECRET_KEY_BASE=

SMTP_FROM_ADDRESS=noreply@netzwissen.de
  
# 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  
  
# Optional list of hosts that are allowed to serve media for your instance  
# EXTRA_MEDIA_HOSTS=https://data.example1.com,https://data.example2.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=xxxxxxxxxxx
SESSION_RETENTION_PERIOD=xxxxxxxxxxx

Docker Networks

docker-compose: horchende IPs/ports einstellen. default ist localhost, was nicht von aussen sichtbar wäre.

NETWORK ID NAME DRIVER SCOPE
cf14c65aa61c bridge bridge local
ed8f3249aa2b gitea_default bridge local
7311abb900d2 host host local
d7bad067f715 mastodon_external_network bridge local
03653e915e6d mastodon_internal_network bridge local
400c8847417e none null local
root@docker1:/etc/docker/mastodon#

Secret Base

Mastodon braucht einen Reihe von sectrets, die einmal erzeugt werden und die man nicht nachträglich ändern sollte.

To generate keys for SECRET_KEY_BASE & OTP_SECRET run

docker run --rm -it --entrypoint /bin/bash lscr.io/linuxserver/mastodon:latest generate-secret

once for each.

More Secrets

Run bin/rails db:encryption:init to generate new secrets and then assign the environment variables
.
web-1 | Do not change the secrets once they are set, as doing so may cause data loss and other issues that w
ill be difficult or impossible to recover from.
web-1 | [7] ! Unable to load application: SystemExit:
web-1 | Mastodon now requires that these variables are set:
web-1 |
web-1 | - ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
web-1 | - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
web-1 | - ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
web-1 |
.

Add the following secret environment variables to your Mastodon environment (e.g. .env.production), ensure they are shared across all your nodes and do not change them after they are set:

ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Web Push

Generate with bundle exec rails mastodon:webpush:generate_vapid_key

VAPID_PRIVATE_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VAPID_PUBLIC_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Datenbank neu erstellen

Die Postgres Datenbank wird in diesem Fall nicht als Container betrieben, sondern auf einer anderen VM. Mit diesem Schalter in der .env.production kann eine Datenbank komplett überschreiben und für diesen Fall ganz neu angelegt werden:

# for destructive recreation of database
DISABLE_DATABASE_ENVIRONMENT_CHECK=1

docker run -it --rm tootsuite/mastodon bundle exec rake mastodon:setup

Did you not create the database, or did you delete it? To create the database, run:

sidekiq-1 | bin/rails db:create

Elasticsearch

Elasticsearch wird dringend empfohlen, hier aber als separater Service auf der Host Maschine betrieben. Doku: Configuring full-text search - Mastodon documentation

Elasticsearch braucht viel RAM Speicher. Nach der Konfiguration von elasticsearch und der erfolgreichen Verbindung von Mastodon mit elasticsearch muss man den Volltext-Index über tootctl aktivieren. Falls elasticsearch dabei crasht, haben wir zu wenig Speicher. Aktuell läuft die VM mit 8 GB virutellem RAM. Ob das reicht, wird man sehen.

Tootctl

tootctl ist das zentrale CLI Werkzeug für Mastodon. Es wird im Container aufgerufen.

https://docs.joinmastodon.org/admin/tootctl/

Einsteig in den Container mit docker exec -t -i [container-id] /bin/bash

mastodon@66b766aa9853:~$ bin/tootctl
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

Administratives Konto

Dieses Konto wird über tootctl mit der Rolle „Owner“ erzeugt.

RAILS_ENV=production bin/tootctl accounts create \
  alice \
  --email alice@example.com \
  --confirmed \
  --role Owner

Zurücksetzen eines Kontos

Das Zurücksetzen setzt ein generiertes Passwort. Der Anwender bekommt eine Mail und kann das Passwort anschliessend aktualisieren.

tootctl accounts modify [username] --reset-password 

mastodon@66b766aa9853:~$ bin/tootctl accounts modify admin
OK
mastodon@66b766aa9853:~$ bin/tootctl accounts modify admin --reset-password
INFO  2026-04-22T13:08:13.815Z pid=645 tid=1x1: Sidekiq 8.0.9 connecting to Redis with options {size: 10, pool_name: "internal", url: "redis://redis:6379/0", driver: :hiredis}
OK
New password: d1486538ff1206bd2ebf3425d995dd09
mastodon@66b766aa9853:~$ 

Konfiguration der Instanz

E-Mail-Anbindung per SMTP

Es gibt zur Zeit keine vernünftige Dokumentation für die Anbindung der E-Mail Kommunikation per SMTP. Entweder es funktioniert oder nicht. Aber ein hiilfreiches ruby Skript von martinmodrak (Martin Modrák) · GitHub auf need Mastodon outgoing email diagnostics · Issue #7323 · mastodon/mastodon · GitHub

Das Skript muss nach /lib/tasks/testemail.rake gespeichert werden.

# frozen_string_literal: true

require 'tty-prompt'

namespace :mastodon do
  desc 'Test e-mail'
  task :testemail do
    prompt = TTY::Prompt.new

    send_to = ENV['send_to']
    enable_starttls = nil
    enable_starttls_auto = nil
   
    case ENV['SMTP_ENABLE_STARTTLS']
      when 'always'
        enable_starttls = true
      when 'never'
        enable_starttls = false
      when 'auto'
        enable_starttls_auto = true
      else
        enable_starttls_auto = ENV['SMTP_ENABLE_STARTTLS_AUTO'] != 'false'
      end

    begin
      ActionMailer::Base.smtp_settings = {
        port: ENV['SMTP_PORT'],
        address: ENV['SMTP_SERVER'],
        user_name: ENV['SMTP_LOGIN'].presence,
        password: ENV['SMTP_PASSWORD'].presence,
        domain: ENV['LOCAL_DOMAIN'],
        authentication: ENV['SMTP_AUTH_METHOD'] == 'none' ? nil : ENV['SMTP_AUTH_METHOD'] || :plain,
        openssl_verify_mode: ENV['SMTP_OPENSSL_VERIFY_MODE'],
        enable_starttls: enable_starttls,
        enable_starttls_auto: enable_starttls_auto,
      }

      ActionMailer::Base.default_options = {
        from: ENV['SMTP_FROM_ADDRESS'],
      }
      
      mail = ActionMailer::Base.new.mail(
        to: send_to,
        subject: 'Test', # rubocop:disable Rails/I18nLocaleTexts
        body: 'Mastodon SMTP configuration works!'
      )
      mail.deliver
      prompt.say("Success")
    rescue => e
      prompt.error 'E-mail could not be sent with this configuration, try again.'
      prompt.error e.message
    end
  end
end  

Start mit

RAILS_ENV=production bin/rails mastodon:testemail send_to=target@email.com