Zum Inhalt springen

Konfiguration

Konfiguriert wird an drei Stellen, in dieser Rangfolge: CLI-Flags schlagen Umgebungsvariablen, und die schlagen die config.json.

Alles, was den Betrieb einer Kundenseite betrifft — Empfänger, Origins, PoW-Bits, Kontingente — steht dagegen nicht hier, sondern pro Mandant in der Datenbank (Bedienung).

FlagBedeutung
-data <dir>Datenverzeichnis für config.json, Datenbank und Logs. Default: Verzeichnis des Binaries; im Container typischerweise /data.
-config <datei>Pfad zu einer config.json außerhalb des Datenverzeichnisses.
-debugHebt das Log-Level zur Laufzeit auf debug an, unabhängig von log_level.
-demoDemo-Modus: lokaler SMTP-Sink plus Demo-Mandanten. Nichts für den Produktivbetrieb.
-versionVersion, Build-Nummer und Build-Zeitpunkt ausgeben und beenden.

Gedacht für Container, wo eine gemountete config.json unhandlich ist:

VariableWirkung
FORMGW_DATADatenverzeichnis (wie -data)
FORMGW_HOSTListen-Adresse, überschreibt host
FORMGW_PORTListen-Port, überschreibt port
FORMGW_CROWDSEC_URLLAPI-URL; gesetzt ⇒ die Meldung ist automatisch aktiv
FORMGW_CROWDSEC_MACHINE_IDWatcher-Login, überschreibt crowdsec.machine_id
FORMGW_CROWDSEC_PASSWORDWatcher-Passwort (Docker Secret), überschreibt crowdsec.password
TZZeitzone für Logs und Zeitstempel, z. B. Europe/Berlin

TZ wirkt auch in minimalen Containern und unter Windows — die Zeitzonendatenbank ist ins Binary eingebettet.

Entsteht beim ersten Start mit sicheren Zufallswerten und Dateirechten 0600. Vollständiges Beispiel:

{
"host": "127.0.0.1",
"port": 8080,
"database_path": "gateway.db",
"jwt_secret": "",
"encryption_key": "",
"access_token_ttl_minutes": 60,
"admin_initial_password": "",
"log_level": "info",
"access_log": true,
"api_key_rate_limit_per_minute": 120,
"login_max_attempts": 10,
"trusted_proxies": [],
"proxy_header": "X-Forwarded-For",
"crowdsec": {
"enabled": false,
"lapi_url": "http://127.0.0.1:8080",
"machine_id": "form-gateway",
"password": "",
"score_threshold": 100,
"window_minutes": 10,
"ban_duration": "4h",
"decision_type": "ban",
"origin": "crowdsec",
"scenario": "techeve/form-gateway",
"insecure_skip_verify": false
}
}
SchlüsselDefaultBedeutung
host127.0.0.1Listen-Adresse. Bewusst lokal — für direkten Zugriff ohne Proxy auf 0.0.0.0 setzen.
port8080Listen-Port. Admin-UI und Public API teilen ihn sich.
trusted_proxies[]IPs/CIDRs der eigenen Reverse-Proxys, deren X-Forwarded-For geglaubt wird. Kurzformen: loopback, private, linklocal.
proxy_headerX-Forwarded-ForHeader mit der Client-IP hinter dem Proxy.
SchlüsselBedeutung
database_pathPfad zur SQLite-Datei, relativ zum Datenverzeichnis oder absolut.
database_dsnGesetzt ⇒ PostgreSQL statt SQLite, z. B. postgres://user:pass@host:5432/db. Hat Vorrang vor database_path.
SchlüsselBedeutung
jwt_secretSigniert die Admin-Access-Tokens (HS256). Wird beim ersten Start zufällig erzeugt; unter 32 Zeichen verweigert das Gateway den Start.
encryption_keybase64-kodierte 32 Bytes. Verschlüsselt SMTP-Passwörter und Signing-Secrets in der Datenbank.
admin_initial_passwordNur beim allerersten Seeding relevant. Leer ⇒ es wird ein Zufallspasswort erzeugt und einmalig auf der Konsole ausgegeben. Danach wirkungslos.

Beide Werte niemals einchecken. Wer die Secrets rotieren will, sollte wissen, dass ein neues jwt_secret alle Sessions beendet und ein neuer encryption_key die bestehenden verschlüsselten Felder unbrauchbar macht.

SchlüsselDefaultBedeutung
access_token_ttl_minutes60Lebensdauer eines Admin-JWT. Nach Ablauf antwortet der Server 401 und das Frontend loggt automatisch aus (kein Refresh-Token-Flow).
api_key_rate_limit_per_minute120Requests pro API-Key und Minute; 0 schaltet ab. Gilt nur für die Admin-API — die Public API hat ihre eigene Pipeline.
login_max_attempts10Fehlversuche bei POST /auth/login je 5-Minuten-Fenster, getrennt gezählt pro Client-IP und pro Benutzername; darüber 429 mit Retry-After. Erfolgreiche Logins zählen nicht mit. 0 schaltet ab — nicht empfohlen: Der Endpunkt ist unauthentifiziert und jeder Versuch kostet 64 MiB argon2-Speicher.

Erkennt das Gateway ein Angriffsmuster, kann es die IP an eine CrowdSec Local API (LAPI) melden. Ein dort registrierter Bouncer sperrt sie dann in der vorgelagerten Firewall — der nächste Request erreicht den Service gar nicht mehr. Details und Einrichtung: Sicherheit → CrowdSec.

SchlüsselDefaultBedeutung
crowdsec.enabledfalseSchaltet die Meldung ein.
crowdsec.lapi_urlBasis-URL der LAPI, ohne /v1, z. B. http://127.0.0.1:8080.
crowdsec.machine_idWatcher-Login, angelegt mit cscli machines add form-gateway --password <pw>.
crowdsec.passwordPasswort dieses Watchers. Secret — besser per FORMGW_CROWDSEC_PASSWORD.
crowdsec.score_threshold100Summe der Signal-Gewichte, ab der gemeldet wird.
crowdsec.window_minutes10Beobachtungsfenster pro IP.
crowdsec.ban_duration4hSperrdauer der Decision — zugleich Cooldown: dieselbe IP wird in dieser Zeit nicht erneut gemeldet.
crowdsec.decision_typebanRemediation für den Bouncer, z. B. auch captcha.
crowdsec.origincrowdsecOrigin der Decision in cscli decisions list. Muss ein CrowdSec-bekannter Wert sein.
crowdsec.scenariotecheve/form-gatewaySzenario-Name in CrowdSec.
crowdsec.insecure_skip_verifyfalseTLS-Prüfung überspringen — nur für eine LAPI mit selbstsigniertem Zertifikat im eigenen Netz.
SchlüsselDefaultBedeutung
log_levelinfodebug, info, warn oder error.
access_logtrueProtokolliert jeden API-Request mit Methode, Pfad, Status, Dauer, IP und Username; 4xx als WARN, 5xx als ERROR.

Passwörter, Tokens, Signing-Secrets und vollständige Formularinhalte landen nie im Log. Client-IPs speichert die Datenbank ausschließlich als gekürzten SHA-256-Hash.

Die config.json wird beim Start gelesen — nach einer Änderung das Gateway neu starten:

Terminal-Fenster
sudo systemctl restart form-gateway # systemd
docker compose restart # Docker

Ist die Datei fehlerhaft, startet das Gateway nicht und nennt den Grund (zu kurzes Secret, ungültiger Port, unbekanntes Log-Level). Die Fehlermeldungen und was dahintersteckt: Installation.