Zum Inhalt springen

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.

Zum Betrieb genügt das Binary — keine Runtime, keine Bibliotheken. Es ist CGO-frei und statisch gelinkt, Zeitzonendaten sind eingebettet.

Zum Bauen:

WerkzeugVersionWofür
Go≥ 1.26 (siehe go.mod)Backend und Binary
Node.jsLTSAdmin-UI (Vite-Build)
Zugriff auf ORM++privates Go-Modul auf gitlab.techeve.dePersistenzschicht

ORM++ liegt als privates Modul auf dem GitLab-Server. Einmalig setzen:

Terminal-Fenster
go env -w GOPRIVATE=gitlab.techeve.de

Die Zugangsdaten kommen lokal aus dem Schlüsselbund, in CI über den Job-Token.

Terminal-Fenster
make build # npm audit → vite build → govulncheck → go build

Das 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):

Terminal-Fenster
make build-linux # bin/form-gateway-linux-amd64
make build-linux-arm64 # bin/form-gateway-linux-arm64
make build-windows # bin/form-gateway-windows-amd64.exe
make build-macos # bin/form-gateway-darwin-arm64 (Apple Silicon)
make build-macos-intel # bin/form-gateway-darwin-amd64
make build-all # alle Plattformen
Terminal-Fenster
./bin/form-gateway

Beim ersten Start passiert Folgendes — einmalig und automatisch:

  1. Eine config.json entsteht mit kryptografisch zufälligen Secrets (JWT-Secret, encryption_key) und Dateirechten 0600.
  2. Die Datenbank wird angelegt und migriert (SQLite, Default gateway.db).
  3. Die Benutzer system und admin werden 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.

Ohne Angabe liegen config.json und Datenbank neben dem Binary. Für einen Serverbetrieb gehören sie woandershin:

Terminal-Fenster
./form-gateway -data /var/lib/form-gateway

Gleichwertig über die Umgebung: FORMGW_DATA=/var/lib/form-gateway. Alle Flags und Variablen stehen unter Konfiguration.

Nach dem Login im Admin-UI in dieser Reihenfolge vorgehen — ein Mandant ohne Route kann nicht versenden:

  1. SMTP-Route anlegen und als geteilte Default-Route markieren. Mit dem Test-Versand-Button prüfen, dass Verbindung und Login stehen.
  2. Mandant anlegen — Empfängeradresse und erlaubte Origins eintragen.
  3. Den angezeigten Site-Key in das Formular der Kundenseite übernehmen.

Ausführlich: Bedienung des Admin-UI und Formular einbinden.

/etc/systemd/system/form-gateway.service:

[Unit]
Description=Techeve Form Gateway
After=network.target
[Service]
User=formgw
WorkingDirectory=/opt/form-gateway
ExecStart=/opt/form-gateway/form-gateway -data /var/lib/form-gateway
Restart=on-failure
[Install]
WantedBy=multi-user.target
Terminal-Fenster
sudo useradd --system --home /var/lib/form-gateway formgw
sudo mkdir -p /opt/form-gateway /var/lib/form-gateway
sudo chown formgw /var/lib/form-gateway
sudo systemctl enable --now form-gateway
sudo journalctl -u form-gateway -f # hier steht das Admin-Passwort des Erststarts

Das Binary behandelt SIGINT und SIGTERM mit Graceful Shutdown und stoppt dabei auch die Hintergrund-Worker sauber — systemctl restart verliert keine Mail aus der Queue.

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.

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.

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.

Terminal-Fenster
sudo systemctl stop form-gateway
sudo cp bin/form-gateway-linux-amd64 /opt/form-gateway/form-gateway
sudo systemctl start form-gateway

Schemaä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:

Terminal-Fenster
./form-gateway -version
curl -s http://127.0.0.1:8080/api/v1/health
MeldungUrsache
jwt_secret ist zu kurzVon 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 seinDer Key ist base64-kodiert und muss 32 Bytes ergeben — nicht kürzen, nicht ersetzen.
ungültiges log_levelErlaubt sind nur debug, info, warn, error.
Startfehler wegen Schema-DriftEin Model wurde geändert, ohne die Schemaversion zu erhöhen — siehe Datenbank.
datenverzeichnis anlegen: permission deniedDer Service-User darf im -data-Pfad nicht schreiben.

Mehr Details im Log: ./form-gateway -debug hebt das Level zur Laufzeit auf debug an.