# [Anleitung] Mastodon-Server v4.6.x inkl. Elasticsearch (Volltextsuche) via Docker Compose
Hallo zusammen,
hier ist ein fertiges, praxiserprobtes Docker Compose Setup für eure eigene Mastodon-Instanz. Diese Konfiguration enthält bereits den Suchserver **Elasticsearch**, um eine schnelle Volltextsuche auf eurer Instanz zu ermöglichen. Das Setup läuft komplett isoliert in einem internen Docker-Netzwerk.
### ⚠️ Wichtige Vorbereitung
Bevor ihr den Stack startet, müsst ihr einmalig eure eigenen geheimen Schlüssel generieren. Führt dazu folgende Befehle auf eurem Server aus:
bash
# 1. SECRET_KEY_BASE generieren:
docker run --rm -it ghcr.io/mastodon/mastodon:v4.6.3 bundle exec rake secret
# 2. OTP_SECRET generieren:
docker run --rm -it ghcr.io/mastodon/mastodon:v4.6.3 bundle exec rake secret
# 3. VAPID-Schlüsselpaar generieren (Public und Private Key):
docker run --rm -it ghcr.io/mastodon/mastodon:v4.6.3 bundle exec rake mastodon:webpress:generate_vapid_keys
Ersetzt die generierten Werte und die Domain-Platzhalter im folgenden Code, bevor ihr den Stack deploit.
---
### Die
docker-compose.yml
yaml
version: '3.8'
services:
db:
image: postgres:14-alpine
restart: always
shm_size: 256mb
environment:
POSTGRES_DB: mastodon_production
POSTGRES_USER: mastodon
POSTGRES_PASSWORD: DEIN_SICHERES_DATENBANK_PASSWORT
volumes:
- db_data:/var/lib/postgresql/data
networks:
- mastodon-intern
redis:
image: redis:7-alpine
restart: always
volumes:
- redis_data:/data
networks:
- mastodon-intern
es:
image: docker.io/library/elasticsearch:7.17.22
restart: always
environment:
- "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
- "discovery.type=single-node"
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- mastodon-intern
web:
image: ghcr.io/mastodon/mastodon:v4.6.3
restart: always
command: bundle exec rails s -p 3000 -b '0.0.0.0'
environment:
RAILS_ENV: production
LOCAL_DOMAIN: deine-domain.de
WEB_DOMAIN: deine-domain.de
LOCAL_HTTPS: true
STREAMING_API_BASE_URL: wss://deine-domain.de
DB_HOST: db
DB_USER: mastodon
DB_NAME: mastodon_production
DB_PASS: DEIN_SICHERES_DATENBANK_PASSWORT
DB_PORT: 5432
REDIS_HOST: redis
REDIS_PORT: 6379
ES_ENABLED: true
ES_HOST: es
ES_PORT: 9200
IP_RETENTION_PERIOD: 31556952
CHEWY_EAGER_LOAD: false
SECRET_KEY_BASE: DEIN_GENERIERTER_SECRET_KEY_BASE
OTP_SECRET: DEIN_GENERIERTER_OTP_SECRET
VAPID_PRIVATE_KEY: DEIN_GENERIERTER_VAPID_PRIVATE_KEY
VAPID_PUBLIC_KEY: DEIN_GENERIERTER_VAPID_PUBLIC_KEY
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: DEIN_GENERIERTER_SECRET_KEY_BASE
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: DEIN_GENERIERTER_OTP_SECRET
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: DEINE_GENERIERTE_32_ZEICHEN_KETTE
TRUSTED_PROXY_IP: 172.16.0.0/12
RAILS_SERVER_TO_ROOT: true
SMTP_SERVER: dein-smtp-relay.de
SMTP_PORT: 25
SMTP_LOGIN: webmaster
SMTP_PASSWORD: DeinSicheresRelayPasswort
SMTP_FROM_ADDRESS: notifications@deine-domain.de
SMTP_AUTH_METHOD: login
SMTP_OPENSSL_VERIFY_MODE: none
SMTP_ENABLE_STARTTLS_AUTO: false
networks:
- mastodon-intern
ports:
- "8282:3000"
volumes:
- system_data:/mastodon/public/system
depends_on:
- db
- redis
- es
streaming:
image: ghcr.io/mastodon/mastodon-streaming:v4.6.3
restart: always
command: node ./streaming/index.js
environment:
NODE_ENV: production
BIND: 0.0.0.0
PORT: 4000
LOCAL_DOMAIN: deine-domain.de
WEB_DOMAIN: deine-domain.de
LOCAL_HTTPS: true
DB_HOST: db
DB_USER: mastodon
DB_NAME: mastodon_production
DB_PASS: DEIN_SICHERES_DATENBANK_PASSWORT
DB_PORT: 5432
REDIS_HOST: redis
REDIS_PORT: 6379
networks:
- mastodon-intern
ports:
- "4000:4000"
depends_on:
- db
- redis
sidekiq:
image: ghcr.io/mastodon/mastodon:v4.6.3
restart: always
command: bundle exec sidekiq
environment:
RAILS_ENV: production
LOCAL_DOMAIN: deine-domain.de
WEB_DOMAIN: deine-domain.de
LOCAL_HTTPS: true
DB_HOST: db
DB_USER: mastodon
DB_NAME: mastodon_production
DB_PASS: DEIN_SICHERES_DATENBANK_PASSWORT
DB_PORT: 5432
REDIS_HOST: redis
REDIS_PORT: 6379
ES_ENABLED: true
ES_HOST: es
ES_PORT: 9200
IP_RETENTION_PERIOD: 31556952
CHEWY_EAGER_LOAD: false
SECRET_KEY_BASE: DEIN_GENERIERTER_SECRET_KEY_BASE
OTP_SECRET: DEIN_GENERIERTER_OTP_SECRET
VAPID_PRIVATE_KEY: DEIN_GENERIERTER_VAPID_PRIVATE_KEY
VAPID_PUBLIC_KEY: DEIN_GENERIERTER_VAPID_PUBLIC_KEY
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: DEIN_GENERIERTER_SECRET_KEY_BASE
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: DEIN_GENERIERTER_OTP_SECRET
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: DEINE_GENERIERTE_32_ZEICHEN_KETTE
TRUSTED_PROXY_IP: 172.16.0.0/12
RAILS_SERVER_TO_ROOT: true
SMTP_SERVER: dein-smtp-relay.de
SMTP_PORT: 25
SMTP_LOGIN: webmaster
SMTP_PASSWORD: DeinSicheresRelayPasswort
SMTP_FROM_ADDRESS: notifications@deine-domain.de
SMTP_AUTH_METHOD: login
SMTP_OPENSSL_VERIFY_MODE: none
SMTP_ENABLE_STARTTLS_AUTO: false
volumes:
- system_data:/mastodon/public/system
networks:
- mastodon-intern
depends_on:
- db
- redis
- es
volumes:
db_data:
redis_data:
system_data:
es_data:
networks:
mastodon-intern:
driver: bridge
---
### 💾 Festplatte sauber halten (Automatisches Löschen)
Da Mastodon extreme Mengen an externen Medien (Bilder, Avatare, Vorschaukarten) im Cache speichert, läuft der Server ohne Pflege schnell voll. Richtet auf eurem Host-System unbedingt diese automatischen Cronjobs (
crontab -e) ein.
**Wichtig bei Docker:** Die Befehle müssen im Hintergrund über den Ruby-Bundler (
bundle exec tootctl) direkt im Sidekiq-Container ausgeführt werden, da sie sonst nicht funktionieren!
text
# Jeden Tag um 03:00 Uhr: Externe Mediendateien loeschen (Aelter als 7 Tage)
0 3 * * * docker exec -t mastodon-server-sidekiq-1 bundle exec tootctl media remove --days 7 > /dev/null 2>&1
# Jeden Tag um 03:15 Uhr: Alte Fremd-Beitraege aus der SQL-Datenbank werfen (Loest Medien-Sperren)
15 3 * * * docker exec -t mastodon-server-sidekiq-1 bundle exec tootctl statuses remove --days 30 > /dev/null 2>&1
# Jeden Tag um 03:30 Uhr: Alte Link-Vorschaukarten entfernen
30 3 * * * docker exec -t mastodon-server-sidekiq-1 bundle exec tootctl preview_cards remove --days 14 > /dev/null 2>&1
# Jeden Sonntag um 04:00 Uhr: Profildaten und Avatare inaktiver externer Accounts aufraeumen
0 4 * * 0 docker exec -t mastodon-server-sidekiq-1 bundle exec tootctl media remove --days 7 --prune-profiles > /dev/null 2>&1
*(Hinweis: Falls euer Stack einen Projektnamen-Präfix nutzt, müsst ihr den Containernamen
mastodon-server-sidekiq-1 in den Cronjobs eventuell anpassen).*