Files

6.2 KiB

ProxUI

Multi-Tenant-Konsole fuer Proxmox auf Basis von Go, Supabase Postgres/Auth, Redis/asynq und React.

Architektur

  • backend/: HTTP-API, Auth/JWT-Validierung, RBAC, DB-Zugriff und Proxmox-Orchestrierung
  • worker/: asynchrone Jobs fuer Proxmox-Tasks, Reconciliation und Cleanup
  • console-proxy/: Websocket-Proxy fuer noVNC/xterm.js ohne direkte Proxmox-Verbindung im Browser
  • platform/: gemeinsame Go-Bausteine fuer Konfiguration, Logging und spaetere Querschnittsfunktionen
  • frontend/: React/TypeScript/Vite-App fuer Kunden- und Admin-Workflows
  • migrations/: versionierte SQL-Migrationen
  • deploy/: lokale und spaetere Deployment-Artefakte

Lokales Setup

  1. Go >= 1.22 installieren.
  2. Node.js >= 20 und npm installieren.
  3. Docker Desktop oder kompatible Docker Engine installieren.
  4. .env.example nach .env kopieren und lokale Werte setzen.
  5. Abhaengigkeiten installieren: npm install --prefix frontend.
  6. Go-Abhaengigkeiten installieren: go work sync.
  7. Lokale Infrastruktur starten: make dev.
  8. Migrationen ausfuehren: make migrate.
  9. Backend starten: go run ./backend/cmd/api.
  10. Console-Proxy starten: go run ./console-proxy/cmd/console-proxy.
  11. Frontend starten: npm run dev --prefix frontend.

Supabase self-hosted liegt unter deploy/supabase/. Die lokale deploy/supabase/.env wird aus der offiziellen Vorlage erzeugt und nicht committed. Fuer App-.env die Werte POSTGRES_PASSWORD, ANON_KEY und SERVICE_ROLE_KEY aus deploy/supabase/.env uebernehmen.

Migrationen nutzen MIGRATE_DATABASE_URL, falls gesetzt. Andernfalls wird DATABASE_DIRECT_URL aus .env oder eine lokale Supavisor-URL aus deploy/supabase/.env verwendet.

Das Backend validiert Supabase-JWTs ueber SUPABASE_JWKS_URL und SUPABASE_ISSUER. Fuer das lokale Self-Hosted-Setup mit leerem JWKS wird zusaetzlich SUPABASE_JWT_SECRET als HS256-Fallback genutzt. Beim ersten authentifizierten Request synchronisiert das Backend den Supabase-User lazy nach public.profiles.

Cluster-Tokens werden mit AES-256-GCM verschluesselt. MASTER_KEY_BASE64 muss ein base64-kodierter 32-Byte-Key sein, zum Beispiel erzeugt mit openssl rand -base64 32. Ohne gueltigen Master-Key bricht der Backend-Start ab.

Das Cluster-Repository speichert Proxmox-Token-Secrets nur als Ciphertext in public.clusters.encrypted_token. Entschluesselte Tokens bleiben interne Runtime-Daten und werden nicht in API-DTOs dokumentiert.

Der Proxmox-Client nutzt HTTPS mit normaler Zertifikatsvalidierung plus SHA-256-Fingerprint-Pinning gegen clusters.tls_fingerprint. Proxmox-Token werden nur als PVEAPIToken=<token_id>=<secret> Header an Proxmox gesendet.

Interne Cluster-Admin-Routen unter /internal/clusters sind nicht tenant-gebunden. Sie erfordern den Header X-ProxUI-Operator-Token mit OPERATOR_TOKEN und die isolierte Rolle operator; Responses enthalten nie token_secret.

Der Worker nutzt asynq gegen REDIS_ADDR, pingt beim Start dieselbe Supabase-DB ueber DATABASE_URL, entschluesselt Cluster-Credentials mit MASTER_KEY_BASE64 und nutzt den gemeinsamen Proxmox-Client aus platform/proxmox fuer UPID-Polls und Reconciliation.

Lokale Dienste:

  • Supabase API Gateway: http://localhost:8000
  • Supabase Studio: http://localhost:8000/project/default
  • Supavisor Session Pooler: localhost:5432
  • Supavisor Transaction Pooler: localhost:6543

Aktuelle Targets:

  • make test: Go-Tests
  • make build: Go-Builds
  • make frontend-build: Frontend-Production-Build
  • make lint: Go Vet und Frontend-ESLint
  • make verify: Lint, Tests und Builds
  • make dev-down: Supabase-Stack stoppen
  • make dev-logs: Supabase-Logs verfolgen
  • make migrate: Migrationen auf den aktuellen Stand bringen
  • make migrate-down: letzte Migration zurueckrollen
  • make migrate-version: aktuelle Migrationsversion anzeigen

Worker-Jobs:

  • proxui.dummy: Dummy-Job mit Payload {"message":"..."} fuer Smoke-Tests der asynq-Verarbeitung
  • proxmox.task.poll: Pollt einen Proxmox-UPID ueber den gespeicherten Cluster, setzt VM-Status auf Erfolgs- oder Fehlerstatus und schreibt Audit-Metadaten.
  • proxmox.reconcile.all: Laeuft alle 5 Minuten, prueft aktive Cluster gegen bekannte VMs und schreibt Drift als Audit-Event vm.reconcile.drift.

Backend-Endpunkte:

  • GET /healthz: oeffentlicher Healthcheck
  • GET /me: geschuetzt, synchronisiert profiles und gibt den authentifizierten Principal aus dem JWT zurueck
  • GET /tenants/{tenantID}/membership: geschuetzt, synchronisiert profiles, prueft Tenant-Mitgliedschaft und gibt Rolle/Tenant zurueck
  • GET /projects/{projectID}/vms: geschuetzt, listet nur VMs aus Projekten, deren Tenant der Nutzer angehoert
  • GET /vms/{vmID}: geschuetzt, gibt VM-Details nur bei Tenant-Mitgliedschaft zurueck
  • POST /vms/{vmID}/start: geschuetzt, prueft vm.power, ruft Proxmox auf und queued UPID-Polling
  • POST /vms/{vmID}/stop: geschuetzt, prueft vm.power, ruft Proxmox auf und queued UPID-Polling
  • POST /vms/{vmID}/reboot: geschuetzt, prueft vm.power, ruft Proxmox auf und queued UPID-Polling
  • POST /internal/clusters: intern, legt Cluster an und speichert Token verschluesselt
  • PUT /internal/clusters/{clusterID}: intern, aktualisiert Cluster und rotiert Token
  • PATCH /internal/clusters/{clusterID}/status: intern, setzt Cluster-Status

Tenant-gescoped Backend-Routen laufen ueber JWT-Auth, Profil-Sync, Membership-Resolver und deklarative RBAC-Pruefung.

Frontend-Prototyp:

  • Supabase Login/Registrierung ueber VITE_SUPABASE_URL und VITE_SUPABASE_ANON_KEY
  • Backend-Profilcheck ueber GET /me
  • Platzhalter-Ansichten fuer Projekte, VMs, SSH-Keys, Audit und Konsole

CI

Forgejo Actions laufen unter .forgejo/workflows/ci.yml.

  • verify: installiert Go/Node-Abhaengigkeiten und fuehrt make verify aus.
  • secret-scan: fuehrt zricethezav/gitleaks:v8.28.0 mit .gitleaks.toml aus. Die Konfiguration erlaubt nur dokumentierte Beispielwerte aus den offiziellen Supabase-Upstream-Dateien.

Sicherheitsregeln

  • Nur Backend, Worker und Console-Proxy sprechen mit Proxmox.
  • Proxmox-Tokens werden nie im Frontend sichtbar und nie unverschluesselt gespeichert.
  • Tenant-bezogene Queries muessen immer tenant-gefiltert sein.
  • Secrets gehoeren in .env oder einen Secret-Manager, nie ins Repo.