Initialer Schema-Set (8 Migrationen, 13 Tabellen) für EdgeGuard v1: users + audit_log + system_settings, ha_nodes, backends/domains/ routing_rules/tls_certs, forward_proxy_acls, wireguard_peers, firewall_rules, dns_zones/dns_records, licenses. Migrations liegen in internal/database/migrations/ (analog mail-gateway) und werden per //go:embed ins Binary gepackt — keine separate SQL-Dateien im .deb. ValidateMigrations + Test schützen vor Duplicate-Versionen (mail-gateway 2026-05-08-Vorfall). GORM-Models für alle Tabellen, sensible Felder (password_hash, private_key_enc) sind json:"-". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
421 lines
23 KiB
Markdown
421 lines
23 KiB
Markdown
# EdgeGuard — Architektur
|
||
|
||
> Status: **v0.1 (Entwurf)** · Stand: 2026-05-08 · Ziel-Plattformen: Debian 13 (Trixie) + Ubuntu 24.04 LTS (Noble Numbat), Architekturen amd64 + arm64.
|
||
|
||
EdgeGuard ist die native Neufassung des bisherigen Docker-basierten Reverse-Proxy/Loadbalancer/Forward-Proxy/VPN-Stacks. Vorbild für Architektur, Build-System und Cluster-Modell ist [`mail-gateway`](../../mail-gateway/docs/architecture.md) (`nmg`); UI-Pattern und Bootstrap-Onliner stammen aus [`netcell-webpanel`](../../netcell-webpanel/CLAUDE.md) (`enconf`).
|
||
|
||
---
|
||
|
||
## 0. Leitplanken (nicht verhandelbar)
|
||
|
||
- **Kein Docker.** Alle Dienste nativ unter `systemd`, installiert via `apt`. Distro-Pakete für Drittsoftware (HAProxy, nginx, Squid, WireGuard, Unbound, PostgreSQL, KeyDB, certbot), eigene `.deb`-Pakete für EdgeGuard-Code (api, ui, ctl).
|
||
- **Plattform-Matrix:** Debian 13 (Trixie) **und** Ubuntu 24.04 LTS (Noble Numbat), je amd64 + arm64. Alle vier Targets gleichberechtigt.
|
||
- **Auslieferung:** signierte `.deb`-Pakete + Meta-Paket via APT. Bootstrap ist der enconf-analoge curl-Onliner `curl -fsSL https://get.edgeguard.netcell-it.de | sudo bash`.
|
||
- **HA nativ als Cluster:** N symmetrische Peers, **KeyDB Active-Active** für Shared State + **PostgreSQL Streaming Replication** (single writer, transparenter API-Write-Proxy) + **Floating-IP des Hosters** für HTTP/HTTPS-Ingress (nicht VRRP, nicht DNS-RR).
|
||
- **Kein WAF, kein IDS, kein DHCP, kein RADIUS, keine Mail-Funktion in v1.** Mail-Gateway ist eigenes Produkt (`nmg`); WAF/CrowdSec/Suricata kommen ggf. in v2.
|
||
- **Migrations:** `goose` (SQL-Dateien), nicht GORM AutoMigrate.
|
||
|
||
**Nicht-Ziele (ausdrücklich):** kein WAF, kein Network-IDS (Suricata), kein IPS (CrowdSec), kein DHCP-Server (Kea), kein RADIUS, keine Mail-Verarbeitung, keine Multi-Tenant-GuardZones in v1, keine ISO-Builds (kein EdgeGuardOS-Klon — nur APT).
|
||
|
||
---
|
||
|
||
## 1. Scope — fünf Daten-Services + Control-Plane
|
||
|
||
| Service | Rolle | Distro-Paket | Config-Quelle |
|
||
|---|---|---|---|
|
||
| **HAProxy** | Public-Ingress (80/443), interner LB (8081), TLS-PassThrough | `haproxy` (Debian/Ubuntu) | aus PG generiert, `systemctl reload haproxy` |
|
||
| **nginx** | Reverse-Proxy, vHost-Routing, ACME-Webroot | `nginx` (Debian/Ubuntu) | aus PG generiert, `systemctl reload nginx` |
|
||
| **Squid** | Forward-Proxy mit ACL/Auth | `squid` | aus PG generiert, `systemctl reload squid` |
|
||
| **WireGuard** | Site-to-Site- + Road-Warrior-VPN | `wireguard-tools` (Kernel-Modul ab Kernel 5.6) | aus PG generiert, `wg syncconf` |
|
||
| **Unbound** | Caching-Forwarder mit DNSSEC + Cluster-internes Split-Horizon (siehe §7.5) | `unbound` (Debian/Ubuntu) | aus PG generiert, `unbound-control reload` |
|
||
| **nftables** | Firewall (Input + Forward + NAT) | `nftables` | aus PG generiert, `nft -f /etc/nftables.conf` |
|
||
|
||
**Control-Plane:**
|
||
|
||
| Komponente | Rolle |
|
||
|---|---|
|
||
| `edgeguard-api` | Go/Gin REST-API, bindet `127.0.0.1:9443`, Reads aus lokaler PG, Writes an Cluster-Primary |
|
||
| `edgeguard-scheduler` | Cron-artige Jobs (ACME-Renewal-Hook, Backup, Health-Aggregation, License-Heartbeat) |
|
||
| `edgeguard-ctl` | CLI für Setup/Wartung (`initdb`, `migrate`, `cluster-join`, `promote`, `dump-config`) |
|
||
| `management-ui` | React 19 + AntD 6 + Vite, statisch unter `/usr/share/edgeguard/ui/`, nginx liefert aus |
|
||
| **PostgreSQL 16** | Single Source of Truth — Domains, Backends, Routing-Rules, ACLs, Peers, etc. |
|
||
| **KeyDB** (Redis-kompatibel) | Active-Active-Replication, Cluster-State, Locks, Rate-Counter, Pub/Sub für Config-Reload |
|
||
|
||
---
|
||
|
||
## 2. Package-Layout (Repo)
|
||
|
||
```
|
||
/var/www/edgeguard-native/
|
||
├── cmd/ # Go-Binary-Entry-Points
|
||
│ ├── edgeguard-api/ # Management-API (HTTP, 127.0.0.1:9443)
|
||
│ ├── edgeguard-scheduler/ # Cron-artige Jobs
|
||
│ └── edgeguard-ctl/ # CLI für Setup/Wartung
|
||
├── internal/
|
||
│ ├── database/ # pgxpool + goose-Runner, migrations/ via go:embed
|
||
│ │ └── migrations/ # 0001_*.sql … (goose-Format, embedded)
|
||
│ ├── models/ # GORM-Models (domain, backend, routing_rule, acl, peer, …)
|
||
│ ├── handlers/ # HTTP-Handler (REST)
|
||
│ ├── services/ # Business-Logik (config-render, health-check, cluster-sync)
|
||
│ ├── haproxy/ # HAProxy-Config-Generator
|
||
│ ├── nginx/ # nginx-Config-Generator (vHosts, Upstreams, ACME)
|
||
│ ├── squid/ # Squid-Config-Generator (squid.conf + squid.d/*)
|
||
│ ├── wireguard/ # WireGuard-Config-Generator (wg-quick + wg syncconf)
|
||
│ ├── unbound/ # Unbound-Config-Generator (Forwarder + Cluster-DNS)
|
||
│ ├── firewall/ # nftables-Ruleset-Generator
|
||
│ ├── cluster/ # Join/Promote/Peer-Discovery, KeyDB-Replication-Setup, pg_basebackup
|
||
│ ├── proxy/ # API-Write-Proxy-Middleware (Replica → Primary), mTLS-Calls
|
||
│ ├── aggregator/ # Cluster-View-APIs (alle Backends, alle Peers, alle Health-States)
|
||
│ └── license/ # License-Validation, License-Leader-Election (KeyDB-Lock)
|
||
├── management-ui/ # React 19 + AntD 6 + Vite (Struktur 1:1 wie netcell-webpanel/management-ui/)
|
||
├── packaging/
|
||
│ └── debian/
|
||
│ ├── edgeguard-api/ # control, postinst, postrm, conffiles, systemd-Units
|
||
│ ├── edgeguard-ui/
|
||
│ └── edgeguard-meta/ # nur Depends, keine Dateien
|
||
├── deploy/
|
||
│ ├── systemd/ # *.service, *.target, *.timer
|
||
│ ├── haproxy/ # haproxy.cfg.tpl
|
||
│ ├── nginx/ # nginx.conf.tpl, sni-map.tpl
|
||
│ ├── squid/ # squid.conf.tpl
|
||
│ ├── unbound/ # unbound.conf.tpl
|
||
│ └── nftables/ # ruleset.nft.tpl
|
||
├── scripts/
|
||
│ ├── apt-repo/ # build-package.sh, publish.sh, setup-repo.sh
|
||
│ ├── install.sh # Bootstrap-Onliner
|
||
│ └── release.sh # CI Release-Helper
|
||
├── docs/
|
||
├── Makefile
|
||
├── go.mod # module git.netcell-it.de/projekte/edgeguard-native
|
||
└── go.sum
|
||
```
|
||
|
||
**Go-Module-Name:** `git.netcell-it.de/projekte/edgeguard-native`
|
||
**Build-System:** `Makefile` (POSIX-kompatibel). Targets: `build`, `test`, `lint`, `deb`, `clean`, `install-local`, `release`.
|
||
|
||
---
|
||
|
||
## 3. Debian-Pakete
|
||
|
||
Drei Pakete + Meta — analog nmg, kein WAF-Paket weil kein WAF in v1.
|
||
|
||
| Paket | Arch | Inhalt | Depends |
|
||
|---|---|---|---|
|
||
| `edgeguard-api` | amd64, arm64 | `/usr/bin/edgeguard-{api,scheduler,ctl}`, Unit-Files, Migrations, Default-Configs | `postgresql-16`, `keydb-server`, `nginx`, `haproxy`, `squid`, `wireguard-tools`, `unbound`, `nftables`, `certbot` |
|
||
| `edgeguard-ui` | all | `/usr/share/edgeguard/ui/` (statische Build-Artefakte), nginx-Site | `edgeguard-api (= ${binary:Version})`, `nginx` |
|
||
| `edgeguard-meta` | all | keine Dateien, nur `Depends` | `edgeguard-api`, `edgeguard-ui` |
|
||
|
||
Pro Release: 1 arch-spezifisch × 2 Dists × 2 Arches = 4 `.deb` + 2 arch-agnostische × 2 Dists = 4 `.deb` → **8 Artefakte je Release**.
|
||
|
||
**KeyDB-Herkunft:** KeyDB ist weder in `trixie` noch `noble` in den offiziellen Repos. Wir bauen es aus Source (amd64 + arm64), veröffentlichen es parallel im eigenen APT-Repo. `edgeguard-api` `Depends: keydb-server` löst aus unserem Repo aus.
|
||
|
||
**Build-Werkzeug:** **direkter `dpkg-deb`-Build** analog WebPanel/EdgeGuardOS-Pattern. **Nicht** `dh_make`/`debhelper`, **nicht** `fpm`. Konsistenz mit existierendem Workflow.
|
||
|
||
**postinst (`edgeguard-api`):**
|
||
1. User `edgeguard` anlegen (`adduser --system --group --home /var/lib/edgeguard`).
|
||
2. `/etc/edgeguard/`, `/var/lib/edgeguard/`, `/var/log/edgeguard/` mit `0750`, `chown edgeguard:edgeguard`.
|
||
3. Default-Configs nur anlegen wenn nicht vorhanden (`conffiles` verhindert Überschreiben).
|
||
4. PostgreSQL: `edgeguard-ctl initdb` (idempotent — prüft DB/User).
|
||
5. DB-Migration: `edgeguard-ctl migrate up`.
|
||
6. `systemctl daemon-reload && systemctl enable --now edgeguard-api.service edgeguard-scheduler.service`.
|
||
|
||
**postrm (purge):** DB + User nur bei `purge`, *niemals* bei `remove`.
|
||
|
||
---
|
||
|
||
## 4. Verzeichnis-Layout auf Zielsystem
|
||
|
||
```
|
||
/etc/edgeguard/
|
||
├── edgeguard.yaml # Hauptconfig (conffile)
|
||
├── api.env # API-Secrets (mode 0600, edgeguard:edgeguard)
|
||
├── haproxy/ # haproxy.cfg-Fragmente (von edgeguard-api generiert)
|
||
├── nginx/ # vHosts + sni-map (generiert)
|
||
├── squid/ # squid.conf-Fragmente
|
||
├── wireguard/ # wg0.conf etc. (generiert)
|
||
├── unbound/ # unbound.conf + cluster-zone.conf (generiert)
|
||
├── nftables.d/ # Ruleset-Fragmente
|
||
└── tls/ # ACME-verwaltete Zertifikate (0750, edgeguard:edgeguard)
|
||
|
||
/var/lib/edgeguard/
|
||
├── state/ # Migrations-Marker, Cluster-Cursor
|
||
├── trial.json # Lizenz-Trial-File
|
||
├── .jwt_fingerprint # JWT-Secret-Fingerprint (analog enconf — Schutz vor Rotation)
|
||
└── backups/ # lokale PG-Dumps (vor Migration)
|
||
|
||
/var/log/edgeguard/
|
||
├── api.log
|
||
├── scheduler.log
|
||
└── audit.log
|
||
|
||
/usr/bin/
|
||
├── edgeguard-api
|
||
├── edgeguard-scheduler
|
||
└── edgeguard-ctl
|
||
|
||
/usr/share/edgeguard/
|
||
├── ui/ # statische React-Build-Artefakte
|
||
└── templates/ # Config-Templates für haproxy/nginx/squid/wireguard/unbound/nftables
|
||
```
|
||
|
||
Entspricht FHS — keine Überraschungen für Admins, Lintian-clean.
|
||
|
||
---
|
||
|
||
## 5. systemd-Units
|
||
|
||
| Unit | Typ | Depends-on | User | Restart |
|
||
|---|---|---|---|---|
|
||
| `edgeguard-api.service` | `simple` | `postgresql.service`, `keydb-server.service` | `edgeguard` | `on-failure`, `RestartSec=5` |
|
||
| `edgeguard-scheduler.service` | `simple` | `edgeguard-api.service` | `edgeguard` | `on-failure` |
|
||
| `edgeguard-cert-deploy.path` | `path` | — | — | — |
|
||
| `edgeguard-firewall.service` | `oneshot`, `RemainAfterExit=true` | — | root | — |
|
||
| `edgeguard.target` | `target` | api+scheduler | — | — |
|
||
|
||
Hardening-Defaults pro Unit (außer `edgeguard-firewall`, das braucht `CAP_NET_ADMIN`):
|
||
```
|
||
NoNewPrivileges=true
|
||
ProtectSystem=strict
|
||
ProtectHome=true
|
||
ProtectKernelTunables=true
|
||
ProtectKernelModules=true
|
||
ProtectControlGroups=true
|
||
PrivateTmp=true
|
||
PrivateDevices=true
|
||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||
SystemCallFilter=@system-service
|
||
ReadWritePaths=/var/lib/edgeguard /var/log/edgeguard /etc/edgeguard
|
||
```
|
||
|
||
Drittsoftware (HAProxy, nginx, Squid, WireGuard via `wg-quick@.service`, Unbound, nftables) läuft als **Distro-Units**. EdgeGuard generiert deren Config + signalisiert Reload, übernimmt aber die Service-Verwaltung **nicht**.
|
||
|
||
API bindet auf `127.0.0.1:9443` (nicht öffentlich). nginx terminiert TLS auf `:443` und proxied an die API.
|
||
|
||
---
|
||
|
||
## 6. Datenbank-Setup
|
||
|
||
- **PostgreSQL 16**, Distro-Paket `postgresql-16`.
|
||
- **Verbindung:** Unix-Socket (`/var/run/postgresql`) für lokale Reads + Writes der API. TCP/5432 mit TLS-Client-Cert nur zwischen Cluster-Peers für Streaming Replication.
|
||
- **Topologie:** **ein logischer Primary** zu jedem Zeitpunkt, N Read-Replicas. Lokale API liest immer aus lokaler PG; Writes routet die API-Write-Proxy-Middleware transparent an den aktuellen Primary (KeyDB-Key `cluster:pg-primary-url`).
|
||
- **Migrations:** `goose` (SQL-Dateien in `internal/database/migrations/`, via `//go:embed` ins Binary gepackt). **Nicht** GORM AutoMigrate.
|
||
|
||
GORM bleibt als ORM für Query-Komfort; nur das Schema-Management wechselt zu `goose`.
|
||
|
||
---
|
||
|
||
## 7. KeyDB Active-Active
|
||
|
||
KeyDB ersetzt Redis. **Active-Active Replication** (Multi-Master, operation-basiert, split-brain-tolerant).
|
||
|
||
**Verwendung:**
|
||
- `cluster:pg-primary-url` — wer ist aktueller PG-Primary?
|
||
- `cluster:license-leader` — Lock für License-Heartbeat (`SET … NX EX 60`)
|
||
- `cluster:license-status` — Cache des Lizenz-Validate-Ergebnisses (TTL 24 h)
|
||
- `cluster:nodes:<node-id>` — Heartbeat-Marker (TTL 2 min)
|
||
- `ratelimit:<scope>:<key>` — Rate-Counter (HINCRBY-Ops mergen korrekt)
|
||
- `acme:lock:<domain>` — verhindert Parallel-Issue auf zwei Nodes
|
||
- Pub/Sub: `edgeguard:config-changed` — alle Nodes regenerieren Config
|
||
|
||
KeyDB hört nur auf `127.0.0.1:6379` für lokale Clients und `<node-ip>:16379` (TLS) für Peer-Replication.
|
||
|
||
---
|
||
|
||
## 7.5 Unbound — DNS Forwarder + Cluster-DNS
|
||
|
||
Unbound erfüllt zwei Rollen, beide aus PG generiert:
|
||
|
||
### Rolle 1 — Caching-Forwarder mit DNSSEC
|
||
|
||
- Forwardet rekursive Queries an Upstream-Resolver (default `1.1.1.1`, `9.9.9.9`; per UI/PG konfigurierbar).
|
||
- **DNSSEC-Validation aktiv** (`auto-trust-anchor-file`).
|
||
- Lokaler Cache (TTL nach Upstream-Antwort).
|
||
- Listen: `127.0.0.1:53` für die EdgeGuard-Box selbst und `<node-internal-ip>:53` für VPN- und LAN-Clients (über nftables-ACL gefiltert).
|
||
- Genutzt von `edgeguard-api`, `edgeguard-scheduler` (License-Heartbeat, ACME), Squid (für Forward-Proxy-Resolutions), HAProxy/nginx (Backend-Health-Checks).
|
||
|
||
### Rolle 2 — Cluster-internes Split-Horizon
|
||
|
||
- **Local-Zone** `eg.cluster.` enthält A/AAAA-Records aller Cluster-Peers (Node-Hostnamen aus PG `ha_nodes`).
|
||
- Beispiel: `node1.eg.cluster → 10.42.0.11`, `node2.eg.cluster → 10.42.0.12`.
|
||
- Wird bei jedem Node-Join/-Leave aus PG regeneriert + via `edgeguard:config-changed` Pub/Sub auf allen Peers neu geladen (`unbound-control reload`).
|
||
- Cluster-interner Traffic (PG-Replication, KeyDB-Replication, mTLS-API-Calls, Cert-Push) löst Peer-Adressen ausschließlich über diese Zone auf — kein DNS-Roundtrip ins öffentliche Internet, keine `/etc/hosts`-Synchronisation.
|
||
- `<node-name>.eg.cluster` ist **nicht extern erreichbar** (nur über Unbound der Cluster-Peers).
|
||
|
||
### Config-Schichten
|
||
|
||
`/etc/edgeguard/unbound/unbound.conf` ist Distro-Konfig-Datei. Generator schreibt drei Includes:
|
||
|
||
```
|
||
# /etc/edgeguard/unbound/forwarders.conf — Upstream-Resolver
|
||
# /etc/edgeguard/unbound/cluster-zone.conf — Local-Zone eg.cluster
|
||
# /etc/edgeguard/unbound/access.conf — access-control: pro CIDR
|
||
```
|
||
|
||
Reload via `unbound-control reload` (kein Restart, keine Cache-Invalidierung außer für die geänderte Zone — `unbound-control auth_zone_reload eg.cluster`).
|
||
|
||
---
|
||
|
||
## 8. Cluster-Topologie & HA pro Service
|
||
|
||
**N symmetrische Peers** (1 … N Nodes, jeder vollwertig). Keine VRRP, keine Master/Backup-Rollen für Daten-Services. Public-IP: **Floating-IP des Hosters** (siehe §9).
|
||
|
||
| Service | HA-Strategie |
|
||
|---|---|
|
||
| **HAProxy** | stateless, pro Node identisch. Floating-IP zeigt zum aktuellen aktiven Node; bei Node-Ausfall API-Call zum Hoster (oder manueller Switch) reicht. |
|
||
| **nginx** | stateless, pro Node identisch. ACME-Issue nur auf License-Leader (KeyDB-Lock); Zerts werden via PG/mTLS an alle verteilt. |
|
||
| **Squid** | stateless (Cache lokal, kein Sync nötig). Pro Node identische ACL-Config. |
|
||
| **WireGuard** | siehe §8.1 |
|
||
| **Unbound** | stateless (Cache lokal). Pro Node identische Forwarder-Config + identische Cluster-internen Local-Zones (siehe §7.5). |
|
||
| **nftables** | pro Node identisch, Ruleset aus PG generiert. `crowdsec_blocklist`/`threat_intel_blocklist`-Sets entfallen in v1 (kein CrowdSec). |
|
||
| **edgeguard-api** | pro Node, Reads lokal, Writes via Proxy zu Primary. |
|
||
| **edgeguard-ui** | statisch, pro Node identisch. |
|
||
| **PostgreSQL** | Streaming Replication, manueller Promote (siehe nmg §6.2). |
|
||
| **KeyDB** | Active-Active. |
|
||
|
||
### 8.1 WireGuard im Cluster
|
||
|
||
Drei Optionen, für v1 wählen wir **Option A**:
|
||
|
||
- **A — Geteilte Server-Identität (gewählt):** alle Peers haben **denselben** Server-Privatkey + dasselbe Listen-Port. Floating-IP routet UDP zum aktiven Node. Bei Failover: Floating-IP wandert, Clients schicken Pakete zum neuen Node, neuer Handshake (~1–2s Latenz beim ersten Paket). Replay-Protection-Counter werden nicht repliziert — beim Failover macht der Client neuen Handshake, alte Counter sind irrelevant.
|
||
- B — Pro Node eigene Identität, Client kennt alle: Client-Configs haben mehrere `[Peer]`-Blöcke. Aufwendiger zu provisionieren, kein Failover-Vorteil.
|
||
- C — Aktiv/Standby per License-Leader-Pattern: nur ein Node hat WireGuard aktiv, andere idle. Verschwendet Kapazität.
|
||
|
||
**Begründung A:** Privatkey ist in PG (verschlüsselt mit `edgeguard.key`), wird beim Cluster-Join an neue Peers verteilt. WireGuard handelt selbständig neue Sessions aus, kein State-Sync nötig. Operation-Tools (Peer hinzufügen/entfernen) wirken auf alle Nodes via `edgeguard:config-changed` Pub/Sub + lokales `wg syncconf`.
|
||
|
||
### 8.2 Manual Promote (PG-Primary-Failover)
|
||
|
||
1:1 nmg-Pattern (siehe `mail-gateway/docs/architecture.md` §6.2). Bei Ausfall des Primary antworten Config-Writes mit `503 + actionable Error`. Admin promotet via UI/CLI. Datenebene (HAProxy/nginx/Squid/WireGuard/Unbound) läuft unbeeinträchtigt weiter, weil jeder Node eine lokale PG-Replica hat.
|
||
|
||
### 8.3 License-Leader-Election
|
||
|
||
Ein einziger Node kontaktiert `license.netcell-it.com` (KeyDB-Lock, 60-s-TTL). Ergebnis cluster-weit in `cluster:license-status` (TTL 24 h). `active_servers`-Verbrauchswert = Count der Peers mit Heartbeat < 2 min.
|
||
|
||
---
|
||
|
||
## 9. Public-Ingress — Floating-IP statt VRRP
|
||
|
||
**Problem:** HTTP-Clients machen kein automatisches Failover bei DNS-RR (anders als MTAs). Ein toter A-Record = 50% Fehler bis DNS-TTL.
|
||
|
||
**Entscheidung:** **Floating-IP des Hosters**. Der Hoster bietet eine API zum Umroute der IP zwischen Servern (z. B. via REST oder DNS-Update bei dynamischer Anycast-Lösung). Failover dauert Sekunden, kein VRRP-Drama, kein "VIP verschwindet"-Problem aus dem alten Setup.
|
||
|
||
Optionen pro Hoster:
|
||
1. **Provider-Floating-IP** (gewünscht): API-Call schaltet IP um. EdgeGuard exponiert `POST /api/v1/cluster/promote-this-node`, das die Hoster-API aufruft.
|
||
2. **DNS-RR mit kurzer TTL (60s)** als Notlösung wenn keine Floating-IP verfügbar.
|
||
3. **Anycast/BGP** als Premium-Variante (für Enterprise).
|
||
|
||
**v1-Default:** Single-Node mit fest zugewiesener Floating-IP. Cluster-Erweiterung kommt mit Phase 2.
|
||
|
||
⚑ **OFFEN:** Welcher Hoster ist Standard? API-Spec dokumentieren sobald geklärt.
|
||
|
||
---
|
||
|
||
## 10. Erst-Einrichtung — curl-Onliner
|
||
|
||
```
|
||
curl -fsSL https://get.edgeguard.netcell-it.de | sudo bash
|
||
```
|
||
|
||
Schritte (idempotent, analog `netcell-webpanel/install.sh`):
|
||
|
||
1. **OS-Detection** (`/etc/os-release`): nur Trixie *oder* Noble, sonst Abbruch.
|
||
2. **Arch-Detection**: nur amd64 *oder* arm64.
|
||
3. **Base-Deps:** `curl gnupg ca-certificates apt-transport-https`.
|
||
4. **APT-Keyrings:**
|
||
- `https://apt.netcell-it.de/edgeguard/repository.key` → `/etc/apt/keyrings/netcell-edgeguard.gpg`
|
||
5. **APT-Sources:** `/etc/apt/sources.list.d/netcell-edgeguard.list`.
|
||
6. **Install:** `apt-get install -y edgeguard` (Meta-Paket).
|
||
7. **Auto-Security-Updates:** `unattended-upgrades` + `apt-listchanges` (nach enconf-Muster).
|
||
8. **Setup-Modus:** `edgeguard-api` läuft im Setup-Modus bis Admin-User existiert. UI leitet alle Anfragen auf `/setup` um. Wizard: Admin-Account, FQDN, ACME-Email, Lizenz oder Trial.
|
||
|
||
**Cluster-Join (zusätzlicher Peer):**
|
||
```
|
||
curl -fsSL https://get.edgeguard.netcell-it.de | sudo bash -s -- \
|
||
--join https://<existing-node-fqdn> \
|
||
--token <cluster-join-token>
|
||
```
|
||
|
||
`edgeguard-ctl cluster-join` führt aus: PG-Basebackup vom Primary, KeyDB-Replication-Setup, Node-Registrierung in `ha_nodes`, TLS-Cert-Pull via mTLS, Config-Regeneration, Service-Start.
|
||
|
||
---
|
||
|
||
## 11. Update-Pfad (apt-Repo)
|
||
|
||
- **Primärquelle:** Gitea Package Registry (`https://git.netcell-it.de/api/packages/projekte/debian`).
|
||
- **Kunden-Mirror:** `https://apt.netcell-it.de/edgeguard/` (rsync von Gitea).
|
||
- **Suiten:** `stable` · `testing` · `security` — pro Codename (`trixie`, `noble`).
|
||
- **Signatur:** GPG-Key `netcell-edgeguard-signing`, ausgeliefert in `/etc/apt/keyrings/`.
|
||
- **Update-Check-API:** `GET /api/v1/system/package-versions` → pro `edgeguard-*`-Paket `{name, installed, available, reboot_required}`.
|
||
- **Upgrade-Trigger:** `POST /api/v1/system/upgrade` startet `systemd-run --unit=edgeguard-upgrade.service --collect …` (HTTP-Response geht VOR dem Upgrade raus, weil API beim Self-Update stirbt — Pattern aus `netcell-webpanel/management-agent/internal/handlers/update.go:105`).
|
||
|
||
Build-/Release-Scripts identisch zu `mail-gateway/scripts/apt-repo/`.
|
||
|
||
---
|
||
|
||
## 12. Lizenz & ACME
|
||
|
||
### 12.1 Lizenz
|
||
|
||
1:1 nach `netcell-webpanel/docs/licensing-integration.md`. Verbrauchswert: `active_domains` (Anzahl konfigurierter EdgeGuard-Domains).
|
||
|
||
- **Lizenzserver:** `https://license.netcell-it.com` (öffentlich, kein API-Key).
|
||
- **Verify-Endpoint:** `GET /api/v1/licenses/{key}/verify?system_id={fp}&system_name={host}&active_domains={n}`.
|
||
- **Fingerprint:** `SHA256(/etc/machine-id + erste-aktive-MAC + hostname)`.
|
||
- **Caching:** Live → KeyDB `cluster:license-status` (TTL 24h) → `/var/lib/edgeguard/trial.json` (30 Tage) → `expired`.
|
||
- **Leader-Election** wie nmg §6.3.
|
||
|
||
### 12.2 ACME
|
||
|
||
- **certbot** (Distro-Paket) mit `--webroot`-Plugin für nginx-vHosts.
|
||
- **Lock vor Issue:** `acme:lock:<domain>` in KeyDB verhindert Parallel-Issue auf zwei Nodes.
|
||
- **Deploy-Hook:** schreibt Sentinel-Datei → `edgeguard-cert-deploy.path`-Unit triggert nginx-/HAProxy-Reload.
|
||
- **Cert-Verteilung im Cluster:** Issuing-Node pushed via mTLS-API an alle Peers, Zerts landen in `/etc/edgeguard/tls/`.
|
||
|
||
---
|
||
|
||
## 13. UI — 100% enconf-WebPanel-Pattern
|
||
|
||
Komponentenbibliothek, Theme, Layouts, Navigations-Struktur, Form-Patterns, i18n-Setup vollständig 1:1 aus `netcell-webpanel/management-ui/`. Keine eigenen Design-Entscheidungen.
|
||
|
||
**Pflichtlektüre:**
|
||
- `netcell-webpanel/docs/design-system.md`
|
||
- `netcell-webpanel/docs/design.md`
|
||
- `netcell-webpanel/docs/frontend-reference.md`
|
||
|
||
**Stack:** React 19 + TypeScript strict, Vite, Ant Design 6.x, TanStack Query 5, axios, i18next (de/en), `@uiw/react-codemirror`, `recharts`, ESLint flat config.
|
||
|
||
**Seiten v1:** Dashboard · Domains · Backends · Routing-Rules · SSL · ForwardProxy (Squid) · VPN (WireGuard) · Firewall · Cluster · Logs · Settings · Setup-Wizard.
|
||
|
||
---
|
||
|
||
## 14. Plattform-Matrix
|
||
|
||
| Distribution | Codename | Arch | Status v1 |
|
||
|---|---|---|---|
|
||
| Debian 13 | trixie | amd64 | Tier 1 |
|
||
| Debian 13 | trixie | arm64 | Tier 1 |
|
||
| Ubuntu 24.04 LTS | noble | amd64 | Tier 1 |
|
||
| Ubuntu 24.04 LTS | noble | arm64 | Tier 1 |
|
||
|
||
Andere Distributionen (Debian 12, Ubuntu 22.04, RHEL/Rocky) sind **nicht unterstützt**. Installer bricht hart ab.
|
||
|
||
---
|
||
|
||
## 15. Migration vom Docker-Stand
|
||
|
||
EdgeGuard-Native ist eigenes Repo (`git.netcell-it.de/projekte/edgeguard-native`), parallel zum bestehenden `proxy-lb-waf`. Migration:
|
||
|
||
1. **Frische Installation** auf Test-VM via `install.sh`.
|
||
2. **Config-Export** aus altem Stack (`edgeguard-ctl export --from-docker`) — liest aus alter PG, schreibt in neues Format.
|
||
3. **Validierung** Side-by-Side (alter Stack auf einem Server, neuer Stack auf anderem, Traffic vergleichen).
|
||
4. **Cutover** via Floating-IP-Switch.
|
||
|
||
Der alte `proxy-lb-waf`-Code bleibt für Bestandskunden im Wartungsmodus, keine neuen Features.
|
||
|
||
---
|
||
|
||
## Offene Punkte
|
||
|
||
- **Hoster + Floating-IP-API** (§9): Spec dokumentieren.
|
||
- **WireGuard-State-Replication** in der Praxis testen (Handshake-Latenz nach Floating-IP-Switch messen).
|
||
- **`get.edgeguard.netcell-it.de`** anlegen oder Übergangs-URL auf `apt.netcell-it.de/edgeguard/install.sh` nutzen.
|