Mautic mit Docker installieren: Open-Source-Marketing-Automation als HubSpot-Alternative
Mautic 7.2.1 mit dem offiziellen Docker-Compose-Beispiel einrichten: Installer, SMTP-Test mit Mailpit, Cron und Worker, Backup und Wiederherstellung. Alle Schritte auf Docker CE nachgestellt.
Werbung Mit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Mautic ist eine Open-Source-Plattform für Marketing-Automation: Kontakte und Segmente, E-Mail-Kampagnen, Formulare, Landingpages und mehrstufige Kampagnenabläufe. Wer HubSpot oder ActiveCampaign ersetzen und die Kontaktdaten im eigenen Rechenzentrum halten will, findet hier den Docker-Weg. Die Anleitung folgt dem offiziellen Beispiel examples/basic aus dem Repository mautic/docker-mautic, legt die Versionen fest, ergänzt Mailpit als SMTP-Testziel und zeigt Sicherung und Wiederherstellung. Die Anleitung bezieht sich auf Mautic 7.2.1 und MySQL 8.4 auf Docker CE.
Voraussetzungen
- Linux-Server oder VM mit Docker Engine und Compose-Plugin v2, Architektur amd64 oder arm64 (das Image
mautic/mautic:7.2.1-apachegibt es für beide). Einrichtung: Docker und Docker Compose auf Linux installieren. - 2 CPU-Kerne und 4 GB RAM. Im Test belegte der Stack direkt nach der Installation rund 1 GB RAM (MySQL etwa 590 MB, Worker 230 MB, Web 180 MB); mit wachsender Kontaktzahl und Kampagnen steigt der Bedarf.
- Rund 5 GB freier Speicher für die Images (Mautic etwa 3,1 GB, MySQL) plus Platz für Datenbank, Medien und Backups.
- Für den Produktivbetrieb eine eigene Domain mit HTTPS über einen Reverse Proxy und ein SMTP-Zugang (eigener Mailserver oder Versanddienst) mit SPF, DKIM und DMARC für die Absenderdomain.
- Rechtlich: Für Newsletter brauchen Sie eine nachweisbare Einwilligung (Double-Opt-in) und einen Vertrag zur Auftragsverarbeitung mit Ihrem Versanddienst. Dieser Beitrag ist keine Rechtsberatung.
Eckdaten
| Dienst | Image | Aufgabe | Daten |
|---|---|---|---|
| db | mysql:8.4.11 | Datenbank | Volume mysql-data |
| mautic_web | mautic/mautic:7.2.1-apache | Weboberfläche, Port 8080 → 80 | ./mautic/config, logs, media |
| mautic_cron | wie Web, DOCKER_MAUTIC_ROLE=mautic_cron | Segmente, Kampagnen, Trigger alle 15 Minuten | wie Web |
| mautic_worker | wie Web, DOCKER_MAUTIC_ROLE=mautic_worker | Warteschlangen für E-Mails und Seitenaufrufe | wie Web |
| mailpit | axllent/mailpit:v1.31.5 | SMTP-Testziel, Weboberfläche 8025 | keine |
Schritt 1: Projektordner und Umgebungsdateien anlegen
$ sudo mkdir -p /opt/mautic/mautic/{config,logs,media/files,media/images}
$ cd /opt/mautic
$ openssl rand -hex 24 # zweimal ausführen: Datenbank- und Root-PasswortDie Datei .env liest Docker Compose für die Platzhalter in der compose.yaml:
# /opt/mautic/.env
COMPOSE_PROJECT_NAME=mautic
MYSQL_DATABASE=mautic
MYSQL_USER=mautic
MYSQL_PASSWORD=ERSTES-ZUFALLSPASSWORT
MYSQL_ROOT_PASSWORD=ZWEITES-ZUFALLSPASSWORT
DOCKER_MAUTIC_LOAD_TEST_DATA=falseDie Datei .mautic_env geht als env_file an alle drei Mautic-Container. Compose ersetzt darin die ${…}-Verweise mit den Werten aus der .env. Als Host steht mysql, der Alias, den die compose.yaml über links: db:mysql vergibt.
# /opt/mautic/.mautic_env
MAUTIC_DB_HOST="mysql"
MAUTIC_DB_PORT="3306"
MAUTIC_DB_DATABASE="${MYSQL_DATABASE}"
MAUTIC_DB_USER="${MYSQL_USER}"
MAUTIC_DB_PASSWORD="${MYSQL_PASSWORD}"
MAUTIC_MESSENGER_DSN_EMAIL="doctrine://default"
MAUTIC_MESSENGER_DSN_HIT="doctrine://default"
PHP_INI_VALUE_DATE_TIMEZONE="Europe/Berlin"doctrine://default legt die Warteschlangen in die MySQL-Datenbank; ein RabbitMQ ist damit nicht nötig. Ein chown der Ordner war im Test nicht nötig: Das Image legte config/local.php beim Start selbst mit dem Besitzer www-data an.
ls -a /opt/mautic zeigt .env, .mautic_env und den Ordner mautic, grep -c ZUFALLSPASSWORT .env ergibt 0 (alle Platzhalter ersetzt).
Schritt 2: compose.yaml erstellen
Gegenüber dem offiziellen Beispiel sind die Image-Tags festgelegt (dort mysql:lts und mautic/mautic:latest), Neustartregeln ergänzt und Mailpit hinzugefügt. Mailpit lauscht nur auf 127.0.0.1 und dient ausschließlich dem Test.
x-mautic-volumes:
&mautic-volumes
- ./mautic/config:/var/www/html/config:z
- ./mautic/logs:/var/www/html/var/logs:z
- ./mautic/media/files:/var/www/html/docroot/media/files:z
- ./mautic/media/images:/var/www/html/docroot/media/images:z
services:
db:
image: mysql:8.4.11
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: mysqladmin --user=$$MYSQL_USER --password=$$MYSQL_PASSWORD ping
start_period: 5s
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
mautic_web:
image: mautic/mautic:7.2.1-apache
links:
- db:mysql
ports:
- 8080:80
volumes: *mautic-volumes
environment:
- DOCKER_MAUTIC_LOAD_TEST_DATA=${DOCKER_MAUTIC_LOAD_TEST_DATA}
env_file:
- .mautic_env
healthcheck:
test: curl http://localhost
start_period: 5s
interval: 5s
timeout: 5s
retries: 100
depends_on:
db:
condition: service_healthy
restart: unless-stopped
mautic_cron:
image: mautic/mautic:7.2.1-apache
links:
- db:mysql
volumes: *mautic-volumes
environment:
- DOCKER_MAUTIC_ROLE=mautic_cron
env_file:
- .mautic_env
depends_on:
mautic_web:
condition: service_healthy
restart: unless-stopped
mautic_worker:
image: mautic/mautic:7.2.1-apache
links:
- db:mysql
volumes: *mautic-volumes
environment:
- DOCKER_MAUTIC_ROLE=mautic_worker
env_file:
- .mautic_env
depends_on:
mautic_web:
condition: service_healthy
restart: unless-stopped
mailpit:
image: axllent/mailpit:v1.31.5
ports:
- "127.0.0.1:8025:8025"
restart: unless-stopped
volumes:
mysql-data:Hinter einem Reverse Proxy auf demselben Server ändern Sie die Portzeile in 127.0.0.1:8080:80, damit Mautic nur über den Proxy erreichbar ist.
docker compose config --quiet endet ohne Ausgabe. docker compose config | grep MAUTIC_DB_PASSWORD zeigt Ihr Passwort statt eines leeren Werts.
Schritt 3: Stack starten
$ docker compose pull
$ docker compose up -d
$ docker compose psDer Web-Container startet erst, wenn MySQL gesund ist; Cron und Worker warten wiederum auf den Web-Container. Vor der Installation schreibt der Cron-Container regelmäßig Waiting for Mautic to be installed ins Log. Das ist erwartet.
Nach etwa einer Minute zeigt docker compose ps db und mautic_web als healthy, mautic_cron, mautic_worker und mailpit als Up. curl -sI http://localhost:8080/ | grep -i location verweist auf /index.php/installer.
Schritt 4: Installationsassistent durchlaufen
Öffnen Sie http://SERVER-IP:8080. Der Assistent prüft zuerst die Umgebung und meldet „Ready to Install!“. Im Datenbankschritt sind Treiber, Host mysql, Port, Datenbankname und Benutzer bereits aus .mautic_env vorbelegt. Das Passwortfeld bleibt leer: Ohne Eingabe bricht die Installation im Test mit Access denied for user 'mautic'@… (using password: NO) ab. Tragen Sie dort MYSQL_PASSWORD aus der .env ein.

Im zweiten Schritt legen Sie den Administrator an. Verwenden Sie einen eigenen Benutzernamen statt admin und ein langes Passwort. Der Datenbankschritt dauert beim Anlegen der Tabellen ein bis zwei Minuten; danach leitet Mautic auf die Anmeldeseite.

Ohne Browser geht es auch per Konsole, wie im README des Docker-Repositorys beschrieben: docker compose exec --user www-data --workdir /var/www/html mautic_web php ./bin/console mautic:install https://mautic.example.de --admin_email=… --admin_password=….
Die Anmeldung mit dem neuen Konto öffnet das Dashboard, unten links steht v7.2.1. docker compose exec --user www-data mautic_web php ./bin/console --version meldet Mautic 7.2.1.
Schritt 5: E-Mail-Versand mit Mailpit prüfen
Testen Sie den Versand zunächst gegen Mailpit, damit keine Testmail an echte Kontakte geht. Öffnen Sie über das Zahnrad Configuration → Email Settings. Tragen Sie unter Email DSN Schema smtp, Host mailpit und Port 1025 ein, darüber Absendername und Absenderadresse. Klicken Sie auf Save und danach auf Send test email: Der Test nutzt immer die gespeicherte DSN, nicht die gerade eingetippten Werte.

Die Testmail geht an die Adresse des angemeldeten Benutzers. Sie sehen sie in der Mailpit-Oberfläche unter http://127.0.0.1:8025 auf dem Server (per SSH-Tunnel: ssh -L 8025:127.0.0.1:8025 server). Für den Echtbetrieb ersetzen Sie Host, Port, Benutzer und Passwort durch die Daten Ihres Versanddienstes (meist Port 587 mit STARTTLS) und entfernen den Dienst mailpit aus der compose.yaml. Hintergrund zu Mailpit: Mailpit per Docker Compose einrichten.
curl -s http://127.0.0.1:8025/api/v1/messages | grep -o '"Subject":"[^"]*"' liefert "Subject":"Mautic test email". Im Test kam die Mail mit dem eingetragenen Absender an.
Schritt 6: Cron und Worker prüfen
Ohne Cron aktualisiert Mautic keine Segmente und führt keine Kampagnen aus. Der Cron-Container bringt einen vorkonfigurierten Zeitplan mit: Segmente zu den Minuten 0, 15, 30 und 45, Kampagnen 5 Minuten später, Trigger weitere 5 Minuten später. Der Worker-Container verarbeitet die Warteschlangen für E-Mails, Seitenaufrufe und fehlgeschlagene Nachrichten mit je zwei Prozessen (DOCKER_MAUTIC_WORKERS_CONSUME_*).
$ docker compose exec mautic_cron cat /opt/mautic/cron/mautic
$ docker compose logs --tail 5 mautic_worker
$ docker compose exec --user www-data --workdir /var/www/html mautic_web php ./bin/console mautic:segments:updateEigene Zeitpläne binden Sie über einen Ordner ./cron nach /opt/mautic/cron ein (im offiziellen Beispiel als auskommentierte Zeile vorbereitet).
Der erste Befehl zeigt die Crontab mit mautic:segments:update, mautic:campaigns:update und mautic:campaigns:trigger. Das Worker-Log enthält Quit the worker with CONTROL-C, und der manuelle Segmentlauf endet mit Exit-Code 0.
Schritt 7: Backup und Wiederherstellung
Zu sichern sind die Datenbank (Kontakte, Kampagnen, E-Mails) und der Ordner mautic (config/local.php mit Zugangsdaten und Geheimschlüssel, hochgeladene Medien) samt .env, .mautic_env und compose.yaml:
$ cd /opt/mautic && mkdir -p backup
$ docker compose exec -T db sh -c 'exec mysqldump --single-transaction --no-tablespaces -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' | gzip > backup/mautic-db-$(date +%F).sql.gz
$ sudo tar czf backup/mautic-files-$(date +%F).tar.gz mautic .env .mautic_env compose.yamlWiederherstellung auf einem leeren Host: Dateiarchiv entpacken, nur die Datenbank starten, den Dump einspielen, dann den Rest starten. Warten Sie nach dem ersten Start von MySQL, bis im Log ready for connections mit port: 3306 steht. Im Test schlug ein Import direkt nach dem ersten healthy fehl, weil MySQL zu diesem Zeitpunkt noch seine Erstinitialisierung abschloss; der zweite Versuch lief sauber durch.
$ sudo tar xzf backup/mautic-files-DATUM.tar.gz
$ docker compose up -d db
$ docker compose logs db | grep "port: 3306"
$ gunzip -c backup/mautic-db-DATUM.sql.gz | docker compose exec -T db sh -c 'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"'
$ docker compose up -dIm Test wurde ein Kontakt mit einer Marker-Adresse angelegt, gesichert, der gesamte Stack samt Volume und Ordner mautic gelöscht und wiederhergestellt. Danach startete Mautic direkt ins Dashboard statt in den Installer, die Anmeldung funktionierte, der Kontakt war in der Kontaktliste vorhanden und die SMTP-Einstellung erhalten.
gunzip -c backup/mautic-db-DATUM.sql.gz | grep -c "INSERT INTO \`leads\`" ist größer null. Nach einer Wiederherstellung leitet curl -sI http://localhost:8080/ auf /s/dashboard statt auf den Installer, und die Kontaktsuche findet einen bekannten Kontakt. Mehr zur Ablage außerhalb des Servers: 3-2-1-Backup-Strategie praktisch umsetzen.
Schritt 8: Updates einspielen
Sichern Sie wie in Schritt 7. Ändern Sie dann den Tag aller drei Mautic-Dienste in der compose.yaml auf die neue Version aus den Release Notes, etwa mit sed -i 's/7.2.1-apache/NEUE-VERSION-apache/' compose.yaml, und starten Sie neu:
$ docker compose pull
$ docker compose up -d
$ docker compose logs mautic_web | grep -i migrationLaut Startskript des Images führt der Web-Container bei einer bestehenden Installation beim Start doctrine:migrations:migrate aus. Springen Sie nicht über Hauptversionen hinweg, sondern folgen Sie dem Upgrade-Pfad in der Mautic-Dokumentation. MySQL aktualisieren Sie getrennt und nur innerhalb von 8.4.
docker compose exec --user www-data mautic_web php ./bin/console --version zeigt die neue Version, alle Dienste laufen, und das Log enthält keine Fehler aus den Migrationen.
Typische Fehler
- „Access denied … (using password: NO)“ im Installer
Das Passwortfeld im Datenbankschritt wurde leer gelassen. Passwort aus der
.enveintragen.- Testmail kommt nicht an
Die Einstellungen wurden vor dem Test nicht gespeichert; der Test nutzt die gespeicherte DSN, die unter der Schaltfläche angezeigt wird.
- Cron-Log meldet dauerhaft „Waiting for Mautic to be installed“
Die Installation ist nicht abgeschlossen oder
config/local.phpfehlt im eingebundenen Ordner.- „mkfifo: cannot create fifo '/tmp/stdout': File exists“
nach einem Neustart des Cron-Containers: Im Test blieb Cron trotzdem aktiv (
cron -flief). Bei Zweifeln den Container mitdocker compose up -d --force-recreate mautic_cronneu erzeugen.- Restore: Importfehler direkt nach dem Start
MySQL war noch in der Erstinitialisierung. Auf
port: 3306im Log warten und erneut importieren.- Kampagnen laufen nicht
mautic_cronodermautic_workergestoppt.docker compose psprüfen.
Häufige Fragen
Warum drei Mautic-Container?
Alle nutzen dasselbe Image, die Variable DOCKER_MAUTIC_ROLE legt die Aufgabe fest. So lassen sich Web, Zeitplan und Warteschlangen getrennt neu starten und skalieren.
Geht PostgreSQL oder MariaDB?
Das offizielle Docker-Beispiel und der Installer setzen auf MySQL (Treiber MySQL PDO). Diese Anleitung bleibt deshalb bei MySQL 8.4; andere Datenbanken prüfen Sie vorab gegen die Systemanforderungen der eingesetzten Mautic-Version.
Brauche ich RabbitMQ?
Nein. Mit doctrine://default liegen die Warteschlangen in MySQL. Für sehr große Versandmengen gibt es im Repository das Beispiel rabbitmq-worker.
Wie binde ich HTTPS an?
Über einen Reverse Proxy wie Traefik mit automatischem HTTPS oder Nginx Proxy Manager. Tragen Sie danach unter Configuration → System Settings die öffentliche HTTPS-Adresse als Site URL ein, sonst enthalten Tracking-Links und E-Mails die interne Adresse.
Lassen sich Demodaten laden?
Ja, mit DOCKER_MAUTIC_LOAD_TEST_DATA=true vor der ersten Installation. Das Startskript installiert dann eine Demo-Instanz mit Beispieldaten; für den Produktivbetrieb bleibt der Wert auf false.
Fazit
Mit dem offiziellen Compose-Beispiel, festgelegten Tags und den drei Rollen-Containern steht Mautic in rund einer halben Stunde. Zwei Stellen kosten im Alltag Zeit: das leere Datenbankpasswort im Installer und der Mailtest, der nur gespeicherte Einstellungen nutzt. Wer den Versand erst gegen Mailpit prüft, regelmäßig Dump und Ordner sichert und die Wiederherstellung einmal durchspielt, betreibt die Marketing-Automation mit überschaubarem Aufwand selbst. Für einfache Newsletter ohne Kampagnenlogik ist Listmonk die schlankere Alternative.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren
- Traefik als Docker-Reverse-Proxy mit automatischem HTTPS
- Mailpit per Docker Compose einrichten
- Docker Compose absichern: Secrets, Healthchecks, Non-Root
- Offizielles Beispiel examples/basic (mautic/docker-mautic)
- docker-mautic: README mit Umgebungsvariablen und Konsolenbefehlen
- mautic/mautic auf Docker Hub
- Mautic-Dokumentation


