chore: initial skeleton

- docs/architecture.md: native rewrite plan (5 services + control plane,
  Active-Active cluster like nmg, Floating-IP for HTTP ingress)
- cmd/edgeguard-{api,scheduler,ctl}: minimal Gin + CLI stubs
- packaging/debian/edgeguard-{api,ui,meta}: control + maintainer scripts
- deploy/systemd/edgeguard-api.service + edgeguard-scheduler.service
  with hardening defaults
- Makefile: build / cross-compile (amd64+arm64) / deb / publish targets
- scripts/install.sh + scripts/apt-repo/build-package.sh stubs
This commit is contained in:
Felix Netzel
2026-05-08 18:45:41 +02:00
commit 0ceab4c814
41 changed files with 1013 additions and 0 deletions

44
.gitignore vendored Normal file
View File

@@ -0,0 +1,44 @@
# ── Go ────────────────────────────────────────────────────────────────────
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
go.work
go.work.sum
# ── Build artifacts ───────────────────────────────────────────────────────
/build/
/dist/
/edgeguard-api
/edgeguard-scheduler
/edgeguard-ctl
# ── Env / secrets ─────────────────────────────────────────────────────────
.env
.env.*
!.env.example
# ── Claude Code ───────────────────────────────────────────────────────────
.claude/
# ── Editor / OS ───────────────────────────────────────────────────────────
.DS_Store
.idea/
.vscode/
*.swp
*.swo
# ── Debian packaging intermediates ────────────────────────────────────────
*.deb
*.buildinfo
*.changes
# ── mkdocs build output ───────────────────────────────────────────────────
docs-site/site/
# ── UI build output ───────────────────────────────────────────────────────
management-ui/dist/
management-ui/node_modules/

104
Makefile Normal file
View File

@@ -0,0 +1,104 @@
# EdgeGuard — Build-System.
# Cross-Compile für Debian 13 + Ubuntu 24.04 auf amd64 und arm64.
# CGO_ENABLED=0 (statische Binaries, keine libre2-/CGO-Abhängigkeit in v1).
GO ?= $(shell which go || echo /usr/local/go/bin/go)
MODULE := git.netcell-it.de/projekte/edgeguard-native
BINARIES := edgeguard-api edgeguard-scheduler edgeguard-ctl
VERSION := $(shell cat VERSION 2>/dev/null || echo 0.0.1-dev)
LDFLAGS := -s -w -X main.version=$(VERSION)
GOFLAGS := -trimpath -mod=readonly
export CGO_ENABLED ?= 0
.PHONY: all help build test lint tidy clean ui \
build-linux-amd64 build-linux-arm64 \
deb deb-amd64 deb-arm64 \
publish publish-amd64 publish-arm64
all: build
help:
@echo "EdgeGuard build targets:"
@echo " build Build all binaries for the host architecture (build/host/)"
@echo " build-linux-amd64 Cross-compile all binaries for linux/amd64 (build/amd64/)"
@echo " build-linux-arm64 Cross-compile all binaries for linux/arm64 (build/arm64/)"
@echo " test go test ./..."
@echo " lint go vet + staticcheck (if installed)"
@echo " tidy go mod tidy"
@echo " ui Build management-ui (vite)"
@echo " deb-amd64 Cross-compile + build edgeguard_<ver>_amd64.deb"
@echo " deb-arm64 Cross-compile + build edgeguard_<ver>_arm64.deb"
@echo " deb Build both amd64 and arm64 .deb packages"
@echo " publish-amd64 Build amd64 deb AND upload to Gitea"
@echo " publish-arm64 Same for arm64"
@echo " publish publish-amd64 + publish-arm64"
@echo " clean Remove build artifacts"
build:
@mkdir -p build/host
@for bin in $(BINARIES); do \
echo " -> build/host/$$bin"; \
$(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' \
-o build/host/$$bin ./cmd/$$bin || exit 1; \
done
build-linux-amd64:
@mkdir -p build/amd64
@for bin in $(BINARIES); do \
echo " -> build/amd64/$$bin"; \
GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' \
-o build/amd64/$$bin ./cmd/$$bin || exit 1; \
done
build-linux-arm64:
@mkdir -p build/arm64
@for bin in $(BINARIES); do \
echo " -> build/arm64/$$bin"; \
GOOS=linux GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' \
-o build/arm64/$$bin ./cmd/$$bin || exit 1; \
done
test:
$(GO) test $(GOFLAGS) ./...
lint:
$(GO) vet ./...
@command -v staticcheck >/dev/null && staticcheck ./... || echo "staticcheck not installed, skipping"
tidy:
$(GO) mod tidy
ui:
@echo " -> management-ui (vite build, version $(VERSION))"
@cd management-ui && npm run build
deb-amd64: build-linux-amd64
@./scripts/apt-repo/build-package.sh amd64 $(VERSION)
deb-arm64: build-linux-arm64
@./scripts/apt-repo/build-package.sh arm64 $(VERSION)
deb: deb-amd64 deb-arm64
GITEA_DEB_URL := https://git.netcell-it.de/api/packages/projekte/debian/pool/trixie/main/upload
publish-amd64: deb-amd64
@TOK="$$(cat $$HOME/.gitea-token | tr -d '\n')"; \
if [ -z "$$TOK" ]; then echo "publish: ~/.gitea-token is empty"; exit 1; fi; \
echo " -> publish edgeguard-api_$(VERSION)_amd64.deb"; \
curl -sS -H "Authorization: token $$TOK" \
--upload-file build/deb/edgeguard-api_$(VERSION)_amd64.deb \
$(GITEA_DEB_URL)
publish-arm64: deb-arm64
@TOK="$$(cat $$HOME/.gitea-token | tr -d '\n')"; \
if [ -z "$$TOK" ]; then echo "publish: ~/.gitea-token is empty"; exit 1; fi; \
echo " -> publish edgeguard-api_$(VERSION)_arm64.deb"; \
curl -sS -H "Authorization: token $$TOK" \
--upload-file build/deb/edgeguard-api_$(VERSION)_arm64.deb \
$(GITEA_DEB_URL)
publish: publish-amd64 publish-arm64
clean:
rm -rf build/

35
README.md Normal file
View File

@@ -0,0 +1,35 @@
# EdgeGuard
Native Reverse-Proxy / Loadbalancer / Forward-Proxy / VPN / Firewall — als signiertes `.deb` für Debian 13 + Ubuntu 24.04, amd64 + arm64.
> Status: **v0.x — Neufassung des bisherigen Docker-Stacks**, parallel zum Bestand `proxy-lb-waf`.
## Installation
```
curl -fsSL https://get.edgeguard.netcell-it.de | sudo bash
```
**Unterstützte Plattformen:** Debian 13 (Trixie), Ubuntu 24.04 LTS (Noble) — amd64 + arm64.
## Architektur in Kürze
- **Daten-Services (v1):** HAProxy, Angie, Squid, WireGuard, nftables — alle nativ via APT, Configs aus PostgreSQL generiert.
- **Control-Plane:** `edgeguard-api` (Go/Gin), `management-ui` (React/AntD), PostgreSQL 16, KeyDB Active-Active.
- **Cluster:** N symmetrische Peers, KeyDB AA für Shared State, PG Streaming Replication, Floating-IP des Hosters statt VRRP.
- **Auslieferung:** signierte `.deb`, Update via `apt`. Update-Trigger via UI/API.
Volle Architektur: [`docs/architecture.md`](docs/architecture.md).
## Build
```
make build # Host-Architektur
make deb # amd64 + arm64 .deb
make publish # deb + Upload Gitea Package Registry
```
## Repo
- **Lokal:** `/var/www/edgeguard-native`
- **Gitea:** `https://git.netcell-it.de/projekte/edgeguard-native`

1
VERSION Normal file
View File

@@ -0,0 +1 @@
0.0.1-dev

31
cmd/edgeguard-api/main.go Normal file
View File

@@ -0,0 +1,31 @@
package main
import (
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
)
var version = "0.0.1-dev"
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Recovery())
r.GET("/api/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok", "version": version})
})
addr := os.Getenv("EDGEGUARD_API_ADDR")
if addr == "" {
addr = "127.0.0.1:9443"
}
log.Printf("edgeguard-api %s listening on %s", version, addr)
if err := r.Run(addr); err != nil {
log.Fatalf("edgeguard-api: %v", err)
}
}

40
cmd/edgeguard-ctl/main.go Normal file
View File

@@ -0,0 +1,40 @@
package main
import (
"fmt"
"os"
)
var version = "0.0.1-dev"
const usage = `edgeguard-ctl — EdgeGuard CLI
Usage:
edgeguard-ctl <command> [args]
Commands:
version Print version
initdb Initialise PostgreSQL database and user (idempotent)
migrate up Apply pending migrations
migrate down Roll back last migration (dev only)
cluster-join Join an existing cluster (--from URL --token TOKEN)
cluster-leave Leave the cluster cleanly
promote Promote this node's PG to primary
dump-config Print effective config to stdout
`
func main() {
if len(os.Args) < 2 {
fmt.Fprint(os.Stderr, usage)
os.Exit(2)
}
switch os.Args[1] {
case "version":
fmt.Println(version)
case "-h", "--help", "help":
fmt.Print(usage)
default:
fmt.Fprintf(os.Stderr, "edgeguard-ctl: command %q not yet implemented\n", os.Args[1])
os.Exit(2)
}
}

View File

@@ -0,0 +1,15 @@
package main
import (
"log"
"time"
)
var version = "0.0.1-dev"
func main() {
log.Printf("edgeguard-scheduler %s starting", version)
for {
time.Sleep(60 * time.Second)
}
}

0
deploy/angie/.gitkeep Normal file
View File

0
deploy/haproxy/.gitkeep Normal file
View File

0
deploy/nftables/.gitkeep Normal file
View File

0
deploy/squid/.gitkeep Normal file
View File

View File

@@ -0,0 +1,31 @@
[Unit]
Description=EdgeGuard Management API
Documentation=https://git.netcell-it.de/projekte/edgeguard-native
After=network-online.target postgresql.service keydb-server.service
Wants=network-online.target keydb-server.service
Requires=postgresql.service
[Service]
Type=simple
User=edgeguard
Group=edgeguard
ExecStart=/usr/bin/edgeguard-api
Restart=on-failure
RestartSec=5
# Hardening — API needs to shell out to `sudo systemctl reload haproxy/angie/squid`
# after writing configs. Sandboxing stays strict around fs/net.
NoNewPrivileges=false
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=/etc/edgeguard /var/lib/edgeguard /var/log/edgeguard
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,28 @@
[Unit]
Description=EdgeGuard Scheduler (cron-like jobs)
Documentation=https://git.netcell-it.de/projekte/edgeguard-native
After=edgeguard-api.service
Requires=edgeguard-api.service
[Service]
Type=simple
User=edgeguard
Group=edgeguard
ExecStart=/usr/bin/edgeguard-scheduler
Restart=on-failure
RestartSec=10
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
[Install]
WantedBy=multi-user.target

384
docs/architecture.md Normal file
View File

@@ -0,0 +1,384 @@
# 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, Angie, Squid, WireGuard, 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` |
| **Angie** | Reverse-Proxy, vHost-Routing, ACME-Webroot | eigenes APT-Repo (`angie`) | aus PG generiert, `systemctl reload angie` |
| **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` |
| **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/`, Angie 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/
│ ├── 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
│ ├── angie/ # Angie-Config-Generator (vHosts, Upstreams, ACME)
│ ├── squid/ # Squid-Config-Generator (squid.conf + squid.d/*)
│ ├── wireguard/ # WireGuard-Config-Generator (wg-quick + wg syncconf)
│ ├── 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
│ ├── angie/ # nginx.conf.tpl, sni-map.tpl
│ ├── squid/ # squid.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
├── migrations/ # SQL-Migrations (goose-Format)
├── 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`, `angie`, `haproxy`, `squid`, `wireguard-tools`, `nftables`, `certbot` |
| `edgeguard-ui` | all | `/usr/share/edgeguard/ui/` (statische Build-Artefakte), Angie-Site | `edgeguard-api (= ${binary:Version})`, `angie` |
| `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.
**Angie-Herkunft:** Eigenes APT-Repo bei `angie.software``edgeguard-api` `Depends: angie`. Im `install.sh` wird das Angie-Repo zusätzlich zu unserem hinzugefügt.
**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)
├── angie/ # vHosts + sni-map (generiert)
├── squid/ # squid.conf-Fragmente
├── wireguard/ # wg0.conf etc. (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/angie/squid/wireguard/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, Angie, Squid, WireGuard via `wg-quick@.service`, 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). Angie 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 `migrations/`). **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.
---
## 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. |
| **Angie** | 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 |
| **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 (~12s 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/Angie/Squid/WireGuard) 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`
- Angie-Repo-Key (für `angie`-Paket)
5. **APT-Sources:** `/etc/apt/sources.list.d/netcell-edgeguard.list` + Angie-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 Angie-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 Angie-/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.
- **Angie-Repo-Verfügbarkeit** für arm64 prüfen.
- **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.

37
go.mod Normal file
View File

@@ -0,0 +1,37 @@
module git.netcell-it.de/projekte/edgeguard-native
go 1.25.0
require github.com/gin-gonic/gin v1.10.0
require (
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/net v0.50.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

100
go.sum Normal file
View File

@@ -0,0 +1,100 @@
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

0
internal/angie/.gitkeep Normal file
View File

View File

0
internal/config/.gitkeep Normal file
View File

View File

View File

View File

View File

View File

0
internal/models/.gitkeep Normal file
View File

0
internal/proxy/.gitkeep Normal file
View File

View File

0
internal/squid/.gitkeep Normal file
View File

View File

View File

0
migrations/.gitkeep Normal file
View File

View File

@@ -0,0 +1 @@
/etc/edgeguard/edgeguard.yaml

View File

@@ -0,0 +1,18 @@
Package: edgeguard-api
Version: __VERSION__
Architecture: __ARCH__
Maintainer: NetCell IT <support@netcell-it.de>
Homepage: https://edgeguard.netcell-it.de
Description: EdgeGuard — native Reverse-Proxy / LB / Forward-Proxy / VPN / Firewall
EdgeGuard is a native Debian/Ubuntu edge gateway combining HAProxy,
Angie (nginx-fork), Squid, WireGuard and nftables, configured from
a PostgreSQL single-source-of-truth via a Go management API.
Deployable as a cluster of symmetric peers (KeyDB Active-Active +
PG Streaming Replication + provider Floating-IP for HTTP ingress).
.
This package ships the management API, scheduler and CLI.
Depends: postgresql-16 | postgresql-17, edgeguard-keydb (>= 6.3.4-edgeguard1), angie, haproxy (>= 2.8), squid, wireguard-tools, nftables, certbot, sudo, adduser, systemd, ca-certificates
Recommends: apparmor, fail2ban
Section: admin
Priority: optional
Installed-Size: 0

View File

@@ -0,0 +1,46 @@
#!/bin/bash
# postinst for edgeguard-api — creates system user, filesystem layout,
# enables systemd units. DB init + migrations run lazily on first start
# of edgeguard-api.
set -e
export LC_ALL=C
export LANG=C
EG_USER="edgeguard"
EG_HOME="/var/lib/edgeguard"
case "$1" in
configure)
# ── System user ──────────────────────────────────────────────
if ! getent passwd "$EG_USER" >/dev/null; then
adduser --system --group --home "$EG_HOME" \
--shell /usr/sbin/nologin --no-create-home \
--gecos "EdgeGuard daemon" "$EG_USER"
fi
# ── Directories ──────────────────────────────────────────────
for d in /etc/edgeguard /var/lib/edgeguard /var/log/edgeguard \
/etc/edgeguard/haproxy /etc/edgeguard/angie \
/etc/edgeguard/squid /etc/edgeguard/wireguard \
/etc/edgeguard/nftables.d /etc/edgeguard/tls; do
install -d -m 0750 -o "$EG_USER" -g "$EG_USER" "$d"
done
# ── systemd ──────────────────────────────────────────────────
systemctl daemon-reload
systemctl enable --now edgeguard-api.service edgeguard-scheduler.service || true
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

View File

@@ -0,0 +1,24 @@
#!/bin/bash
set -e
case "$1" in
purge)
# Only on purge: remove user, configs, state.
if getent passwd edgeguard >/dev/null; then
deluser --quiet edgeguard >/dev/null 2>&1 || true
fi
rm -rf /etc/edgeguard /var/lib/edgeguard /var/log/edgeguard
;;
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

View File

@@ -0,0 +1,21 @@
#!/bin/bash
set -e
case "$1" in
remove|upgrade|deconfigure)
systemctl stop edgeguard-api.service edgeguard-scheduler.service || true
systemctl disable edgeguard-api.service edgeguard-scheduler.service || true
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

View File

@@ -0,0 +1,14 @@
Package: edgeguard
Version: __VERSION__
Architecture: all
Maintainer: NetCell IT <support@netcell-it.de>
Homepage: https://edgeguard.netcell-it.de
Description: EdgeGuard — meta package
Pulls the full EdgeGuard stack: management API, UI, configured
third-party services (HAProxy, Angie, Squid, WireGuard, nftables).
.
Install this package to get a complete EdgeGuard node.
Depends: edgeguard-api (= ${binary:Version}), edgeguard-ui (= ${binary:Version})
Section: admin
Priority: optional
Installed-Size: 0

View File

@@ -0,0 +1,12 @@
Package: edgeguard-ui
Version: __VERSION__
Architecture: all
Maintainer: NetCell IT <support@netcell-it.de>
Homepage: https://edgeguard.netcell-it.de
Description: EdgeGuard — management UI (static React build)
React 19 + Ant Design 6 single-page admin UI for EdgeGuard.
Served by the Angie reverse proxy bundled in edgeguard-api.
Depends: edgeguard-api (= ${binary:Version}), angie
Section: admin
Priority: optional
Installed-Size: 0

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Build .deb packages for EdgeGuard.
# Usage: build-package.sh <amd64|arm64> <version>
# Output: build/deb/edgeguard-{api,ui,meta}_<version>_<arch>.deb
#
# TODO — Stub. Wird mit Task #3 (Spike-Build) implementiert.
set -euo pipefail
ARCH="${1:?arch required}"
VERSION="${2:?version required}"
echo "build-package.sh stub — would build edgeguard-{api,ui,meta}_${VERSION}_${ARCH}.deb"

17
scripts/install.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# ============================================================================
# EdgeGuard — Bootstrap Installer (One-Liner)
# ============================================================================
# Usage:
# curl -fsSL https://get.edgeguard.netcell-it.de | sudo bash
# curl -fsSL https://get.edgeguard.netcell-it.de | sudo bash -s -- \
# --join https://<existing-node-fqdn> --token <cluster-join-token>
#
# Platform: Debian 13 (Trixie) or Ubuntu 24.04 LTS (Noble), amd64 + arm64.
# Idempotent — safe to re-run.
# ============================================================================
set -euo pipefail
# ─── TODO — Stub. Wird in Task #4 implementiert. ────────────────────────────
echo "EdgeGuard installer stub — full install.sh follows in Task #4."
exit 0