2FAuth mit Docker Compose: Zwei-Faktor-Konten selbst hosten
2FAuth 9.0.0 mit Docker Compose selbst hosten: APP_KEY sicher erzeugen, Datenbankverschlüsselung aktivieren, Port nur lokal hinter Reverse Proxy, Freigaben für geteilte Dienstkonten sowie Backup und Restore, praktisch getestet.
Geprüft am 28.10.2026 · für 2FAuth 9.0.0
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

2FAuth ist eine selbst gehostete Weboberfläche (AGPL-3.0), die TOTP- und HOTP-Konten speichert und die Einmalcodes im Browser erzeugt. Für kleine Unternehmen löst das ein konkretes Problem: Der zweite Faktor eines geteilten Dienstkontos, etwa beim Hoster, beim Domain-Registrar oder in einem Kundenportal, hängt nicht mehr am Privathandy einer einzelnen Person. Seit Version 7 lassen sich einzelne Konten an andere Benutzer freigeben, ohne das Geheimnis offenzulegen. Diese Anleitung installiert 2FAuth 9.0.0 mit Docker Compose, aktiviert die Datenbankverschlüsselung und prüft Backup und Wiederherstellung.
Voraussetzungen
- Linux-Server oder VPS, 1 bis 2 CPU-Kerne, 4 GB RAM reichen deutlich. 2FAuth belegte im Test im Leerlauf rund 61 MB RAM.
- Architektur amd64, 386, arm64, arm/v6 oder arm/v7 laut Docker-Dokumentation des Projekts. Getestet wurde amd64.
- Etwa 500 MB Speicher: Das Image belegt rund 211 MB, die SQLite-Datei startet bei etwa 292 KB.
- Docker Engine mit Compose-Plugin (Docker-Installation).
- Eine Domain und ein Reverse Proxy mit TLS (Nginx als Reverse Proxy mit TLS), idealerweise zusätzlich VPN oder IP-Beschränkung.
- Ein getrennter Passwortmanager. Passwörter und zweite Faktoren gehören nicht in dieselbe Anwendung.
Eckdaten
| Punkt | Wert |
|---|---|
| Image | 2fauth/2fauth:9.0.0 |
| Version | v9.0.0 vom 27. Oktober 2026, aktuelles Release am 28.10.2026 |
| Port im Container | 8000 (Nginx mit PHP-FPM) |
| Datenverzeichnis | /2fauth (SQLite, Storage, OAuth-Schlüssel, Logs) |
| Benutzer im Container | UID/GID 1000 |
| Pflicht-Variablen | APP_KEY, APP_URL |
| Wichtig hinter Proxy | TRUSTED_PROXIES |
Schritt 1: Verzeichnis und APP_KEY
Legen Sie Projekt- und Datenordner an und übergeben Sie den Datenordner an UID 1000. Alle Prozesse im Container laufen unter dieser Kennung, bei falschem Besitzer scheitert das Anlegen der Datenbank.
mkdir -p /opt/2fauth/data
cd /opt/2fauth
sudo chown -R 1000:1000 data
chmod 700 dataErzeugen Sie dann den Schlüssel mit dem Image selbst:
docker run --rm --entrypoint /usr/bin/php 2fauth/2fauth:9.0.0 artisan key:generate --show2FAuth ist eine Laravel-Anwendung. Laut Dokumentation sichert APP_KEY Sitzungen, Datenbankverschlüsselung, WebAuthn und persönliche Zugriffstoken. Geht er verloren, sind alle verschlüsselten Daten verloren. Legen Sie ihn deshalb zusätzlich im Passwortmanager oder offline ab, nicht nur im selben Backup wie die Datenbank.
Verifizieren: Der Befehl gibt eine Zeile base64:… aus, ls -ln zeigt für data Besitzer 1000 1000.
Schritt 2: settings.env und Compose-Datei
Das offizielle Compose-Beispiel liest die Variablen aus settings.env. Die folgende Fassung bindet den Port an 127.0.0.1 und ergänzt einen Healthcheck mit dem im Image vorhandenen wget:
services:
2fauth:
image: 2fauth/2fauth:9.0.0
container_name: 2fauth
restart: unless-stopped
env_file: settings.env
volumes:
- ./data:/2fauth
ports:
- "127.0.0.1:8000:8000"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8000/"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60sDie settings.env mit Ihrem Schlüssel aus Schritt 1:
APP_NAME=2FAuth
APP_ENV=production
APP_DEBUG=false
APP_TIMEZONE=Europe/Berlin
SITE_OWNER=admin@example.de
APP_URL=https://2fa.example.de
APP_KEY=base64:HIER_IHR_SCHLUESSEL
DB_CONNECTION=sqlite
DB_DATABASE=/2fauth/database.sqlite
CACHE_DRIVER=file
SESSION_DRIVER=file
LOG_CHANNEL=daily
LOG_LEVEL=notice
MAIL_MAILER=log
LOGIN_THROTTLE=5
TRUSTED_PROXIES=172.16.0.0/12
CONTENT_SECURITY_POLICY=true
BLOCK_OPTAUTH_IMAGELINK_FETCHING=trueAPP_URL muss exakt der aufgerufenen Adresse samt Schema entsprechen, sonst funktionieren laut Dokumentation WebAuthn, SSO-Weiterleitungen und Links nicht. TRUSTED_PROXIES enthält die Adresse Ihres Proxys, sonst erzeugt 2FAuth Links mit http. BLOCK_OPTAUTH_IMAGELINK_FETCHING verhindert das Nachladen von Bildern aus QR-Codes und schützt vor Blind-SSRF. Mit MAIL_MAILER=log landen Mails nur im Protokoll. Für Passwort-Zurücksetzen tragen Sie einen echten SMTP-Server ein.
Verifizieren: docker compose config läuft ohne Fehler und zeigt als Port 127.0.0.1:8000.
Schritt 3: Starten und erstes Konto
docker compose up -d
docker compose logs --no-log-prefix | grep "Running version"Beim ersten Start legt das Einstiegsskript die SQLite-Datei an und führt die Migrationen aus. Im Test antwortete die Oberfläche in den ersten Sekunden mit HTTP 502, weil PHP-FPM noch nicht bereit war, nach rund zehn Sekunden mit 200. Deshalb die großzügige start_period.
Das erste registrierte Konto wird laut Dokumentation Administrator. Öffnen Sie die Oberfläche per SSH-Tunnel (ssh -L 8000:127.0.0.1:8000 benutzer@server) und registrieren Sie sich sofort, bevor der Proxy die Instanz erreichbar macht. Hinterlegen Sie danach unter den Kontoeinstellungen einen Passkey (WebAuthn).
Verifizieren: Das Log zeigt Running version 9.0.0, docker compose ps meldet healthy, und curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/ liefert 200.
Schritt 4: Verschlüsselung und Freigaben
Aktivieren Sie im Administrationsbereich unter „App Setup“ die Option „Sensible Daten schützen“. Im Test stand ein angelegtes Geheimnis vorher im Klartext in der Datenbank, danach nur noch als verschlüsselter Wert:
vorher: 1|S-EDV Testdienst|JBSWY3DPEHPK3PXP
nachher: 1|eyJpdi...Q0E9|eyJpdi...MTRzIm selben Bereich steuern Sie die Freigabe. „2FA-Freigabe“ erlaubt Benutzern, Konten zu teilen. Der Bereich „ALL_USERS“ gibt an sämtliche, auch künftige Benutzer frei und wird von der Dokumentation selbst als potenziell gefährlich eingestuft. Für kleine Teams ist „SPECIFIC_USERS“ die passende Wahl. Schließen Sie außerdem die Registrierung, wenn alle Konten angelegt sind.
Verifizieren: Legen Sie ein Testkonto mit dem Geheimnis JBSWY3DPEHPK3PXP an und vergleichen Sie den Code mit einer zweiten Authenticator-App. Beide Codes müssen übereinstimmen.
Schritt 5: Reverse Proxy
Eine passende Nginx-Konfiguration:
server {
listen 443 ssl;
http2 on;
server_name 2fa.example.de;
ssl_certificate /etc/letsencrypt/live/2fa.example.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/2fa.example.de/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Tragen Sie in TRUSTED_PROXIES die Adresse ein, von der der Proxy den Container erreicht. Läuft Nginx direkt auf dem Host, ist das die Gateway-Adresse des Docker-Netzes. Beschränken Sie den Zugriff zusätzlich per VPN oder IP-Liste. Eine aus dem Internet offene Instanz bündelt die zweiten Faktoren vieler Konten und ist nur mit Passkey-Pflicht vertretbar. Die Option AUTHENTICATION_GUARD=reverse-proxy-guard überlässt die Anmeldung vollständig dem Proxy. 2FAuth prüft dann nichts mehr selbst, ab Version 8 muss der Proxy zwingend in TRUSTED_PROXIES stehen.
Verifizieren: curl -sI https://2fa.example.de liefert 200 mit einem Header Content-Security-Policy, und der Browser zeigt keine Warnung zu unsicheren Inhalten.
Schritt 6: Backup und Wiederherstellung
Ein vollständiges Backup besteht aus dem Datenverzeichnis, settings.env und der Compose-Datei. Das Verzeichnis enthält neben der SQLite-Datei auch die OAuth-Schlüssel unter storage/. Stoppen Sie den Container, damit die SQLite-Datei konsistent ist:
cd /opt/2fauth
mkdir -p backup
docker compose stop 2fauth
sudo tar czf backup/2fauth-$(date +%F).tar.gz data settings.env compose.yaml
docker compose start 2fauthDie Wiederherstellung im Test: Container entfernen, Datenverzeichnis löschen, Archiv entpacken, starten.
docker compose down
sudo rm -rf data
sudo tar xzf backup/2fauth-2026-09-30.tar.gz
docker compose up -dDanach funktionierte die Anmeldung, und der Code des verschlüsselten Testkontos stimmte wieder mit der Referenz überein. Das Archiv enthält den APP_KEY in settings.env. Verschlüsseln Sie es deshalb, bevor es den Server verlässt, zum Beispiel mit restic.
Verifizieren: tar tzf listet data/database.sqlite, data/storage/oauth-private.key und settings.env. Nach einem Probe-Restore ist docker compose ps wieder healthy und die Codes stimmen.
Grundlagen zum Betrieb finden Sie in Docker-Container automatisch aktualisieren: Diun, WUD und Renovate im Vergleich.
Typische Fehler
The secret cannot be decipheredmit HTTP 400: DerAPP_KEYwurde nach Aktivieren der Verschlüsselung geändert. Im Test trat genau das nach einem Schlüsseltausch auf. Den alten Schlüssel inAPP_PREVIOUS_KEYSeintragen und neu starten, danach lieferte derselbe Abruf wieder 200. Ohne alten Schlüssel sind die Geheimnisse verloren.!! Environment variable APP_KEY is empty !!: Kein Schlüssel gesetzt. Schritt 1 ausführen.- HTTP 502, im Log
connect() failed (111: Connection refused) while connecting to upstream: PHP-FPM startet noch. Etwa zehn Sekunden warten. - Datenbank wird nicht angelegt: Datenordner gehört nicht UID 1000.
chown -R 1000:1000 data. chmod(): Operation not permittednach Update auf Version 8: Laut Release Notes falsche Besitzrechte an den Passport-Schlüsseln.docker compose exec 2fauth /usr/bin/php /srv/artisan 2fauth:fix-passport-key-permissionsausführen.- Browser warnt hinter dem Proxy vor unsicherer Verbindung:
TRUSTED_PROXIESfehlt oder enthält die falsche Adresse. Bind for 127.0.0.1:8000 failed: port is already allocated: Port belegt. Linke Seite der Portzuordnung ändern.
Häufige Fragen
Ersetzt 2FAuth die Authenticator-App?
Für persönliche Konten nein. Die App auf dem eigenen Gerät bleibt dafür die bessere Lösung. 2FAuth ist für geteilte Dienstkonten gedacht, bei denen mehrere Personen den Code brauchen.
Was passiert beim Update von Version 7?
Laut Release Notes werden persönliche Zugriffstoken aus Version 7 ungültig und müssen neu erstellt werden. Ein Auth-Proxy muss ab Version 8 in TRUSTED_PROXIES stehen. Sichern Sie vorher nach Schritt 6, ein Rollback gelingt nur mit dem Backup von vor dem Update.
Update von 8.0 auf 9.0: Trotz der neuen Hauptversion nennt das Changelog keine Breaking Changes. 9.0.0 bringt eine Tabellenansicht für große Bildschirme, Favoriten, Schnellauswahl-Schaltflächen für Sammelaktionen und den Import aus Ente Auth. Außerdem behebt die Version abgeschnittene große API-Antworten im Docker-Image, wenn der Container wie hier nicht als root läuft. Sichern Sie vorher nach Schritt 6, setzen Sie das Tag auf 9.0.0 und führen Sie docker compose pull und docker compose up -d aus. Im Test von 8.0.2 auf 9.0.0 mit Compose-Datei und settings.env aus Schritt 2 meldete das Log Installed commit ... is different from program commit ..., we are migrating und lief die Migrationen automatisch durch. Danach war der Container healthy, die Anmeldung lieferte 200, ein falsches Passwort 401, die API ohne Anmeldung 401, und das vorher angelegte Konto erzeugte weiter gültige Codes. Im selben Test nahm 2FAuth nach dem ersten Konto auch eine zweite Registrierung an. Schließen Sie die Registrierung deshalb wie in Schritt 4 beschrieben.
Kann ich den APP_KEY als Docker-Secret übergeben?
Ja. Das Image unterstützt laut Dokumentation APP_KEY_FILE und weitere Variablen mit Suffix _FILE. Setzen Sie nicht APP_KEY und APP_KEY_FILE gleichzeitig, das führt zu einem Startfehler.
Brauche ich MySQL oder PostgreSQL?
Für kleine Teams nicht. SQLite reicht. 2FAuth unterstützt zusätzlich mysql, pgsql und sqlsrv, dann sichern Sie statt der SQLite-Datei einen Datenbank-Dump und weiterhin das Verzeichnis storage.
Fazit
2FAuth ist in wenigen Minuten installiert. Der Aufwand liegt in der Absicherung: Schlüssel getrennt aufbewahren, Verschlüsselung aktivieren, Port nur lokal, Zugang per VPN oder Passkey, Registrierung schließen und die Wiederherstellung einmal real durchspielen. So umgesetzt, macht 2FAuth geteilte Dienstkonten unabhängig von einzelnen Telefonen.
Weiterführende Anleitungen und Quellen
- Zwei-Faktor-Authentifizierung richtig einführen
- Vaultwarden produktiv betreiben
- Nginx als Reverse Proxy mit TLS einrichten
- Docker Compose absichern: Secrets, Healthchecks und Non-Root
- Linux-Server absichern mit UFW und Fail2ban
- 2FAuth-Dokumentation: Docker Compose
- 2FAuth-Dokumentation: Umgebungsvariablen
- 2FAuth-Dokumentation: Datenschutz und APP_KEY
- 2FAuth-Dokumentation: Freigaben
- 2FAuth Release v9.0.0


