Firefly III mit Docker installieren: Self-Hosted Finanzverwaltung mit doppelter Buchführung
Firefly III ist mit über 23.000 GitHub-Stars die meistgenutzte selbst gehostete Finanzverwaltung und läuft sauber per Docker Compose. Diese Anleitung zeigt dir den vollständigen Weg: von der .env-Datei über den MariaDB-Healthcheck bis zum Cron-Container für automatische Wiederkehr-Buchungen.

Wer seine Finanzen ernsthaft im Griff behalten möchte, braucht kein teures SaaS-Abo: Firefly III (AGPL-3.0) bietet doppelte Buchführung, Budgets, Kategorien, Tags, Berichte und eine vollständige REST-API – vollständig lokal, ohne dass auch nur ein Cent an Dritte fließt. Mit über 23.700 GitHub-Stars und mehr als 10 Millionen Docker-Pulls ist es die etablierteste selbst gehostete Finanz-App überhaupt. 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 eine datenschutzkonforme Buchhaltung ohne Cloud-Abhängigkeit betreiben 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.
- Mindestens 1 GB RAM, 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 du Traefik einrichtest, beschreibt Traefik als Docker-Reverse-Proxy mit automatischem HTTPS.
Schritt 1: Projektordner anlegen
Lege einen dedizierten 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 gehen davon aus, dass du dich in diesem Verzeichnis befindest.
Verifizieren: ls /opt/firefly-iii gibt das leere Verzeichnis zurück (kein Fehler). Das Verzeichnis existiert und ist bereit für die Konfigurationsdateien.
Schritt 2: APP_KEY generieren
Der APP_KEY ist der Kern der Verschlüsselung: Er schützt Sessions und sensible Daten in der Datenbank. Generiere ihn einmalig vor dem allerersten Start und bewahre 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:
xK9mQpLrTvZwAjNbCfHdEuYsOiGe7X4nMerke dir diesen Wert – er wird in der nächsten .env-Datei eingetragen. Den Key unbedingt in einem Passwortmanager sichern, etwa in Vaultwarden: eigener Passwortmanager mit Docker.
Verifizieren: Der Befehl liefert exakt 32 Zeichen ohne Leerzeichen oder Zeilenumbruch. Zähle nach – alles andere führt später zu Fehlern beim Start.
Schritt 3: Umgebungsdateien anlegen
Firefly III trennt App-Konfiguration (.env) und Datenbankzugangsdaten (.db.env) sauber in zwei Dateien. Das hat den Vorteil, dass du Datenbankgeheimnisse nicht unnötig in der App-Umgebung exponierst.
.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, frei wählbar
STATIC_CRON_TOKEN=CronToken32ZeichenHierEintragen
# 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_AENDERNErsetze 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). Der Healthcheck auf MariaDB stellt sicher, dass der App-Container erst startet, wenn die Datenbank wirklich bereit ist – ohne diesen Mechanismus schlägt die Migration beim ersten Start häufig fehl.
| Eigenschaft | Wert |
|---|---|
| Image (stabil) | fireflyiii/core:latest (aktuell v6.6.3) |
| Stabiler Pin | fireflyiii/core:version-6.6.3 |
| Architekturen | linux/amd64, linux/arm64 (kein arm/v7) |
| Interner Port | 8080 (HTTP) |
| Host-Port (Standard) | 80 → 8080 |
| Image-Größe | ca. 310 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, tauscht fireflyiii/core:latest durch fireflyiii/core:version-6.6.3 aus 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 alle drei Images herunter (zusammen ca. 350 MB), startet MariaDB, wartet auf dessen Healthcheck und führt dann automatisch alle Datenbankmigrationen durch.
docker compose up -dNach dem Pull vergehen erfahrungsgemäß 30–60 Sekunden, bis MariaDB als „healthy" gilt und der App-Container hochläuft.
Verifizieren:
docker compose ps
# Erwartete Ausgabe (alle drei Container):
# NAME IMAGE STATUS
# firefly_iii_core fireflyiii/core:latest Up X seconds
# 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
# Erwartetes 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
Rufe http://localhost (oder den konfigurierten Host und Port) im Browser auf. Da noch kein Konto existiert, leitet Firefly III automatisch zur Registrierungsseite weiter. Der erste registrierte Account wird Administrator – trage daher sofort deine eigene E-Mail-Adresse ein.
Nach der Registrierung landest du im Dashboard. Empfohlene erste Schritte:
- Unter Konten → Vermögenskonten deine 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: Das Dashboard ist erreichbar und zeigt das leere Finanz-Dashboard ohne Fehlerseite. 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 – das ist bewusst so gestaltet, damit ein vorgelagerter Reverse Proxy diese Aufgabe übernimmt. 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.deine-domain.de
TRUSTED_PROXIES=**Danach den Stack neu starten:
docker compose up -dWie du Caddy mit automatischem HTTPS-Zertifikat einrichtest, erklärt Caddy als Reverse Proxy einrichten ausführlich.
Verifizieren:
curl -I https://firefly.deine-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
Firefly-III-Updates sind unkompliziert – Datenbankmigrationen laufen beim Container-Start automatisch. Vor jedem Update dennoch ein Datenbank-Backup anlegen:
# Backup vor dem Update
docker exec firefly_iii_db mysqldump -u firefly -p'SICHERES_PASSWORT_AENDERN' 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 – niemals ohne vorheriges Backup ausführen. 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; letzter Eintrag: "ready to handle connections"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: Klassischer 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 beim ersten Start noch nicht bereit. Mit der gezeigten
compose.yamlundcondition: service_healthysollte das nicht auftreten. Zur Sicherheit:docker 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. Entweder auf arm64-Hardware wechseln oder PostgreSQL als Datenbank einsetzen und auf eine ältere Image-Version ausweichen.
- 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. Für arm/v7-Hardware ist PostgreSQL die einzige offizielle Option.
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 Formate: CSV, CAMT.053, OFX/QFX und Nordigen/Spectre (Open Banking für Europa).
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 einem docker compose up -d ist die UI auf Deutsch. Einzelne Benutzer können die Sprache außerdem unter Einstellungen → Profil → Preferences → Language individuell überschreiben.
Was tun, wenn ich den APP_KEY verloren habe?
Ohne den originalen APP_KEY ist kein Zugang zu verschlüsselten Daten mehr möglich. Falls noch eine funktionierende Instanz läuft: docker exec firefly_iii_core env | grep APP_KEY zeigt den aktiven Key. Ansonsten bleibt nur ein Neustart mit neuen Volumes. Der Key gehört deshalb unbedingt in einen Passwortmanager.
Was kostet Firefly III im Betrieb?
Die Software selbst ist kostenlos (GNU AGPL-3.0). Kosten entstehen nur durch den Betrieb: Strom und Hardware für den Host-Server. Bei einem bestehenden Heimserver oder NAS sind die Zusatzkosten nahezu null. Wer Firefly III als Dienst öffentlich anbieten möchte, muss den Quellcode offenlegen (AGPL-Pflicht).
Fazit
Firefly III ist eine ausgereifte, aktiv gepflegte Lösung für alle, die ihre Finanzen vollständig lokal und ohne Abo-Modell verwalten möchten. Der Docker-Compose-Stack mit drei Containern ist in unter 30 Minuten aufgesetzt und läuft stabil auf nahezu jeder Linux-Plattform. Die Lernkurve für das Konzept der doppelten Buchführung ist anfangs etwas steiler als bei einfachen Haushaltsbuch-Apps – wer das System aber einmal verstanden hat, bekommt präzise Berichte, vollständige Nachvollziehbarkeit jeder Transaktion und eine REST-API für eigene Automatisierungen. Für Freelancer ist die Kombination aus Budgets, Kategorien und dem optionalen Data-Importer mit CAMT.053-Unterstützung besonders praktisch. Wer regelmäßige Backups einrichtet und den APP_KEY sicher aufbewahrt, hat eine Finanzverwaltung, die ohne externe Abhängigkeit jahrelang zuverlässig läuft.
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.