Firefly III mit Docker installieren: Self-Hosted Finanzverwaltung mit doppelter Buchführung
Firefly III 6.7 per Docker Compose installieren: doppelte Buchführung, Budgets und Kategorien selbst hosten. Die Anleitung führt von der .env-Datei über den MariaDB-Healthcheck und den Cron-Container bis zu Update und Backup.
Geprüft am 30.09.2026 · für firefly-iii 6.7.6
WerbelinksMit * 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

Firefly III (AGPL-3.0) ist eine selbst gehostete Finanzverwaltung mit doppelter Buchführung, Budgets, Kategorien, Tags, Berichten und REST-API. Die Daten bleiben auf Ihrem eigenen Server. Die Anwendung läuft als PHP/Laravel-Stack hinter integriertem Nginx im Container und benötigt drei Dienste: die Kern-App, eine MariaDB-Datenbank und einen schlanken Alpine-Cron-Container für automatische Aufgaben. Diese Anleitung richtet sich an Privatpersonen, Freelancer und KMU-Admins, die ihre Finanzdaten nicht in einen Cloud-Dienst geben wollen.
Voraussetzungen
- Docker Engine >= 24.x und das Docker Compose Plugin >= 2.x (Befehl:
docker compose) sind installiert – wie das geht, erklärt die Grundanleitung Docker und Docker Compose auf Linux installieren. - Linux-Host, VM oder NAS mit Docker-Unterstützung (Ubuntu/Debian, Proxmox-LXC, Synology DSM 7.x). Unterstützte Architekturen: linux/amd64 und linux/arm64. Auf älteren Raspberry-Pi-Modellen mit arm/v7 funktioniert das aktuelle Image nicht mehr.
- 1 CPU-Kern, mindestens 1 GB RAM (im Test belegten die drei Container zusammen rund 350 MB), empfohlen 2 GB; mindestens 2 GB freier Speicherplatz für Images und Daten.
- Internetzugang für den Image-Pull beim ersten Start.
- Optional, aber empfohlen: ein vorgelagerter Reverse Proxy (Traefik, Caddy, Nginx Proxy Manager) für HTTPS. Wie Sie Traefik einrichten, beschreibt Traefik als Docker-Reverse-Proxy mit automatischem HTTPS.
Schritt 1: Projektordner anlegen
Legen Sie einen eigenen Ordner für den Stack an. Alle Konfigurationsdateien landen hier; Docker-Volumes werden separat von Docker verwaltet.
mkdir -p /opt/firefly-iii
cd /opt/firefly-iiiAlle folgenden Befehle setzen voraus, dass Sie sich in diesem Verzeichnis befinden.
Verifizieren: pwd zeigt /opt/firefly-iii, ls gibt ein leeres Verzeichnis ohne Fehler zurück.
Schritt 2: APP_KEY generieren
Der APP_KEY ist der Kern der Verschlüsselung: Er schützt Sessions und sensible Daten in der Datenbank. Erzeugen Sie ihn einmalig vor dem ersten Start und bewahren Sie ihn sicher auf. Wer ihn nachträglich ändert, verliert den Zugang zu allen verschlüsselten Einträgen.
# 32 zufällige Zeichen ohne Sonderzeichen generieren (Linux/macOS):
head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32 && echoDie Ausgabe sieht beispielsweise so aus:
xK9mQpLrTvZwAjNbCfHdEuYsOiGe7X4nFühren Sie den Befehl ein zweites Mal aus: Den zweiten Wert brauchen Sie als STATIC_CRON_TOKEN, der ebenfalls exakt 32 Zeichen lang sein muss. Beide Werte tragen Sie im nächsten Schritt in die .env ein. Sichern Sie den APP_KEY in einem Passwortmanager, etwa in Vaultwarden: eigener Passwortmanager mit Docker.
Verifizieren: Der Befehl liefert exakt 32 Zeichen ohne Leerzeichen oder Zeilenumbruch. Prüfen Sie das mit echo -n 'WERT' | wc -c, die Ausgabe muss 32 lauten.
Schritt 3: Umgebungsdateien anlegen
Firefly III trennt App-Konfiguration (.env) und Datenbankzugangsdaten (.db.env) sauber in zwei Dateien. Die Root-Zugangsdaten der Datenbank landen so nicht in der App-Umgebung.
.env – App-Konfiguration
# -------------------------------------------------------
# Firefly III – App-Konfiguration
# -------------------------------------------------------
# Pflicht: 32-Zeichen-Zufallsstring, NIEMALS nachträglich ändern!
APP_KEY=xK9mQpLrTvZwAjNbCfHdEuYsOiGe7X4n
APP_ENV=production
# Muss der tatsächlichen Aufruf-URL entsprechen (inkl. Port, falls nicht 80/443)
APP_URL=http://localhost
# Datenbank
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=firefly
DB_USERNAME=firefly
# Identisch mit MYSQL_PASSWORD in .db.env!
DB_PASSWORD=SICHERES_PASSWORT_AENDERN
# Cron-Token: exakt 32 Zeichen (zweiter Wert aus Schritt 2)
STATIC_CRON_TOKEN=Rw7TzQ2mXbN4kLpV9sHdC3fJ8gYtA6uE
# Zeitzone
TZ=Europe/Berlin
# Deutsch als Standard-UI
DEFAULT_LANGUAGE=de_DE
DEFAULT_LOCALE=de_DE
# Admin-E-Mail für Fehlermeldungen
SITE_OWNER=admin@example.com
# Hinter Reverse Proxy: CSRF-Fehler vermeiden
# TRUSTED_PROXIES=**
# Log-Einstellungen (optional)
LOG_CHANNEL=stack
APP_LOG_LEVEL=notice.db.env – Datenbankzugangsdaten
# -------------------------------------------------------
# MariaDB – Datenbankzugangsdaten
# -------------------------------------------------------
MYSQL_ROOT_PASSWORD=SICHERES_ROOT_PASSWORT_AENDERN
MYSQL_DATABASE=firefly
MYSQL_USER=firefly
# Identisch mit DB_PASSWORD in .env!
MYSQL_PASSWORD=SICHERES_PASSWORT_AENDERNErsetzen Sie beide SICHERES_PASSWORT_AENDERN-Platzhalter durch dasselbe sichere Passwort. Ein Mismatch zwischen DB_PASSWORD und MYSQL_PASSWORD ist der häufigste Fehler und führt zu einem sofortigen Verbindungsfehler der App.
Verifizieren:
ls -la /opt/firefly-iii/
# Erwartet: .env und .db.env vorhanden
grep DB_PASSWORD .env
grep MYSQL_PASSWORD .db.env
# Beide Zeilen müssen das identische Passwort zeigenSchritt 4: compose.yaml anlegen
Der Stack besteht aus drei Diensten: app (Firefly III Core), db (MariaDB) und cron (Alpine-Cron für automatische Tasks). Anders als die offizielle Beispieldatei enthält diese Fassung einen Healthcheck auf MariaDB: Der App-Container startet erst, wenn die Datenbank bereit ist.
| Eigenschaft | Wert |
|---|---|
| Image (stabil) | fireflyiii/core:latest (Stand September 2026: v6.7.6) |
| Stabiler Pin | fireflyiii/core:version-6.7.6 |
| Architekturen | linux/amd64, linux/arm64 (kein arm/v7) |
| Interner Port | 8080 (HTTP) |
| Host-Port (Standard) | 80 → 8080 |
| Image-Größe | ca. 335 MB (komprimiert) |
| Datenbank | MariaDB LTS (Standard), PostgreSQL 16 (Alternative) |
| Lizenz | GNU AGPL-3.0 |
| Volume | Container-Pfad | Inhalt |
|---|---|---|
firefly_iii_upload | /var/www/html/storage/upload | Hochgeladene Belege und Anhänge |
firefly_iii_db | /var/lib/mysql | MariaDB-Datenbankdaten |
services:
app:
image: fireflyiii/core:latest
container_name: firefly_iii_core
hostname: app
restart: unless-stopped
volumes:
- firefly_iii_upload:/var/www/html/storage/upload
env_file:
- .env
ports:
- "80:8080"
networks:
- firefly_iii
depends_on:
db:
condition: service_healthy
db:
image: mariadb:lts
container_name: firefly_iii_db
hostname: db
restart: unless-stopped
env_file:
- .db.env
volumes:
- firefly_iii_db:/var/lib/mysql
networks:
- firefly_iii
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 20s
timeout: 5s
retries: 10
start_period: 30s
cron:
image: alpine
container_name: firefly_iii_cron
restart: unless-stopped
env_file:
- .env
command: >
sh -c "apk add --no-cache tzdata &&
(ln -sf /usr/share/zoneinfo/$$TZ /etc/localtime || true) &&
echo '0 3 * * * wget -qO- http://app:8080/api/v1/cron/$$STATIC_CRON_TOKEN; echo' | crontab - &&
crond -f -L /dev/stdout"
networks:
- firefly_iii
depends_on:
- app
volumes:
firefly_iii_upload:
firefly_iii_db:
networks:
firefly_iii:
driver: bridgeWer den Image-Tag pinnen möchte, ersetzt fireflyiii/core:latest durch fireflyiii/core:version-6.7.6 und spielt Updates dann manuell via docker compose pull ein. Mehr zu Docker-Netzwerken und Volumes erklärt Docker-Netzwerke und Volumes richtig nutzen.
Verifizieren:
docker compose config
# Erwartet: Validierte Compose-Konfiguration ohne Fehler
# Keine "invalid" oder "unknown" Warnungen in der AusgabeSchritt 5: Stack starten
Beim ersten Start lädt Docker die drei Images herunter (zusammen ca. 440 MB komprimiert), startet MariaDB, wartet auf dessen Healthcheck und führt dann automatisch alle Datenbankmigrationen durch.
docker compose up -dNach dem Pull vergehen 30 bis 60 Sekunden, bis MariaDB als „healthy“ gilt. Danach führt der App-Container Migrationen und Integritätsprüfungen aus, auf schwacher Hardware (1 CPU-Kern) dauert das zwei bis drei Minuten.
Verifizieren:
docker compose ps
# Erwartete Ausgabe (alle drei Container):
# NAME IMAGE STATUS
# firefly_iii_core fireflyiii/core:latest Up X seconds (healthy)
# firefly_iii_db mariadb:lts Up X seconds (healthy)
# firefly_iii_cron alpine Up X seconds
# App-Logs auf Migrationsfehler prüfen:
docker compose logs app --tail=50
# Erwartet gegen Ende: "NOTICE: ready to handle connections"
# HTTP-Check:
curl -I http://localhost
# Erwartet: HTTP/1.1 302 Found (Redirect zur Login-/Registrierungsseite)Schritt 6: Ersteinrichtung im Browser
Rufen Sie http://localhost (oder den konfigurierten Host und Port) im Browser auf. Über „Registrieren“ legen Sie das erste Konto an. Das erste registrierte Konto erhält die Rolle „owner“ (Administrator), registrieren Sie sich deshalb sofort selbst.
Nach der Registrierung führt ein kurzer Assistent durch das erste Konto. Empfohlene erste Schritte:
- Unter Konten → Vermögenskonten Ihre Bankkonten, Kreditkarten und Bargeld anlegen.
- Unter Budgets monatliche Ausgabegrenzen definieren (z. B. Lebensmittel, Mobilität, Freizeit).
- Unter Kategorien thematische Felder für Transaktionen erstellen.
- Einstellungen → Profil: Sprache auf „Deutsch“ prüfen, sie sollte bereits per
DEFAULT_LANGUAGE=de_DEgesetzt sein.
Verifizieren: Nach der Registrierung erscheint der Einrichtungsassistent ohne Fehlerseite, die Oberfläche ist deutsch. In den Logs taucht kein 500 Internal Server Error auf:
docker compose logs app --tail=20
# Keine Zeile mit "ERROR" oder "500"Schritt 7: HTTPS mit Reverse Proxy einrichten (empfohlen)
Firefly III selbst terminiert kein TLS, diese Aufgabe übernimmt ein vorgelagerter Reverse Proxy. Traefik, Caddy oder Nginx Proxy Manager eignen sich alle gleichermaßen.
Sobald ein Reverse Proxy davor sitzt, müssen zwei Variablen in der .env angepasst werden:
APP_URL=https://firefly.ihre-domain.de
TRUSTED_PROXIES=**Danach den Stack neu starten:
docker compose up -dWie Sie Caddy mit automatischem HTTPS-Zertifikat einrichten, erklärt Caddy als Reverse Proxy einrichten ausführlich.
Verifizieren:
curl -I https://firefly.ihre-domain.de
# Erwartet: HTTP/2 302 oder HTTP/2 200
# Kein "SSL_ERROR_RX_RECORD_TOO_LONG"
docker compose logs app --tail=20
# Keine "419 Page Expired" oder CSRF-Fehler in den LogsSchritt 8: Updates und Backup
Update durchführen
Datenbankmigrationen laufen beim Container-Start automatisch. Legen Sie vor jedem Update trotzdem ein Datenbank-Backup an. Aktuelle MariaDB-Images enthalten nur noch mariadb-dump, der alte Befehl mysqldump fehlt. Das Passwort liest der Befehl aus der Container-Umgebung, es landet so nicht in der Shell-History:
# Backup vor dem Update
docker exec firefly_iii_db sh -c 'mariadb-dump -u firefly -p"$MYSQL_PASSWORD" --single-transaction firefly' > backup_$(date +%Y%m%d).sql
# Update durchführen
docker compose pull
docker compose up -d --force-recreateVolumes sichern
Named Volumes gehen bei docker compose down -v unwiderruflich verloren, führen Sie den Befehl nie ohne Backup aus. Eine robuste Strategie für Offsite-Backups beschreibt 3-2-1-Backup-Strategie umsetzen. Für automatisierte Datenbank-Dumps hilft MySQL & PostgreSQL Backup automatisieren mit cron.
Verifizieren:
docker compose ps
# Alle drei Container zeigen "Up" mit aktuellem Timestamp
docker compose logs app --tail=20
# Keine Migrationsfehler, Eintrag "ready to handle connections" vorhanden
grep -c 'CREATE TABLE' backup_*.sql
# Erwartet: eine Zahl deutlich über 0 (im Test 81)Troubleshooting / Typische Fehler
SQLSTATE[HY000] [1045] Access denied for user 'firefly':DB_PASSWORDin.envundMYSQL_PASSWORDin.db.envstimmen nicht überein. Beide auf denselben Wert setzen. Wurde die Datenbank bereits initialisiert, muss das Passwort auch in MariaDB selbst geändert werden – oder die Volumes werden gelöscht und neu initialisiert.419 Page Expiredbeim Login: CSRF-Fehler hinter einem Reverse Proxy. Lösung:TRUSTED_PROXIES=**in.envsetzen, danachdocker compose up -d.- Redirect-Schleife oder falsche Links in E-Mails:
APP_URLstimmt nicht mit der tatsächlichen Aufruf-URL überein. Vollständige URL inkl. Schema und Port angeben (z. B.https://firefly.example.com), danachdocker compose up -d. - Cron-Container läuft, aber Wiederkehr-Buchungen erscheinen nicht:
STATIC_CRON_TOKENprüfen – er muss exakt 32 Zeichen haben und in.envgesetzt sein. Cron läuft täglich um 03:00 Uhr; für einen sofortigen Test:docker exec firefly_iii_cron wget -qO- http://app:8080/api/v1/cron/TOKEN. - App-Container startet und hält sofort wieder an, Migrations-Fehler in den Logs: MariaDB war noch nicht bereit. Mit
condition: service_healthytritt das nicht auf. Andernfalls indocker compose logs dbauf „ready for connections“ warten, danndocker compose restart app. - Fehler auf arm/v7 (ältere Raspberry Pi): Das aktuelle Image unterstützt kein linux/arm/v7 mehr. Wechseln Sie auf arm64-Hardware oder ein 64-Bit-Betriebssystem.
- APP_KEY nachträglich geändert: Alle Sessions werden ungültig, verschlüsselte Daten sind nicht mehr lesbar. Den ursprünglichen Key aus dem Backup wiederherstellen – es gibt keinen anderen Weg.
Häufige Fragen
Kann ich PostgreSQL statt MariaDB verwenden?
Ja, PostgreSQL ist offiziell unterstützt. In .env DB_CONNECTION=pgsql und DB_PORT=5432 setzen. In .db.env die MYSQL_*-Variablen durch POSTGRES_PASSWORD, POSTGRES_DB und POSTGRES_USER ersetzen. In compose.yaml das Image auf postgres:16 und den Volume-Mount auf /var/lib/postgresql/data ändern (ab postgres:18 lautet der Mount /var/lib/postgresql).
Wie richte ich den Datenimport ein (CSV, Banking)?
Firefly III selbst importiert keine Daten direkt – dafür gibt es den separaten Container fireflyiii/data-importer. Dieser wird als eigener Dienst im Stack ergänzt und kommuniziert per API (Token aus den Firefly-III-Einstellungen) mit der Kern-App. Unterstützte Dateiformate: CSV, CAMT.052 und CAMT.053. Kontoabrufe laufen über Drittanbieter wie GoCardless (ehemals Nordigen). Die Sprache des Data Importers steuert dessen eigene Variable FALLBACK_LOCALE, Firefly III selbst nutzt DEFAULT_LOCALE.
Wie aktiviere ich die deutsche Benutzeroberfläche?
In .env die Zeilen DEFAULT_LANGUAGE=de_DE und DEFAULT_LOCALE=de_DE setzen (in der Beispiel-Konfiguration oben bereits enthalten). Nach docker compose up -d ist die Oberfläche deutsch. Jeder Benutzer kann die Sprache in seinen Einstellungen ändern.
Was tun, wenn ich den APP_KEY verloren habe?
Ohne den originalen APP_KEY sind verschlüsselte Daten verloren. Läuft die Instanz noch, zeigt docker exec firefly_iii_core env | grep APP_KEY den aktiven Key. Sonst bleibt nur ein Neuanfang mit neuen Volumes.
Was kostet Firefly III im Betrieb?
Die Software ist kostenlos (GNU AGPL-3.0), Kosten entstehen nur für Strom und Hardware. Wer eine veränderte Fassung als Dienst für andere anbietet, muss deren Quellcode offenlegen (AGPL).
Fazit
Firefly III ist aktiv gepflegt und eignet sich für alle, die ihre Finanzen lokal und ohne Abo verwalten möchten. Der Stack mit drei Containern ist in etwa 30 Minuten aufgesetzt. Die doppelte Buchführung erfordert anfangs mehr Einarbeitung als ein einfaches Haushaltsbuch, liefert dafür nachvollziehbare Berichte und eine REST-API für eigene Automatisierungen. Freelancer profitieren von Budgets, Kategorien und dem optionalen Data Importer mit CAMT-Unterstützung. Entscheidend für den Dauerbetrieb sind regelmäßige Backups und ein sicher aufbewahrter APP_KEY.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
- Traefik als Docker-Reverse-Proxy mit automatischem HTTPS einrichten
- Caddy als Reverse Proxy mit automatischem HTTPS
- Vaultwarden: eigener Passwortmanager mit Docker und SQLite-Backup
- 3-2-1-Backup-Strategie umsetzen: Anleitung mit Restic, USB-Disk und S3-Cloud
- MySQL & PostgreSQL Backup automatisieren mit cron: mysqldump, pg_dump und rclone
Offizielle Quellen: Firefly III Docker-Installationsdokumentation, Firefly III Docker-Repository auf GitHub, fireflyiii/core auf Docker Hub.


