Installation
Eine Installation besteht aus drei Dateien: dem Binary, einer
config.json und der Datenbank. Die beiden letzten entstehen beim ersten
Start von selbst.
Wer nur ausprobieren will, springt zum Demo-Modus; wer Container bevorzugt, zu Betrieb mit Docker.
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“Zum Betrieb genügt das Binary — keine Runtime, keine Bibliotheken. Es ist CGO-frei und statisch gelinkt, Zeitzonendaten sind eingebettet.
Zum Bauen:
| Werkzeug | Version | Wofür |
|---|---|---|
| Go | ≥ 1.26 (siehe go.mod) | Backend und Binary |
| Node.js | LTS | Admin-UI (Vite-Build) |
| Zugriff auf ORM++ | privates Go-Modul auf gitlab.techeve.de | Persistenzschicht |
ORM++ liegt als privates Modul auf dem GitLab-Server. Einmalig setzen:
go env -w GOPRIVATE=gitlab.techeve.deDie Zugangsdaten kommen lokal aus dem Schlüsselbund, in CI über den Job-Token.
Binary bauen
Abschnitt betitelt „Binary bauen“make build # npm audit → vite build → govulncheck → go buildDas Ergebnis liegt unter bin/form-gateway. Die Sicherheits-Gates sind
Teil des Builds: Findet npm audit oder govulncheck etwas, bricht er
ab — ein verwundbares Binary entsteht gar nicht erst.
Für andere Zielplattformen (CGO-frei, also ohne Cross-Toolchain):
make build-linux # bin/form-gateway-linux-amd64make build-linux-arm64 # bin/form-gateway-linux-arm64make build-windows # bin/form-gateway-windows-amd64.exemake build-macos # bin/form-gateway-darwin-arm64 (Apple Silicon)make build-macos-intel # bin/form-gateway-darwin-amd64make build-all # alle PlattformenErster Start
Abschnitt betitelt „Erster Start“./bin/form-gatewayBeim ersten Start passiert Folgendes — einmalig und automatisch:
- Eine
config.jsonentsteht mit kryptografisch zufälligen Secrets (JWT-Secret,encryption_key) und Dateirechten0600. - Die Datenbank wird angelegt und migriert (SQLite, Default
gateway.db). - Die Benutzer
systemundadminwerden angelegt. Das generierte Admin-Passwort erscheint genau einmal auf der Konsole.
Danach lauscht das Gateway auf http://127.0.0.1:8080 — Admin-UI und Public API teilen sich denselben Port.
Datenverzeichnis wählen
Abschnitt betitelt „Datenverzeichnis wählen“Ohne Angabe liegen config.json und Datenbank neben dem Binary. Für
einen Serverbetrieb gehören sie woandershin:
./form-gateway -data /var/lib/form-gatewayGleichwertig über die Umgebung: FORMGW_DATA=/var/lib/form-gateway.
Alle Flags und Variablen stehen unter Konfiguration.
Einrichten: Route zuerst, dann Mandant
Abschnitt betitelt „Einrichten: Route zuerst, dann Mandant“Nach dem Login im Admin-UI in dieser Reihenfolge vorgehen — ein Mandant ohne Route kann nicht versenden:
- SMTP-Route anlegen und als geteilte Default-Route markieren. Mit dem Test-Versand-Button prüfen, dass Verbindung und Login stehen.
- Mandant anlegen — Empfängeradresse und erlaubte Origins eintragen.
- Den angezeigten Site-Key in das Formular der Kundenseite übernehmen.
Ausführlich: Bedienung des Admin-UI und Formular einbinden.
Dauerbetrieb mit systemd
Abschnitt betitelt „Dauerbetrieb mit systemd“/etc/systemd/system/form-gateway.service:
[Unit]Description=Techeve Form GatewayAfter=network.target
[Service]User=formgwWorkingDirectory=/opt/form-gatewayExecStart=/opt/form-gateway/form-gateway -data /var/lib/form-gatewayRestart=on-failure
[Install]WantedBy=multi-user.targetsudo useradd --system --home /var/lib/form-gateway formgwsudo mkdir -p /opt/form-gateway /var/lib/form-gatewaysudo chown formgw /var/lib/form-gatewaysudo systemctl enable --now form-gatewaysudo journalctl -u form-gateway -f # hier steht das Admin-Passwort des ErststartsDas Binary behandelt SIGINT und SIGTERM mit Graceful Shutdown und stoppt
dabei auch die Hintergrund-Worker sauber — systemctl restart verliert
keine Mail aus der Queue.
Reverse-Proxy und TLS
Abschnitt betitelt „Reverse-Proxy und TLS“Das Gateway spricht HTTP und bindet standardmäßig an 127.0.0.1. TLS
terminiert ein Reverse-Proxy davor; Public API (/v1) und Admin-UI
laufen über denselben Port und brauchen keine getrennte Konfiguration.
server { listen 443 ssl http2; server_name forms.example.de;
# ssl_certificate ... (z. B. via certbot)
location / { proxy_pass http://127.0.0.1:8080; 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; }}Soll das Gateway ohne Proxy direkt erreichbar sein, muss host bewusst
auf 0.0.0.0 gesetzt werden — der Default bindet absichtlich nur lokal.
Ausgehende Verbindungen
Abschnitt betitelt „Ausgehende Verbindungen“Der Server braucht Zugriff auf:
- die SMTP-Server der konfigurierten Routen (Port 587 bzw. 465),
- iptoasn.com und check.torproject.org für den täglichen Reputations-Refresh.
Ohne den zweiten Punkt läuft das Gateway weiter, die ASN- und Tor-Erkennung arbeitet dann aber mit veralteten Daten.
PostgreSQL statt SQLite
Abschnitt betitelt „PostgreSQL statt SQLite“SQLite ist der Standard und für den typischen Betrieb völlig
ausreichend. Für PostgreSQL genügt eine Zeile in der config.json:
"database_dsn": "postgres://formgw:geheim@localhost:5432/formgw"Mehr ist nicht zu tun — ORM++ macht beide Backends verhaltensgleich, der Anwendungscode verzweigt nirgends nach Datenbank. Details: Datenbank.
Aktualisieren
Abschnitt betitelt „Aktualisieren“sudo systemctl stop form-gatewaysudo cp bin/form-gateway-linux-amd64 /opt/form-gateway/form-gatewaysudo systemctl start form-gatewaySchemaänderungen wendet ORM++ beim Start selbst an: additive Änderungen
automatisch, Umbauten über versionierte Migrationsschritte. Vor dem
Update trotzdem das Datenverzeichnis sichern — config.json und
Datenbank liegen beieinander, ein tar genügt.
Die laufende Version prüfen:
./form-gateway -versioncurl -s http://127.0.0.1:8080/api/v1/healthWenn der Start fehlschlägt
Abschnitt betitelt „Wenn der Start fehlschlägt“| Meldung | Ursache |
|---|---|
jwt_secret ist zu kurz | Von Hand bearbeitete config.json. Mindestens 32 Zeichen; alternativ die Datei löschen und neu erzeugen lassen (Achtung: neuer encryption_key macht verschlüsselte Felder unlesbar). |
encryption_key muss 32 Bytes lang sein | Der Key ist base64-kodiert und muss 32 Bytes ergeben — nicht kürzen, nicht ersetzen. |
ungültiges log_level | Erlaubt sind nur debug, info, warn, error. |
| Startfehler wegen Schema-Drift | Ein Model wurde geändert, ohne die Schemaversion zu erhöhen — siehe Datenbank. |
datenverzeichnis anlegen: permission denied | Der Service-User darf im -data-Pfad nicht schreiben. |
Mehr Details im Log: ./form-gateway -debug hebt das Level zur Laufzeit
auf debug an.