Zammad 7.1.3 mit Docker Compose installieren und betreiben
Zammad 7.1.3 lässt sich mit der offiziellen Compose-Datei zügig aufsetzen, scheitert auf kleinen Servern aber gern am Healthcheck des Rails-Servers und am Speicherbedarf von Elasticsearch. Diese Anleitung zeigt den kompletten Weg mit echten Messwerten, Fehlermeldungen im Wortlaut und den Lösungen aus einem eigenen Testlauf.

Zammad ist ein quelloffenes Ticketsystem für Support und Service-Desk. Diese Anleitung beschreibt die Installation der Version 7.1.3 mit Docker Compose auf einem Linux-Server, den realen Startverlauf inklusive der Stolperfallen, die dabei tatsächlich aufgetreten sind, sowie Betrieb, Backup und Deinstallation. Alle Zeiten, Fehlermeldungen und Speicherwerte in diesem Text stammen aus einem eigenen Testlauf vom 13.09.2026 auf einem Host mit zwei vCPU und 5,4 GB RAM, davon rund 3 GB frei, Docker 29.1.3 und Compose 2.40.3.
Wichtig vorweg: Dieser Artikel trennt konsequent zwischen dem, was selbst ausgeführt und beobachtet wurde, und dem, was nur der offiziellen Dokumentation entnommen ist. Selbst getestet wurden Erstinstallation, Startverlauf, der Healthcheck-Abbruch, die HTTP-Erreichbarkeit, ein Datenbank-Dump, die Volume-Liste und die vollständige Deinstallation. Nicht selbst getestet wurden der Betrieb mit Elasticsearch, der Einrichtungsassistent im Browser, ein vollständiger Restore-Lauf und der Update-Pfad im Livebetrieb. Das ist an den jeweiligen Stellen gekennzeichnet.
Was Zammad ist und für wen es sich lohnt
Zammad bündelt Anfragen aus E-Mail, Webformular, Telefonnotiz, Chat und Social-Media-Kanälen in einem gemeinsamen Ticketbestand. Jede Anfrage wird zu einem Ticket mit Verlauf, Zuständigkeit, Priorität und Zeitstempeln. Für ein Support-Team ersetzt das die geteilte Mailbox, in der niemand zuverlässig sagen kann, wer gerade antwortet und welche Anfrage seit vier Tagen liegen geblieben ist.
Das Projekt steht auf GitHub unter zammad/zammad, ist unter AGPL-3.0 lizenziert und mit 5.908 Sternen sowie einem letzten Push am 11.09.2026 aktiv gepflegt. Das separate Compose-Repository zammad/zammad-docker-compose kommt auf 382 Sterne, das Release v17.0.0 stammt vom 10.09.2026 und pinnt den Image-Tag 7.1.3-0011. Keines der beiden Repositories ist archiviert. Alle Zahlen wurden am 13.09.2026 über die GitHub-API abgerufen.
- Passend für Teams ab etwa drei Personen, die gemeinsam auf denselben Posteingang antworten müssen.
- Passend, wenn nachvollziehbar dokumentiert sein muss, wann wer was zugesagt hat.
- Passend, wenn Fachabteilungen eigene Gruppen mit eigenen Berechtigungen brauchen.
- Passend, wenn Textbausteine, Makros und Automatisierungen wiederkehrende Antworten abkürzen sollen.
Grenzen und wann Zammad nicht passt
Zammad ist kein leichtgewichtiges Werkzeug. Der Stack besteht aus mindestens neun Containern, braucht PostgreSQL, Redis und Memcached und ist für die Volltextsuche auf Elasticsearch ausgelegt. Wer lediglich eine geteilte Inbox mit Zuweisung sucht, fährt mit einer schlankeren Lösung oft besser. Ebenso ist Zammad kein Asset-Management und keine Inventarisierung, auch wenn es Objekte pro Kunde verwalten kann.
- Nicht passend auf Hosts mit weniger als 4 GB RAM, dazu unten mehr.
- Nicht passend, wenn ausschließlich IT-Inventar und Lizenzen verwaltet werden sollen.
- Nicht passend für Einzelpersonen, die nur ein Kontaktformular auswerten.
- Nicht passend, wenn kein Wartungsfenster für Datenbankmigrationen bei Updates eingeplant werden kann.
- Ein Downgrade auf eine ältere Version ist laut Zammad-Dokumentation nicht vorgesehen, der Rückweg führt nur über einen Datenbank-Restore. Das wurde hier nicht selbst geprüft.
Voraussetzungen und realistischer Ressourcenbedarf
Der wichtigste Punkt zuerst, weil er in vielen Anleitungen fehlt: Elasticsearch startet im offiziellen Compose-Stack mit dem Standardwert -Xms1g -Xmx1g. Zusammen mit dem restlichen Zammad-Stack, der im Test rund 1,5 GB belegte, passt das nicht in 3 GB freien Arbeitsspeicher. Im Testlauf wurde Elasticsearch deshalb bewusst weggelassen. Zammad läuft dann vollständig, nur ohne Volltextsuche über Tickets und Anhänge.
Die gemessenen Werte aus docker stats --no-stream kurz nach dem Start, ohne Elasticsearch: zammad-scheduler 388 MiB, zammad-init 382 MiB, zammad-websocket 277 MiB, zammad-railsserver 273 MiB, zammad-postgresql 108 MiB, zammad-nginx 27 MiB, zammad-backup 26 MiB, zammad-redis 17 MiB, zammad-memcached 11 MiB. In Summe rund 1,5 GB, der Host meldete 2.770 MB belegt von 5.402 MB.
- Mindestens 4 GB RAM ohne Elasticsearch, damit Peaks beim Start nicht ins Swap laufen.
- 6 bis 8 GB RAM mit Elasticsearch, je nach Ticketmenge und gewähltem Heap.
- Zwei CPU-Kerne reichen für den Start, verlängern ihn aber spürbar. Der Rails-Boot dauerte im Test rund 170 Sekunden.
- Plattenplatz großzügig planen: Vor dem Pull waren 9,9 GB frei, danach nur noch 5,5 GB. Das Zammad-Image allein bringt 1,47 GB mit.
- Für Elasticsearch muss
vm.max_map_countmindestens 262144 betragen, geprüft mitsysctl vm.max_map_count. Auf dem Testhost stand der Wert bereits auf 1048576, der bekannte Startfehler trat deshalb nicht auf.
Unterstützte Plattformen und getestete Versionen
Der Compose-Stack läuft auf jedem Linux-Host mit aktueller Docker Engine und dem Compose-Plugin. Der hier dokumentierte Lauf fand auf Ubuntu mit Docker 29.1.3 und Compose 2.40.3 statt. Auf NAS-Systemen mit eingeschränkter Container-Oberfläche ist der Stack grundsätzlich lauffähig, wurde hier aber nicht erprobt. Die folgenden Image-Versionen kamen zum Einsatz und stammen unverändert aus der offiziellen Compose-Datei.
| Komponente | Image und Tag | Rolle im Stack |
|---|---|---|
| Zammad | ghcr.io/zammad/zammad:7.1.3-0011 | Basis für init, railsserver, scheduler, websocket, nginx, backup |
| PostgreSQL | postgres:17.11-alpine | Primäre Datenhaltung, alle Tickets und Stammdaten |
| Redis | redis:8.10.1-alpine | Hintergrundjobs und Websocket-Zustand |
| Memcached | memcached:1.6.45-alpine | Anwendungs-Cache, gestartet mit 256 MB |
| Elasticsearch | elasticsearch:9.5.3 | Volltextsuche, im Test bewusst nicht gestartet |
Compose-Datei und die wichtigen Blöcke
Die offizielle docker-compose.yml ist mehrere hundert Zeilen lang und enthält fast ausschließlich durchgereichte Umgebungsvariablen. Sie sollte nicht abgeschrieben, sondern direkt bezogen werden, damit spätere Korrekturen des Projekts mitkommen.
# Arbeitsverzeichnis anlegen und wechseln
mkdir -p /opt/zammad && cd /opt/zammad
# Offizielle Compose-Datei unveraendert herunterladen
curl -fsSLO https://raw.githubusercontent.com/zammad/zammad-docker-compose/master/docker-compose.yml
Drei Blöcke lohnen einen genaueren Blick. Erstens der YAML-Anker x-shared: Alle Zammad-Container teilen sich dasselbe Image und denselben Umgebungsblock und unterscheiden sich nur im command. Zweitens der Healthcheck des Rails-Servers, der später noch eine Rolle spielt.
zammad-railsserver:
<<: *zammad-service
command: ["zammad-railsserver"]
healthcheck:
test: ["CMD", "curl", "-sf", "http://127.0.0.1:${ZAMMAD_RAILSSERVER_PORT:-3000}"]
interval: 30s
timeout: 5s
start_period: 120s
retries: 3
Drittens die Rollentrennung in PostgreSQL. Das Postgres-Image legt seine Bootstrap-Rolle immer als Superuser an. Die aktuelle Compose-Datei nutzt diese Rolle deshalb nur noch für Administration und erzeugt über ein initdb-Skript eine separate, unprivilegierte Login-Rolle für Zammad, der die Datenbank gehört.
zammad-postgresql:
environment:
POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_SUPERUSER_PASS:-${POSTGRES_PASS:-zammad}}
ZAMMAD_DB: ${POSTGRES_DB:-zammad_production}
ZAMMAD_DB_USER: ${POSTGRES_USER:-zammad}
ZAMMAD_DB_PASS: ${POSTGRES_PASS:-zammad}
Daraus folgt ein konkreter Härtungspunkt: POSTGRES_SUPERUSER_PASS fällt auf POSTGRES_PASS zurück, wenn es nicht gesetzt ist. Wer nur das Anwendungspasswort ändert, lässt also einen Superuser mit demselben Passwort zurück. Beide Variablen gehören gesetzt, mit unterschiedlichen Werten. Ebenfalls zu beachten: Das initdb-Skript läuft ausschließlich bei einem leeren Datenverzeichnis. Bestehende Installationen behalten das Rollen-Layout, mit dem sie einst erzeugt wurden.
Umgebungsvariablen in der env-Datei
Die Compose-Datei bleibt unverändert, sämtliche Anpassungen gehören in eine .env im selben Verzeichnis. Die folgende Datei wurde im Test genau so verwendet. Die Passwörter sind Platzhalter und müssen ersetzt werden.
NGINX_EXPOSE_PORT=18081
ELASTICSEARCH_ENABLED=false
ELASTICSEARCH_JAVA_OPTS=-Xms256m -Xmx256m
POSTGRES_PASS=testpass123
RESTART=on-failure
Für einen produktiven Betrieb kommen weitere Variablen dazu. Die folgende Tabelle listet die praktisch relevanten mit ihrer Bedeutung.
| Variable | Standard | Bedeutung und Hinweis |
|---|---|---|
| NGINX_EXPOSE_PORT | 8080 | Hostport der Weboberfläche. Bei belegtem 8080 frei wählen. |
| VERSION | 7.1.3-0011 | Image-Tag. Pinnen, damit ein Pull nicht ungeplant eine neue Version zieht. |
| POSTGRES_PASS | zammad | Passwort der Anwendungsrolle. Zwingend ändern. |
| POSTGRES_SUPERUSER_PASS | Wert von POSTGRES_PASS | Passwort des Datenbank-Superusers. Separat setzen, sonst identisch mit dem App-Passwort. |
| POSTGRES_SUPERUSER | postgres | Name der Bootstrap-Rolle. Muss sich von POSTGRES_USER unterscheiden, sonst bricht initdb ab. |
| ELASTICSEARCH_ENABLED | leer | Schaltet die Anbindung in der Anwendung ab. Verhindert den Containerstart nicht. |
| ELASTICSEARCH_JAVA_OPTS | -Xms1g -Xmx1g | Heap der Suchmaschine. Auf kleinen Hosts der wichtigste Stellhebel. |
| ZAMMAD_FQDN | leer | Öffentlicher Hostname. Wird in Links und ausgehenden Mails verwendet. |
| ZAMMAD_HTTP_TYPE | http | Auf https setzen, sobald ein Reverse Proxy mit TLS davor steht. |
| NGINX_SERVER_NAME | leer | server_name des internen nginx. Meist identisch mit ZAMMAD_FQDN. |
| RAILS_TRUSTED_PROXIES | leer | Netze des vorgelagerten Proxys, damit echte Client-IPs im Log landen. |
| TZ | Europe/Berlin | Zeitzone für Zeitstempel und geplante Aufgaben. |
| BACKUP_TIME | 03:00 | Uhrzeit des integrierten Backup-Laufs. |
| HOLD_DAYS | 10 | Aufbewahrungsdauer der integrierten Backups in Tagen. |
| RESTART | always | Neustartverhalten. In Testumgebungen on-failure, produktiv always. |
Installation Schritt für Schritt
Die folgende Sequenz entspricht dem tatsächlich ausgeführten Lauf. Der Syntaxcheck vor dem Start kostet zwei Sekunden und erspart einen halben Abend Fehlersuche, wenn sich in der .env ein Tippfehler versteckt hat.
# In das Verzeichnis mit compose-Datei und .env wechseln
cd /opt/zammad
# Syntax und Variablenaufloesung pruefen, ohne etwas zu starten
docker compose config -q
# Stack starten, Elasticsearch bewusst weglassen
docker compose up -d --scale zammad-elasticsearch=0
Der Parameter --scale zammad-elasticsearch=0 ist der entscheidende Punkt auf kleinen Hosts. Die Variable ELASTICSEARCH_ENABLED=false allein hindert nur die Anwendung daran, die Suchmaschine zu verwenden. Der Container startet trotzdem und belegt seinen vollen Heap. Wer die Suche dauerhaft nicht braucht, sollte den Dienst über eine Override-Datei mit replicas: 0 abschalten oder den Scale-Parameter konsequent bei jedem Aufruf mitgeben.
Start und was dabei wirklich passiert
Der erste Start ist kein Vorgang von Sekunden. Der beobachtete Ablauf vom 13.09.2026 sah so aus: Um 08:10:10 begann der Image-Pull, gegen 08:16 war er abgeschlossen, Zammad mit 1,47 GB, PostgreSQL mit 424 MB, Redis mit 160 MB und Memcached mit 20 MB. Zwischen 08:16 und 08:18 meldeten sich PostgreSQL, Redis und Memcached als healthy, parallel fuhr zammad-init die Rails-Migrationen. Um 08:18:14 schrieb der Init-Container Setting.set('app_version', "20260913061814") ins Log.
Zwischen 08:18:28 und 08:19:42 schlug der Healthcheck des Rails-Servers dreimal mit ExitCode 7 fehl, der Status wechselte auf unhealthy. Um 08:20:57, also rund zwei Minuten und fünfzig Sekunden nach Containerstart, war der Rails-Server healthy. Um 08:21:07 wurde zammad-nginx nachgestartet, um 08:21:33 antwortete die Oberfläche mit HTTP 200. Insgesamt rund elf Minuten inklusive Pull, rund fünfeinhalb Minuten ab Containerstart.
Dass die Installation frisch ist und der Assistent noch aussteht, lässt sich ohne Browser prüfen:
# Setup-Status der Instanz abfragen
curl -s http://127.0.0.1:18081/api/v1/getting_started
Die Antwort im Test lautete {"setup_done":false,"import_mode":false,"import_backend":"","system_online_service":false}.
Der Healthcheck-Abbruch und seine Lösung
Das ist der Fehler, an dem die meisten Erstinstallationen auf kleiner Hardware hängen bleiben. docker compose up -d bricht mit einer Fehlermeldung ab, obwohl inhaltlich alles korrekt läuft:
Container test-zammad-zammad-railsserver-1 Error
dependency failed to start: container test-zammad-zammad-railsserver-1 is unhealthy
Das Health-Log dazu zeigt dreimal denselben Befund: {"Status":"unhealthy","FailingStreak":3,"Log":[{"ExitCode":7,"Output":""},{"ExitCode":7,"Output":""},{"ExitCode":7,"Output":""}]}. ExitCode 7 von curl bedeutet connection refused. Der Prozess ist also nicht abgestürzt, er war schlicht noch nicht so weit.
Die Rechnung dahinter: start_period: 120s, danach interval: 30s bei retries: 3. Spätestens nach rund 210 Sekunden muss Rails antworten. Auf zwei langsamen Kernen brauchte der Boot länger, die drei Versuche waren vorher aufgebraucht. Da zammad-nginx per depends_on: service_healthy am Rails-Server hängt, wurde der nginx-Container nie gestartet und blieb im Status Created. Genau deshalb ist die Oberfläche nach dem vermeintlich gescheiterten Start nicht erreichbar.
Der schnelle Weg: abwarten, bis der Rails-Server von selbst healthy meldet, dann nginx nachziehen. Beides wurde so verifiziert.
# Gesundheitsstatus des Rails-Containers abfragen
docker inspect --format '{{.State.Health.Status}}' zammad-zammad-railsserver-1
# Sobald healthy: nginx nachstarten
docker compose up -d zammad-nginx
Der dauerhafte Weg führt über eine docker-compose.override.yml neben der Originaldatei. Compose führt beide automatisch zusammen, die offizielle Datei bleibt damit unverändert und update-fähig.
services:
zammad-railsserver:
healthcheck:
start_period: 300s
retries: 10
Erstkonfiguration im Browser
Nach dem erfolgreichen Start ist die Oberfläche unter http://SERVER-IP:18081/ erreichbar. Dort führt ein Einrichtungsassistent durch die Anlage des ersten Administratorkontos, der Organisation, der Kanäle und optional eines E-Mail-Postfachs. Dieser Assistent wurde im Testlauf nicht durchlaufen, geprüft wurde ausschließlich die Erreichbarkeit mit HTTP 200 und der Setup-Status über die API. Die folgenden Punkte stammen daher aus der offiziellen Dokumentation und sollten bei der eigenen Einrichtung verifiziert werden.
- Das erste angelegte Konto erhält Administratorrechte. Es sollte ein persönliches Konto sein, kein geteiltes Sammelkonto.
- Die Basis-URL muss zum späteren öffentlichen Namen passen, sonst zeigen Links in Benachrichtigungen auf die interne Adresse.
- E-Mail-Kanäle lassen sich per IMAP oder POP3 anbinden, der Versand getrennt davon über SMTP.
- Ohne Elasticsearch steht die Volltextsuche nicht zur Verfügung. Tickets bleiben über Filter und Übersichten auffindbar.
- Die Instanz sollte erst nach Abschluss des Assistenten aus dem Internet erreichbar gemacht werden, sonst kann ein Fremder das erste Administratorkonto anlegen.
Funktions- und Healthchecks im Betrieb
Für die laufende Überwachung genügen wenige Befehle. Der erste zeigt, welcher Container in welchem Zustand ist, der zweite liefert eine schnelle Erreichbarkeitsprüfung, die sich auch in ein Monitoring einhängen lässt.
# Status aller Container des Stacks
docker compose ps
# Erreichbarkeit der Oberflaeche als reiner Statuscode
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18081/
# Speicherverbrauch aller laufenden Container, einmalige Momentaufnahme
docker stats --no-stream
# Logs des Init-Containers, hier laufen die Migrationen
docker compose logs -f zammad-init
Ein Detail aus den Messwerten verdient Erwähnung: Der Container zammad-init lief auch nach Abschluss der Migrationen weiter und zeigte dabei zeitweise nahezu vollständige CPU-Auslastung eines Kerns. Auf Hosts mit wenigen Kernen sollte man das im Blick behalten, bevor man vorschnell auf ein Problem schließt.
Persistente Daten und Volumes
Der Stack legt fünf benannte Volumes an. Die Namen tragen den Projektnamen als Präfix, also den Namen des Verzeichnisses, in dem die Compose-Datei liegt. Die folgende Liste wurde real mit docker volume ls geprüft.
postgresql-datanach/var/lib/postgresql/data: die Datenbank mit allen Tickets und Stammdaten, das wichtigste Volume.zammad-storagenach/opt/zammad/storage: Anhänge und abgelegte Dateien.zammad-backupnach/var/tmp/zammad: Ablage des integrierten Backup-Containers.redis-datanach/data: Hintergrundjobs und Sitzungszustand.elasticsearch-data: der Suchindex, bei Bedarf vollständig neu aufbaubar.
Auf dem Host liegen die Daten unter /var/lib/docker/volumes/NAME/_data. Wer dort direkt mit dem Dateisystem hantiert, sollte den zugehörigen Container vorher stoppen. Eine laufende PostgreSQL-Instanz verträgt kein Kopieren ihres Datenverzeichnisses im laufenden Betrieb.
Sichere Netzwerkfreigabe und Reverse Proxy mit TLS
Der mitgelieferte nginx-Container spricht reines HTTP. Er gehört nicht direkt ins Internet, sondern hinter einen Reverse Proxy, der TLS terminiert. Die konkrete Proxy-Einrichtung ist auf S-EDV bereits ausführlich beschrieben, deshalb hier nur die Zammad-Seite der Konfiguration. Vier Variablen entscheiden darüber, ob Zammad hinter dem Proxy korrekt arbeitet.
ZAMMAD_FQDN: der öffentliche Hostname, etwasupport.example.com. Er landet in generierten Links und ausgehenden Benachrichtigungen.ZAMMAD_HTTP_TYPE=https: sorgt dafür, dass erzeugte Links das richtige Schema tragen. Ohne diese Einstellung verweisen Mails auf http, obwohl der Proxy TLS anbietet.NGINX_SERVER_NAME: derserver_namedes internen nginx, in aller Regel identisch mit dem FQDN.RAILS_TRUSTED_PROXIES: das Netz des vorgelagerten Proxys, damit Rails die weitergereichte Client-IP akzeptiert und nicht die Proxy-Adresse protokolliert.
ZAMMAD_FQDN=support.example.com
ZAMMAD_HTTP_TYPE=https
NGINX_SERVER_NAME=support.example.com
RAILS_TRUSTED_PROXIES=172.16.0.0/12
Zusätzlich sollte der Hostport nicht öffentlich lauschen. Wenn Proxy und Zammad auf demselben Host laufen, gehört die Portveröffentlichung an 127.0.0.1 gebunden, etwa über eine Override-Datei. Andernfalls ist die Anwendung trotz Proxy weiterhin unverschlüsselt über den Hostport erreichbar und umgeht damit jede Zugriffsregel des Proxys.
Backup und Wiederherstellung
Zammad bringt einen eigenen Backup-Container mit, der täglich zur in BACKUP_TIME gesetzten Uhrzeit nach /var/tmp/zammad schreibt und Stände gemäß HOLD_DAYS aufbewahrt. Im Testlauf war das Volume noch leer, weil BACKUP_ON_START=false gilt. Ein Sofortlauf lässt sich manuell anstoßen.
# Integriertes Backup sofort ausloesen
docker compose exec -u 0 zammad-backup zammad-backup
Unabhängig davon ist ein eigener Datenbank-Dump sinnvoll, weil er sich leichter versionieren und auf einen anderen Host übertragen lässt. Die folgenden beiden Befehle wurden real ausgeführt, der Dump umfasste bei der frischen Installation 17 MB.
# Datenbank als SQL-Dump sichern
docker compose exec -T zammad-postgresql pg_dump -U zammad -d zammad_production > zammad.sql
# Anhaenge und Dateien aus dem storage-Volume als Archiv sichern
docker run --rm -v zammad_zammad-storage:/d -v "$PWD":/b alpine \
tar czf /b/zammad-storage.tgz -C /d .
Der Rückweg ist dokumentiert, wurde in diesem Testlauf aber nicht ausgeführt. Die Befehle sind daher als ungeprüft zu behandeln und gehören vor dem Ernstfall einmal auf einem Testsystem durchgespielt. Wichtig ist, die Anwendungscontainer vorher zu stoppen, damit während des Einspielens niemand schreibt.
# Anwendungsdienste stoppen, Datenbank laeuft weiter
docker compose stop zammad-railsserver zammad-scheduler zammad-websocket zammad-nginx
# SQL-Dump zurueckspielen
cat zammad.sql | docker compose exec -T zammad-postgresql psql -U zammad -d zammad_production
# Dateien zurueckspielen
docker run --rm -v zammad_zammad-storage:/d -v "$PWD":/b alpine \
sh -c 'rm -rf /d/* && tar xzf /b/zammad-storage.tgz -C /d'
# Alles wieder hochfahren
docker compose up -d
Updates und die Grenzen des Rollbacks
Der Update-Weg besteht aus drei Befehlen. Der Init-Container übernimmt die Datenbankmigrationen automatisch, sein Log ist beim Update die interessanteste Quelle. Dieser Ablauf wurde nicht live über einen Versionssprung geprüft, die Migrationsschritte des Init-Containers sind jedoch aus dem Erstinstallationslog belegt.
# In das Stack-Verzeichnis wechseln
cd /opt/zammad
# Neue Images beziehen
docker compose pull
# Stack mit den neuen Images neu erzeugen
docker compose up -d
# Migrationen mitlesen
docker compose logs -f zammad-init
Drei Punkte sind vor jedem Update zu beachten. Erstens: immer zuerst ein Backup, weil Migrationen das Schema verändern. Zweitens: Ein Downgrade wird laut Zammad-Dokumentation nicht unterstützt, Rails-Migrationen sind nicht rückwärtskompatibel. Der einzige Rückweg ist ein Restore der Datenbank auf den Stand vor dem Update. Drittens: Laut Dokumentation dürfen Major-Versionen nicht übersprungen werden, die Upgrade-Kette ist einzuhalten. Diese beiden letzten Punkte stammen aus der Dokumentation und wurden hier nicht selbst nachgestellt.
Praktische Konsequenz für den Betrieb: Wer VERSION in der .env auf einen konkreten Tag pinnt, entscheidet selbst über den Zeitpunkt eines Versionssprungs. Ohne Pin zieht ein docker compose pull unter Umständen eine neue Version, deren Migration sich nicht mehr zurücknehmen lässt.
Typische Fehler mit Diagnose und Lösung
Die folgende Übersicht fasst die im Test tatsächlich aufgetretenen sowie die naheliegenden Fehlerbilder zusammen. Die ersten drei Zeilen beruhen auf eigener Beobachtung.
| Symptom | Ursache | Abhilfe |
|---|---|---|
| dependency failed to start: container zammad-railsserver-1 is unhealthy | Rails-Boot dauert länger als die rund 210 Sekunden des Healthchecks | Warten bis healthy, dann zammad-nginx nachstarten. Dauerhaft start_period und retries per Override erhöhen. |
| Oberfläche nicht erreichbar, zammad-nginx im Status Created | Folge des obigen Abbruchs, die Abhängigkeit wurde nie erfüllt | docker compose up -d zammad-nginx |
| Host läuft beim Start voll, Container werden beendet | Elasticsearch belegt per Standard 1 GB Heap zusätzlich zu rund 1,5 GB Stack | --scale zammad-elasticsearch=0 oder ELASTICSEARCH_JAVA_OPTS reduzieren |
| Suche liefert keine Treffer, Tickets sind aber vorhanden | Elasticsearch läuft nicht oder ist nicht angebunden | Suchmaschine starten und Reindex anstoßen, oder bewusst ohne Volltextsuche betreiben |
| initdb bricht mit Hinweis auf identische Rollen ab | POSTGRES_USER und POSTGRES_SUPERUSER tragen denselben Namen | Namen unterscheiden, Volume postgresql-data entfernen, neu starten |
| Links in Benachrichtigungen zeigen auf http oder die interne IP | ZAMMAD_FQDN und ZAMMAD_HTTP_TYPE nicht gesetzt | Beide Variablen setzen und den Stack neu erzeugen |
| Elasticsearch startet nicht, Hinweis auf max virtual memory areas | vm.max_map_count unter 262144 | Kernelparameter dauerhaft in /etc/sysctl.d anheben |
Ein vierter Punkt aus dem Test betrifft nicht Zammad selbst, sondern den Host: Der Plattenplatz sank durch den Pull von 9,9 GB auf 5,5 GB freien Speicher. Wer mehrere umfangreiche Stacks nacheinander ausprobiert, sollte zwischendurch mit docker image prune -a -f aufräumen, sonst ist die Platte schneller voll als erwartet.
Saubere Deinstallation
Warnung vorab: Der folgende Ablauf löscht alle Daten unwiderruflich. Der Schalter -v entfernt die benannten Volumes, damit die Datenbank mit sämtlichen Tickets und das Storage-Volume mit allen Anhängen. Es gibt danach keinen Weg zurück außer einem zuvor erstellten Backup. Wer nur vorübergehend stoppen möchte, verwendet docker compose down ohne -v oder besser docker compose stop.
# Stack stoppen und ALLE Volumes loeschen, unwiderruflicher Datenverlust
cd /opt/zammad && docker compose down -v
# Arbeitsverzeichnis entfernen
cd .. && rm -rf /opt/zammad
# Kontrolle: es darf nichts mehr uebrig bleiben
docker ps -a | grep zammad
docker volume ls | grep zammad
# Nicht mehr benoetigte Images entfernen
docker image prune -a -f
Dieser Ablauf wurde im Test ausgeführt, beide Kontrollbefehle lieferten anschließend eine leere Ausgabe. Die Deinstallation hinterlässt bei dieser Vorgehensweise keine Reste auf dem Host.
Fazit aus dem Testlauf
Zammad 7.1.3 lässt sich mit der offiziellen Compose-Datei ohne Anpassung an der YAML-Datei installieren, sämtliche Konfiguration passt in eine .env. Die beiden Hürden sind vorhersehbar und keine Fehler der Software: Der Healthcheck des Rails-Servers ist auf zügige Hardware ausgelegt, und Elasticsearch bringt einen Speicherbedarf mit, der auf kleinen Hosts nicht eingeplant ist. Wer beides vorher kennt, hat den Stack in rund fünf Minuten ab Containerstart erreichbar.
Für den produktiven Einsatz bleiben drei Aufgaben, die über diese Anleitung hinausgehen und vor dem Livegang erledigt sein sollten: ein Reverse Proxy mit TLS, ein geprüfter Restore-Lauf auf einem Testsystem und eine Entscheidung darüber, ob die Volltextsuche gebraucht wird. Letztere bestimmt maßgeblich, wie groß der Server ausfallen muss.
Passende Anleitungen auf S-EDV
- Docker Compose Grundlagen und Stacks: erklärt Aufbau, Override-Dateien und Umgebungsvariablen, die in dieser Anleitung vorausgesetzt werden.
- Nginx Proxy Manager einrichten: der passende Weg, um Zammad mit TLS und eigenem Hostnamen ins Netz zu stellen.
- PostgreSQL mit pg_dump und pg_restore sichern: vertieft die Dump- und Restore-Befehle aus dem Backup-Abschnitt.
- FreeScout als schlanke Helpdesk-Alternative: sinnvoll, wenn der Zammad-Stack für den Bedarf zu groß ausfällt.
Quellen
- zammad/zammad-docker-compose auf GitHub: offizielle Compose-Dateien, Release v17.0.0 vom 10.09.2026, abgerufen am 13.09.2026.
- zammad/zammad auf GitHub: Quellcode und Lizenz AGPL-3.0, letzter Push 11.09.2026, abgerufen am 13.09.2026.
- Offizielle Zammad-Dokumentation: Angaben zu Update-Kette, Downgrade und Ersteinrichtung.
- Docker-Dokumentation zu Compose-Override-Dateien: Zusammenführung von docker-compose.yml und docker-compose.override.yml.