feat: umfangreiches UI+API-Polish (v1.1.36–1.1.42)
Backend: - Audit-Log: Search-Endpoint mit ILIKE-Filter (actor/action/subject/date) - NTP: /ntp/status via chronyc tracking (Stratum, Offset, Quelle) - System: /service-restart mit Allowlist (haproxy/squid/unbound/chrony/scheduler) - Domain-Response-Headers + Rate-Limit (Migration 0024) - Join-Tokens (Migration 0025), Cluster-mTLS, Aggregator-Fan-Out - apt-Service für Update-Banner (apt-get update + Versionsprüfung) - Backup-Retry mit exponential backoff (retry_apt 3×) - publish.sh fail-fast + cleanup-old.sh (max 10 Versionen) Frontend: - Audit-Log-Page (/audit) mit Filter + Pagination - ErrorBoundary an React-Root + Vite build-target festgenagelt (iOS 15+) - Storage-Schema-Stamp: auto-wipe bei Versions-Mismatch (blank-page-Fix) - EmptyState-Komponente überall ausgerollt - SSL: Aggregate-Karte (total/expiring/expired/errors) - Backups: Aggregate-Karte (letzter Backup/Größe/Fehlschläge 24h) + Backup-Now - NTP: Sync-Status-Karte (chronyc tracking live) - Domains: Backend-UP/DOWN-Chip aus HAProxy-Stats - Backends: HAProxy-Status-Spalte (UP/DEGRADED/DOWN) - Settings: Service-Neustart-Karte (haproxy/squid/unbound/chrony/scheduler) - Settings: Upgrade-Status-Card, Wartungsmodus, Auto-Update, Retention - Dashboard: Recent-Alerts, Cluster-Health, License-Chip, Onboarding-Hint - System-Regeln im Firewall als eigener Tab Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
"firewallLive": "Firewall-Log",
|
||||
"cluster": "Cluster",
|
||||
"logs": "Logs",
|
||||
"audit": "Audit-Log",
|
||||
"backups": "Backups",
|
||||
"diagnostics": "Diagnose",
|
||||
"alerts": "Alarme",
|
||||
@@ -44,7 +45,8 @@
|
||||
"addrObj": "Adress-Objekte",
|
||||
"addrGrp": "Adress-Gruppen",
|
||||
"services": "Services",
|
||||
"svcGrp": "Service-Gruppen"
|
||||
"svcGrp": "Service-Gruppen",
|
||||
"system": "System-Regeln"
|
||||
},
|
||||
"zone": {
|
||||
"name": "Name",
|
||||
@@ -55,31 +57,41 @@
|
||||
"namePattern": "Nur Kleinbuchstaben, Ziffern, _ und -; muss mit Buchstaben beginnen, max. 32 Zeichen.",
|
||||
"add": "Zone hinzufügen",
|
||||
"edit": "Zone bearbeiten",
|
||||
"deleteConfirm": "Zone {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "Zone {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine eigenen Firewall-Zonen.",
|
||||
"emptyDesc": "Zonen gruppieren Interfaces (lan, wan, dmz). Vordefinierte Zonen sind bereits da; eigene anlegen wenn du z. B. eine separate dmz-Zone oder eine wg-Zone fürs VPN brauchst."
|
||||
},
|
||||
"ao": {
|
||||
"name": "Name", "kind": "Typ", "value": "Wert", "description": "Beschreibung",
|
||||
"add": "Adress-Objekt hinzufügen", "edit": "Adress-Objekt bearbeiten",
|
||||
"deleteConfirm": "Adress-Objekt {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "Adress-Objekt {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine Adress-Objekte.",
|
||||
"emptyDesc": "Wiederverwendbare benannte IPs/Netze/Ranges für Firewall- und NAT-Regeln (z. B. office-net = 10.0.0.0/24, mailbox-1 = 10.0.1.42)."
|
||||
},
|
||||
"ag": {
|
||||
"name": "Name", "members": "Mitglieder", "description": "Beschreibung",
|
||||
"add": "Adress-Gruppe hinzufügen", "edit": "Adress-Gruppe bearbeiten",
|
||||
"selectMembers": "Adress-Objekte wählen",
|
||||
"deleteConfirm": "Adress-Gruppe {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "Adress-Gruppe {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine Adress-Gruppen.",
|
||||
"emptyDesc": "Bündele mehrere Adress-Objekte zu einer Gruppe (z. B. office-locations = [hq-net, branch-1-net, branch-2-net]) — Regeln müssen dann nur eine Gruppe referenzieren."
|
||||
},
|
||||
"svc": {
|
||||
"name": "Name", "proto": "Protokoll", "ports": "Ports",
|
||||
"portStart": "Port (Start)", "portEnd": "Port (Ende)",
|
||||
"description": "Beschreibung", "builtinHint": "Vordefiniert — nicht editierbar",
|
||||
"add": "Service hinzufügen", "edit": "Service bearbeiten",
|
||||
"deleteConfirm": "Service {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "Service {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine eigenen Services.",
|
||||
"emptyDesc": "Vordefinierte (HTTP, HTTPS, SSH, …) sind bereits da. Eigene Services für app-spezifische Ports (z. B. mailcow-imaps tcp/993) erleichtern Regeln deutlich."
|
||||
},
|
||||
"sg": {
|
||||
"name": "Name", "members": "Mitglieder", "description": "Beschreibung",
|
||||
"add": "Service-Gruppe hinzufügen", "edit": "Service-Gruppe bearbeiten",
|
||||
"selectMembers": "Services wählen",
|
||||
"deleteConfirm": "Service-Gruppe {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "Service-Gruppe {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine Service-Gruppen.",
|
||||
"emptyDesc": "Bündele mehrere Services zu einer Gruppe (z. B. web-stack = [HTTP, HTTPS, HTTP/3]) — eine Regel mit der Gruppe ersetzt drei Regeln pro Service."
|
||||
},
|
||||
"rule": {
|
||||
"name": "Name", "priority": "Priority", "enabled": "Aktiv", "log": "Logging",
|
||||
@@ -90,7 +102,9 @@
|
||||
"serviceKind": "Service-Typ", "serviceGroup": "Service-Gruppe",
|
||||
"comment": "Kommentar",
|
||||
"add": "Regel hinzufügen", "edit": "Regel bearbeiten",
|
||||
"deleteConfirm": "Diese Regel wirklich löschen?"
|
||||
"deleteConfirm": "Diese Regel wirklich löschen?",
|
||||
"emptyTitle": "Noch keine eigenen Firewall-Regeln.",
|
||||
"emptyDesc": "Die System-Regeln oben halten SSH (rate-limited), HTTPS :443 und Mgmt-UI :3443 immer offen (Anti-Lockout). Eigene Regeln für app-spezifische Inbound-Ports oder zonenübergreifende Forwards anlegen."
|
||||
},
|
||||
"nat": {
|
||||
"name": "Name", "priority": "Priority", "kind": "Typ", "enabled": "Aktiv",
|
||||
@@ -102,7 +116,9 @@
|
||||
"targetAddr": "Ziel-Adresse", "targetPortStart": "Ziel-Port (Start)", "targetPortEnd": "Ziel-Port (Ende)",
|
||||
"comment": "Kommentar",
|
||||
"add": "NAT-Regel hinzufügen", "edit": "NAT-Regel bearbeiten",
|
||||
"deleteConfirm": "Diese NAT-Regel wirklich löschen?"
|
||||
"deleteConfirm": "Diese NAT-Regel wirklich löschen?",
|
||||
"emptyTitle": "Noch keine NAT-Regeln.",
|
||||
"emptyDesc": "DNAT (z. B. extern :2030 → intern 10.10.20.12:22 für SSH zu einem internen Host) oder SNAT/MASQUERADE (Internet-Zugang für ein internes Subnetz über die Box-IP)."
|
||||
},
|
||||
"sys": {
|
||||
"title": "System-Regeln (immer aktiv)",
|
||||
@@ -125,6 +141,8 @@
|
||||
"systemDiscovered": "System-Interfaces (read-only)",
|
||||
"addInterface": "Interface hinzufügen",
|
||||
"editInterface": "Interface bearbeiten",
|
||||
"emptyTitle": "Noch keine verwalteten Interfaces.",
|
||||
"emptyDesc": "System-Interfaces (siehe oben) werden read-only erkannt. Verwaltete Interfaces sind das was EdgeGuard selbst anlegt — VLANs, Bridges, Bond, GRE-Tunnels — und in /etc/network/interfaces.d rendert.",
|
||||
"name": "Name",
|
||||
"type": "Typ",
|
||||
"parent": "Parent-Interface",
|
||||
@@ -152,6 +170,8 @@
|
||||
"managedTitle": "Verwaltete Adressen",
|
||||
"family": "Familie",
|
||||
"addAddress": "Adresse hinzufügen",
|
||||
"emptyTitle": "Noch keine eigenen IP-Adressen.",
|
||||
"emptyDesc": "Lege deine erste IP an — Floating-VIPs für HA-Failover oder zusätzliche Listen-Adressen für HAProxy/Squid/Unbound. Box-eigene Distro-IPs werden oben unter \"Erkannte IPs\" gelesen.",
|
||||
"editAddress": "Adresse bearbeiten",
|
||||
"interface": "Interface",
|
||||
"selectInterface": "Interface wählen",
|
||||
@@ -192,12 +212,19 @@
|
||||
"setup": {
|
||||
"title": "Erst-Einrichtung",
|
||||
"intro": "Lege den Admin-Account an, gib die öffentliche FQDN an und – optional – einen Lizenzschlüssel. Ohne Lizenz startet eine 30-Tage-Trial.",
|
||||
"preflightTitle": "Vor dem Klick auf \"Setup abschließen\"",
|
||||
"preflightDesc": "Die FQDN muss bereits per DNS auf diese Box zeigen (A/AAAA-Record). Ohne DNS-Auflösung scheitert die spätere ACME-HTTP-01-Challenge — dein Browser-URL muss schon jetzt diese FQDN sein, sonst klemmt's spätestens beim ersten Let's-Encrypt-Issue.",
|
||||
"adminEmail": "Admin-E-Mail",
|
||||
"adminEmailHint": "Login-Identifier für die Management-UI. Wird NICHT für ausgehende Mails benutzt (das ist die ACME-E-Mail unten bzw. die SMTP-Settings im Alerts-Channel).",
|
||||
"adminPassword": "Admin-Passwort",
|
||||
"passwordRule": "Mindestens 12 Zeichen.",
|
||||
"fqdn": "Öffentliche FQDN",
|
||||
"fqdnHint": "Vollqualifizierter Hostname dieser Box (z. B. eg.example.com). Wird Subject-CN des Self-Signed-Bootstrap-Cert UND wandert in das ACME-Cert sobald Let's Encrypt ausgestellt hat. Muss per DNS auf die Public-IP zeigen.",
|
||||
"fqdnInvalid": "Sieht nicht wie eine gültige FQDN aus (mindestens label.tld).",
|
||||
"acmeEmail": "ACME-/Let's-Encrypt-E-Mail",
|
||||
"acmeEmailHint": "Wird Let's Encrypt als Account-Contact mitgegeben (Expiry-Warnungen + Compliance-Mails von LE). Kann gleich der Admin-E-Mail sein, muss aber nicht.",
|
||||
"licenseKey": "Lizenzschlüssel (optional)",
|
||||
"licenseKeyHint": "Wenn vorhanden: 30-Tage-Trial wird übersprungen, Features unmittelbar freigeschaltet. Kann auch später unter License nachgereicht werden.",
|
||||
"submit": "Setup abschließen",
|
||||
"successTitle": "Setup abgeschlossen",
|
||||
"successHint": "Du wirst zur Anmeldung weitergeleitet."
|
||||
@@ -211,14 +238,64 @@
|
||||
"intro": "Verwalte FQDNs, die HAProxy terminiert. Optionales Primary-Backend als Catch-all; Pfad-Routing via Routing-Regeln.",
|
||||
"addDomain": "Domain hinzufügen",
|
||||
"editDomain": "Domain bearbeiten",
|
||||
"emptyTitle": "Noch keine Domains.",
|
||||
"emptyDesc": "Lege deine erste Domain an — HAProxy terminiert dann TLS für diesen Hostnamen und routet an das gewählte Backend.",
|
||||
"name": "Name",
|
||||
"active": "Aktiv",
|
||||
"primaryBackend": "Primary-Backend",
|
||||
"primaryBackendHint": "Catch-all-Backend für Requests, die kein Routing-Regel-Match haben. Optional — leer lassen, wenn alles über Routing-Regeln läuft.",
|
||||
"selectBackend": "Backend wählen",
|
||||
"noBackend": "kein Backend",
|
||||
"quickBackendBtn": "+ neu",
|
||||
"quickBackendBtnHint": "Backend + ersten Upstream-Server in einem Klick anlegen — spart den Umweg über die Backends-Seite.",
|
||||
"quickBackendTitle": "Backend schnell anlegen",
|
||||
"quickBackendName": "Backend-Name",
|
||||
"quickBackendScheme": "Schema",
|
||||
"quickBackendAddress": "Server-Adresse (Erster Upstream)",
|
||||
"quickBackendPort": "Port",
|
||||
"quickBackendCreated": "Backend + Server angelegt und ausgewählt.",
|
||||
"quickBackendFailed": "Quick-Backend-Anlage fehlgeschlagen",
|
||||
"httpToHttps": "HTTP→HTTPS",
|
||||
"hsts": "HSTS",
|
||||
"tlsCert": "TLS-Cert",
|
||||
"tlsCertValid": "gültig",
|
||||
"tlsCertExpiring": "noch {{days}}d",
|
||||
"tlsCertExpired": "abgelaufen",
|
||||
"tlsCertError": "Fehler",
|
||||
"tlsCertNone": "fehlt",
|
||||
"tlsCertNoneHint": "Kein eigener TLS-Cert für diese Domain — HAProxy serviert das Bootstrap-Self-Signed-Cert. Im SSL-Tab issuen.",
|
||||
"hstsMaxAge": "HSTS max-age (Sek.)",
|
||||
"hstsMaxAgeHint": "Wie lange Browser den HTTPS-Zwang cachen. Empfehlung 31536000 (1 Jahr).",
|
||||
"hstsSubdomains": "includeSubDomains",
|
||||
"hstsSubdomainsHint": "Erstreckt HSTS auf alle Sub-Domains. Nur aktivieren wenn alle Subs ausschließlich HTTPS sprechen.",
|
||||
"hstsPreload": "preload",
|
||||
"hstsPreloadHint": "Setzt den preload-Flag damit die Domain in die hstspreload.org-Liste aufgenommen werden kann. Voraussetzung: max-age ≥ 31536000 + includeSubDomains an.",
|
||||
"maintenance": "Wartungs-Modus",
|
||||
"maintenanceHint": "An: alle Requests auf diese Domain bekommen direkt 503 von HAProxy. Backends werden nicht kontaktiert.",
|
||||
"maintenanceMessage": "Wartungs-Meldung",
|
||||
"maintenanceMessagePlaceholder": "Service vorübergehend nicht verfügbar.",
|
||||
"wwwRedirect": "www-Redirect",
|
||||
"wwwRedirectHint": "Kanonisiert die Domain. „nach naked\": Name=example.com → www.example.com leitet auf example.com. „nach www\": Name=www.example.com → example.com leitet auf www.example.com.",
|
||||
"wwwRedirectNone": "Kein Redirect",
|
||||
"wwwRedirectToNaked": "→ naked (ohne www)",
|
||||
"wwwRedirectToWWW": "→ www",
|
||||
"rateLimit": "Rate-Limit (pro Client-IP)",
|
||||
"rateLimitHint": "Max. Requests pro Sekunde je Client-IP. HAProxy zählt über ein 10-Sekunden-Fenster pro Stick-Table (max. 100k IPs). 0 = aus.",
|
||||
"maxBody": "Max. Request-Body",
|
||||
"maxBodyHint": "Cap auf Content-Length-Header. Größere Requests bekommen 413. Nicht erkannt: Chunked-Bodies (HAProxy bufferd nicht standardmäßig). 0 = aus.",
|
||||
"headersBtn": "Headers",
|
||||
"headersTitle": "Response-Headers — {{name}}",
|
||||
"headersHint": "Diese Header werden von HAProxy auf jede Response für diese Domain gesetzt (http-response set-header). Reihenfolge via Position.",
|
||||
"headersEmpty": "Noch keine Custom-Headers konfiguriert.",
|
||||
"addHeader": "Header hinzufügen",
|
||||
"editHeader": "Header bearbeiten",
|
||||
"headerName": "Name",
|
||||
"headerNameHint": "Nur Buchstaben, Zahlen, Bindestriche. Pro Domain case-insensitive eindeutig.",
|
||||
"headerNamePattern": "Nur a-z, A-Z, 0-9, '-'",
|
||||
"headerValue": "Wert",
|
||||
"headerPosition": "Position",
|
||||
"headerDeleteConfirm": "Header „{{name}}\" wirklich löschen?",
|
||||
"settingsSection": "HAProxy-Einstellungen",
|
||||
"notes": "Notizen",
|
||||
"actions": "Aktionen",
|
||||
"edit": "Bearbeiten",
|
||||
@@ -229,11 +306,14 @@
|
||||
"title": "Backends",
|
||||
"intro": "Upstream-Pools (Backend = N Server). HAProxy verteilt laut LB-Algorithmus; Health-Check-Pfad aktiviert HTTP-Probes alle 5s pro Server.",
|
||||
"addBackend": "Backend-Pool hinzufügen",
|
||||
"emptyTitle": "Noch keine Backend-Pools.",
|
||||
"emptyDesc": "Lege deinen ersten Pool an — definiere Upstream-Server (z. B. App-Server / Mailbox-Knoten) damit Domains darauf routen können.",
|
||||
"editBackend": "Backend-Pool bearbeiten",
|
||||
"name": "Name",
|
||||
"scheme": "Schema",
|
||||
"target": "Ziel",
|
||||
"healthCheck": "Health-Check-Pfad",
|
||||
"liveStatus": "HAProxy-Status",
|
||||
"active": "Aktiv",
|
||||
"usedBy": "Genutzt von",
|
||||
"noDomain": "keine Domain",
|
||||
@@ -271,6 +351,8 @@
|
||||
"title": "Routing-Regeln",
|
||||
"intro": "Pfad-Präfix → Backend-Mapping pro Domain. Niedrige Priority gewinnt; Catch-all per Domain.primary_backend.",
|
||||
"addRule": "Regel hinzufügen",
|
||||
"emptyTitle": "Noch keine Routing-Regeln.",
|
||||
"emptyDesc": "Pfad-spezifisches Routing — z. B. domain.tld/api → Backend A, domain.tld/* → Backend B. Optional. Ohne Regeln nutzt HAProxy die Primary-Backend-Auswahl der Domain.",
|
||||
"editRule": "Regel bearbeiten",
|
||||
"domain": "Domain",
|
||||
"pathPrefix": "Pfad-Präfix",
|
||||
@@ -313,8 +395,35 @@
|
||||
"configHash": "Config-Hash",
|
||||
"version": "Version",
|
||||
"lastSeen": "Last seen",
|
||||
"mgmtIp": "MGMT-IP"
|
||||
}
|
||||
"mgmtIp": "MGMT-IP",
|
||||
"load": "Load 1/5/15",
|
||||
"mem": "Memory",
|
||||
"disk": "Disk",
|
||||
"conntrack": "Conntrack",
|
||||
"uptime": "Uptime",
|
||||
"fetchMs": "Fetch"
|
||||
},
|
||||
"loadTitle": "Per-Node Resources (mTLS-Aggregator)",
|
||||
"loadEmpty": "Keine Node-Resources verfügbar — Agent-Listener nicht erreichbar?",
|
||||
"certCardTitle": "Cluster-TLS-Zertifikate",
|
||||
"certCALabel": "Cluster-CA",
|
||||
"certPeerLabel": "Peer-Cert (diese Node)",
|
||||
"certExpiry": "Läuft ab in",
|
||||
"renewSelfBtn": "Peer-Cert erneuern",
|
||||
"renewSelfConfirm": "Peer-Cert mit lokaler CA neu signieren (1 Jahr)? edgeguard-api Restart danach erforderlich.",
|
||||
"certRenewedRestartHint": "Cert erneuert — bitte sudo systemctl restart edgeguard-api ausführen.",
|
||||
"certRenewFailed": "Cert-Erneuerung fehlgeschlagen",
|
||||
"removePeerBtn": "Entfernen",
|
||||
"removePeerConfirmTitle": "Peer wirklich aus dem Cluster entfernen?",
|
||||
"removePeerConfirmDesc": "{{fqdn}} wird aus ha_nodes gelöscht. Firewall-Renderer entfernt seine IP aus dem peer_ipv4-Set. Auf der Peer-Seite läuft edgeguard-api weiter; manuell stoppen + cluster-tls löschen für vollständigen Decommission.",
|
||||
"removePeerOk": "Peer entfernt.",
|
||||
"removePeerFailed": "Peer-Entfernung fehlgeschlagen",
|
||||
"generateJoinToken": "Join-Token erzeugen",
|
||||
"joinTokenTitle": "Cluster-Join-Token",
|
||||
"joinTokenOneShot": "Einmalig anzeigen, einmalig nutzbar",
|
||||
"joinTokenOneShotDesc": "Token jetzt sicher übertragen — er erscheint nie wieder. Gültig bis {{expires}}. Beim Einlösen via cluster-join wird er server-seitig als verbraucht markiert.",
|
||||
"joinTokenFailed": "Token-Generierung fehlgeschlagen",
|
||||
"joinCmdLabel": "Auf dem neuen Node ausführen:"
|
||||
},
|
||||
"ssl": {
|
||||
"title": "SSL-Zertifikate",
|
||||
@@ -338,22 +447,112 @@
|
||||
"uploadButton": "Hochladen",
|
||||
"issueSuccess": "Zertifikat ausgestellt + installiert.",
|
||||
"uploadSuccess": "Zertifikat hochgeladen + installiert.",
|
||||
"renewBtn": "Renew",
|
||||
"renewConfirmTitle": "Zertifikat jetzt erneuern?",
|
||||
"renewConfirmDesc": "Triggert eine ACME-HTTP-01-Challenge für {{domain}}. Let's Encrypt hat Rate-Limits (50 Issues/Domain/Woche) — nicht öfter als nötig nutzen.",
|
||||
"renewSuccess": "Zertifikat erneuert + installiert.",
|
||||
"renewFailed": "Renewal fehlgeschlagen",
|
||||
"deleteConfirm": "Zertifikat für {{domain}} löschen? HAProxy fällt für diese Domain auf das Default-Cert zurück.",
|
||||
"installedTitle": "Installierte Zertifikate",
|
||||
"lastRenewed": "Zuletzt erneuert",
|
||||
"statTotal": "Zertifikate gesamt",
|
||||
"statExpiring": "< 30 Tage gültig",
|
||||
"statExpired": "Abgelaufen",
|
||||
"statErrors": "Mit Fehler",
|
||||
"relAgo": {
|
||||
"justNow": "gerade eben",
|
||||
"minutes": "vor {{n}} min",
|
||||
"hours": "vor {{n}} h",
|
||||
"days": "vor {{n}} Tagen"
|
||||
},
|
||||
"emptyTitle": "Noch keine Zertifikate installiert.",
|
||||
"emptyDesc": "Nutze die Tabs oben — Let's Encrypt issued vollautomatisch per HTTP-01-Challenge, oder lade ein eigenes PEM hoch. Bis dahin liefert HAProxy das Bootstrap-Self-Signed-Cert für alle Domains.",
|
||||
"certPem": "Zertifikat (PEM)",
|
||||
"chainPem": "Chain (PEM, optional)",
|
||||
"keyPem": "Private Key (PEM)"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Einstellungen",
|
||||
"intro": "System-Information und Setup-Status. Bearbeitbare Werte folgen in einem späteren Release.",
|
||||
"intro": "System-Information, Setup-Status und Admin-Account.",
|
||||
"systemInfo": "System",
|
||||
"version": "Version",
|
||||
"status": "Status",
|
||||
"dbSize": "PostgreSQL-DB-Größe",
|
||||
"dbSizeTop": "Top-Tabellen",
|
||||
"upgradeStatusCardTitle": "Letzter Update-Versuch",
|
||||
"upgradeStatusStarted": "Gestartet",
|
||||
"upgradeStatusFinished": "Beendet",
|
||||
"upgradeStatusResult": "Ergebnis",
|
||||
"upgradeStatusState": "Status",
|
||||
"upgradeStatusOk": "Erfolgreich",
|
||||
"upgradeStatusShowLog": "Vollständiges Log anzeigen ({{n}} Zeilen)",
|
||||
"actionsCardTitle": "System-Aktionen",
|
||||
"actionsHint": "Manuelle Trigger für Operator-Tasks die sonst nur automatisch beim Speichern in den jeweiligen Seiten passieren. Sinnvoll nach SSH-Eingriffen (z. B. /etc/edgeguard/tls/ manuell befüllt).",
|
||||
"haproxyReloadBtn": "HAProxy reload",
|
||||
"haproxyReloadOk": "HAProxy neu geladen.",
|
||||
"haproxyReloadFailed": "HAProxy-Reload fehlgeschlagen",
|
||||
"renderConfigsBtn": "Configs neu rendern (HAProxy)",
|
||||
"renderConfigsOk": "Configs neu gerendert + reloaded.",
|
||||
"renderConfigsFailed": "Config-Render fehlgeschlagen",
|
||||
"backupNowBtn": "Backup jetzt erstellen",
|
||||
"backupNowOk": "Backup ausgelöst — Status in der Backups-Seite verfolgen.",
|
||||
"backupNowFailed": "Backup-Trigger fehlgeschlagen",
|
||||
"serviceRestartCardTitle": "Dienste neu starten",
|
||||
"serviceRestartBtn": "Restart",
|
||||
"serviceRestartOk": "{{service}} wurde neu gestartet.",
|
||||
"serviceRestartFailed": "Neustart von {{service}} fehlgeschlagen",
|
||||
"serviceRestartHint": "Startet den Dienst via systemctl restart. edgeguard-api und PostgreSQL sind bewusst ausgeschlossen.",
|
||||
"setupInfo": "Setup",
|
||||
"adminEmail": "Admin-E-Mail",
|
||||
"fqdn": "FQDN",
|
||||
"setupCompleted": "Setup abgeschlossen"
|
||||
"setupCompleted": "Setup abgeschlossen",
|
||||
"emailsCardTitle": "Kontakt-E-Mails",
|
||||
"adminEmailHint": "Wird beim Login als Admin-Identifier genutzt. Änderung erfordert Re-Login mit der neuen Adresse.",
|
||||
"acmeEmail": "ACME-E-Mail",
|
||||
"acmeEmailHint": "Wird Let's Encrypt als Account-Contact mitgegeben. Bestehende Zertifikate sind nicht betroffen — die nächste Renew-Operation registriert die neue Adresse.",
|
||||
"emailsSaved": "E-Mails aktualisiert.",
|
||||
"emailsFailed": "E-Mail-Update fehlgeschlagen",
|
||||
"maintenanceCardTitle": "Wartungs-Modus (gesamte Box)",
|
||||
"maintenanceOn": "Aktiv — alle Customer-Domains liefern 503. Mgmt-UI bleibt erreichbar.",
|
||||
"maintenanceOff": "Inaktiv — Customer-Traffic wird normal an die Backends geroutet.",
|
||||
"maintenanceMessage": "Wartungs-Meldung",
|
||||
"maintenanceMessagePlaceholder": "Service vorübergehend nicht verfügbar — wir sind in Kürze zurück.",
|
||||
"maintenanceMessageHint": "Wird im Response-Body der 503-Antworten an Endkunden mitgeschickt. Plain text, max. 500 Zeichen.",
|
||||
"maintenanceHint": "Schaltet HAProxy auf :443 in einen Default-503-Modus. Pro-Domain-Maintenance (Domains-Seite) wird hiervon übersteuert. Mgmt-UI auf :3443 ist NICHT betroffen.",
|
||||
"maintenanceSaved": "Wartungs-Modus aktualisiert.",
|
||||
"maintenanceFailed": "Wartungs-Modus-Toggle fehlgeschlagen",
|
||||
"maintenanceActiveTitle": "Wartungs-Modus aktiv",
|
||||
"maintenanceActiveDesc": "Alle Customer-Domains liefern aktuell 503. Mgmt-UI ist erreichbar — Customer-Traffic NICHT. Settings → Wartungs-Modus zum Deaktivieren.",
|
||||
"backupRetentionCardTitle": "Backup-Aufbewahrung",
|
||||
"backupRetentionUnit": "Backups",
|
||||
"backupRetentionDefault": "Default ({{n}} Backups) — pro Tag bei täglichem Schedule = {{n}} Tage History.",
|
||||
"backupRetentionCustom": "Custom — die letzten {{n}} erfolgreichen Backups werden behalten, ältere werden nach jedem Backup-Lauf gelöscht.",
|
||||
"backupRetentionHint": "0 = Default (14). 1-365 = Custom-Limit. Bedenke: jedes Backup ist ein voller pg_dump + Files-tar (typisch 50-500 MB). Bei /var-Disk-Druck eher reduzieren.",
|
||||
"backupRetentionSaved": "Backup-Retention aktualisiert.",
|
||||
"backupRetentionFailed": "Backup-Retention-Update fehlgeschlagen",
|
||||
"auditRetentionCardTitle": "Audit-Log-Aufbewahrung",
|
||||
"auditRetentionUnit": "Tage",
|
||||
"auditRetentionDefault": "Default ({{n}} Tage) — Audit-Einträge älter als {{n}} Tage werden täglich gepruned.",
|
||||
"auditRetentionCustom": "Custom — Audit-Einträge werden für {{n}} Tage behalten.",
|
||||
"auditRetentionHint": "0 = Default (90). 1-3650 (= 10 Jahre) für Compliance (SOX 7y = 2555, DSGVO meist <= 365). Cleanup läuft im Scheduler täglich.",
|
||||
"auditRetentionSaved": "Audit-Retention aktualisiert.",
|
||||
"auditRetentionFailed": "Audit-Retention-Update fehlgeschlagen",
|
||||
"autoUpdateCardTitle": "Automatische Updates",
|
||||
"autoUpdateOn": "Aktiviert — edgeguard-Pakete werden täglich automatisch installiert.",
|
||||
"autoUpdateOff": "Deaktiviert — Updates müssen manuell über den Banner installiert werden.",
|
||||
"autoUpdateHint": "Whitelist umfasst nur edgeguard, edgeguard-api, edgeguard-ui. Andere Pakete bleiben unter manueller Kontrolle. Verlangt unattended-upgrades (Distro-Standard auf Trixie). Conf-File: /etc/apt/apt.conf.d/52edgeguard-auto-updates.",
|
||||
"autoUpdateToggled": "Auto-Update-Einstellung gespeichert.",
|
||||
"autoUpdateFailed": "Auto-Update-Toggle fehlgeschlagen",
|
||||
"passwordCardTitle": "Admin-Passwort ändern",
|
||||
"currentPassword": "Aktuelles Passwort",
|
||||
"newPassword": "Neues Passwort",
|
||||
"newPasswordHint": "Mindestens 12 Zeichen. Wird mit bcrypt gehasht.",
|
||||
"confirmPassword": "Neues Passwort bestätigen",
|
||||
"changePasswordBtn": "Passwort ändern",
|
||||
"passwordChanged": "Passwort geändert.",
|
||||
"passwordChangeFailed": "Passwort-Änderung fehlgeschlagen",
|
||||
"passwordMismatch": "Die Passwörter stimmen nicht überein.",
|
||||
"passwordMinLen": "Mindestens 12 Zeichen erforderlich."
|
||||
},
|
||||
"update": {
|
||||
"available": "Update verfügbar: Version {{version}}",
|
||||
@@ -362,6 +561,8 @@
|
||||
"confirmTitle": "Update jetzt installieren?",
|
||||
"confirmDesc": "Pakete werden auf Version {{version}} aktualisiert. edgeguard-api + scheduler restarten (~2-5s), HAProxy/nft/WG/Squid/Unbound/Chrony laufen durch.",
|
||||
"checkNow": "Auf Updates prüfen",
|
||||
"checkNowHint": "Server-seitigen apt-Cache jetzt aktualisieren und nach neueren Versionen schauen.",
|
||||
"updateReady": "Update bereit: v{{version}}",
|
||||
"checkDone": "Update verfügbar",
|
||||
"noUpdate": "Keine neuen Updates",
|
||||
"checkFailed": "Update-Check fehlgeschlagen",
|
||||
@@ -404,6 +605,10 @@
|
||||
"editServer": "Server-Tunnel bearbeiten",
|
||||
"addClient": "Client-Tunnel hinzufügen",
|
||||
"editClient": "Client-Tunnel bearbeiten",
|
||||
"emptyServerTitle": "Noch keine WireGuard-Server-Tunnel.",
|
||||
"emptyServerDesc": "Server-Modus: diese Box hört auf einem UDP-Port und akzeptiert Peer-Verbindungen (z. B. Roadwarrior-User, Site-to-Site-Niederlassungen).",
|
||||
"emptyClientTitle": "Noch keine WireGuard-Client-Tunnel.",
|
||||
"emptyClientDesc": "Client-Modus: diese Box verbindet sich zu einem externen WireGuard-Server (z. B. HQ-Datacenter, Cloud-Anbindung).",
|
||||
"upstream": "Upstream-Peer",
|
||||
"deleteConfirm": "Tunnel {{name}} wirklich löschen? wg-quick wird gestoppt.",
|
||||
"keys": "Schlüssel",
|
||||
@@ -430,6 +635,8 @@
|
||||
"add": "Peer hinzufügen",
|
||||
"edit": "Peer bearbeiten",
|
||||
"deleteConfirm": "Peer {{name}} wirklich entfernen?",
|
||||
"emptyTitle": "Noch keine Peers in diesem Tunnel.",
|
||||
"emptyDesc": "Lege Peers an — pro Peer eine WireGuard-Identität (Public-Key + Allowed-IPs). Server-generierte Keys liefern dir Config-Download bzw. QR-Code für Mobile-Clients direkt mit.",
|
||||
"keys": "Schlüssel",
|
||||
"generateExtra": "Wenn an: Server erzeugt für diesen Peer ein Keypair und kann die Config / QR-Code ausliefern. Wenn aus: nur den Public-Key paste-en — keine Config-Download möglich.",
|
||||
"pskExtra": "Wenn an: Server generiert einen 32-Byte PSK für diesen Peer.",
|
||||
@@ -471,7 +678,15 @@
|
||||
},
|
||||
"clusterCard": {
|
||||
"title": "Cluster",
|
||||
"nodes": "Knoten"
|
||||
"nodes": "Knoten",
|
||||
"modeSingle": "Single-Node",
|
||||
"modeCluster": "Cluster",
|
||||
"drift": "Config-Drift erkannt",
|
||||
"health": {
|
||||
"ok": "OK",
|
||||
"degraded": "degraded",
|
||||
"split-brain": "split-brain"
|
||||
}
|
||||
},
|
||||
"routingCard": {
|
||||
"title": "Routing",
|
||||
@@ -486,6 +701,15 @@
|
||||
"ifaces": "Interfaces",
|
||||
"wg": "WireGuard"
|
||||
},
|
||||
"alertsCard": {
|
||||
"title": "Aktuelle Alerts",
|
||||
"viewAll": "Alle anzeigen"
|
||||
},
|
||||
"onboardingTitle": "Willkommen bei EdgeGuard",
|
||||
"onboardingIntro": "Frische Box — hier die nächsten Schritte um Customer-Traffic zu routen:",
|
||||
"onboardingStep1": "Backend-Pool anlegen (App-Server hinter HAProxy)",
|
||||
"onboardingStep2": "Domain hinzufügen (FQDN, primary Backend zuweisen)",
|
||||
"onboardingStep3": "TLS-Zertifikat ausstellen (Let's Encrypt HTTP-01)",
|
||||
"servicesCard": {
|
||||
"title": "Service-Status (live, 10s)"
|
||||
},
|
||||
@@ -510,6 +734,17 @@
|
||||
"title": "Zeitserver (Chrony)",
|
||||
"intro": "Chrony als Time-Sync-Daemon (NTP). Quellen oben, Listen-/Serve-Konfig im Settings-Tab. Wenn 'serve_clients' aktiv und LAN-IPs gebound sind, wird die Box selbst zum NTP-Server für das LAN.",
|
||||
"tabs": { "pools": "Quellen", "settings": "Settings" },
|
||||
"statusCard": {
|
||||
"title": "Sync-Status (chronyc tracking)",
|
||||
"sync": "Synchronisiert",
|
||||
"synced": "Ja",
|
||||
"notSynced": "Nein",
|
||||
"source": "Quelle",
|
||||
"stratum": "Stratum",
|
||||
"offset": "Offset",
|
||||
"offsetHint": "Zeitdifferenz zur Referenzquelle. Werte > 100 ms sind ungewöhnlich — Netzwerkprobleme oder fehlkonfigurierte Quelle prüfen.",
|
||||
"loading": "Lade…"
|
||||
},
|
||||
"pool": {
|
||||
"kind": "Typ",
|
||||
"kindPool": "pool — DNS-Round-Robin (mehrere Server aus A-Records)",
|
||||
@@ -524,7 +759,9 @@
|
||||
"description": "Beschreibung",
|
||||
"add": "Quelle hinzufügen",
|
||||
"edit": "Quelle bearbeiten",
|
||||
"deleteConfirm": "NTP-Quelle {{addr}} wirklich löschen?"
|
||||
"deleteConfirm": "NTP-Quelle {{addr}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine NTP-Quellen.",
|
||||
"emptyDesc": "Ohne konfigurierte Pool/Server-Einträge nutzt chrony nur seine compiled-in Default-Pool (debian.pool.ntp.org). Setze eigene Pools für genauere Zeitabstimmung oder interne Stratum-Server."
|
||||
},
|
||||
"settings": {
|
||||
"intro": "Globale Chrony-Settings. Save reloaded chrony automatisch.",
|
||||
@@ -560,7 +797,9 @@
|
||||
"records": "Records …",
|
||||
"add": "Zone hinzufügen",
|
||||
"edit": "Zone bearbeiten",
|
||||
"deleteConfirm": "Zone {{name}} mit allen Records wirklich löschen?"
|
||||
"deleteConfirm": "Zone {{name}} mit allen Records wirklich löschen?",
|
||||
"emptyTitle": "Noch keine DNS-Zonen.",
|
||||
"emptyDesc": "Unbound forwarded standardmäßig alles an die Upstream-Resolver. Lege eine Zone an, um z. B. interne FQDNs (internal.example.com) lokal zu hosten oder einen Upstream-Stub für eine fremde Domain einzurichten."
|
||||
},
|
||||
"record": {
|
||||
"name": "Name",
|
||||
@@ -572,7 +811,9 @@
|
||||
"drawerTitle": "DNS-Records",
|
||||
"add": "Record hinzufügen",
|
||||
"edit": "Record bearbeiten",
|
||||
"deleteConfirm": "Record {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "Record {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine Records in dieser Zone.",
|
||||
"emptyDesc": "A/AAAA/CNAME/MX/TXT-Einträge. Bei local-Zone authoritativ; bei forward-Zone hat das hier keinen Effekt (Upstream gewinnt)."
|
||||
},
|
||||
"settings": {
|
||||
"intro": "Globale Resolver-Settings. Änderungen hier reloaden Unbound automatisch.",
|
||||
@@ -608,7 +849,9 @@
|
||||
"comment": "Kommentar",
|
||||
"add": "ACL hinzufügen",
|
||||
"edit": "ACL bearbeiten",
|
||||
"deleteConfirm": "ACL {{name}} wirklich löschen?"
|
||||
"deleteConfirm": "ACL {{name}} wirklich löschen?",
|
||||
"emptyTitle": "Noch keine Forward-Proxy-ACLs.",
|
||||
"emptyDesc": "Default ohne ACLs: nur localnet (10/8, 172.16/12, 192.168/16) darf raus. Lege eine ACL an, um spezifische Domains/IPs/Ports gezielt zu erlauben oder zu blocken."
|
||||
},
|
||||
"common": {
|
||||
"yes": "Ja",
|
||||
@@ -629,7 +872,9 @@
|
||||
"add": "Hinzufügen",
|
||||
"download": "Download",
|
||||
"copy": "Kopieren",
|
||||
"copied": "Kopiert"
|
||||
"copied": "Kopiert",
|
||||
"close": "Schließen",
|
||||
"refresh": "Aktualisieren"
|
||||
},
|
||||
"license": {
|
||||
"title": "Lizenz",
|
||||
@@ -678,6 +923,8 @@
|
||||
"addTitle": "Statische Route anlegen",
|
||||
"editTitle": "Statische Route bearbeiten",
|
||||
"empty": "Keine verwalteten Routen.",
|
||||
"emptyTitle": "Noch keine verwalteten Routen.",
|
||||
"emptyDesc": "Statische Routen die EdgeGuard beim Boot setzt (z. B. nach 10.0.5.0/24 via VPN-Gateway). Live-Routen oben sind read-only — was hier eingetragen wird, persistiert.",
|
||||
"confirmDelete": "Route nach {{dest}} wirklich löschen?",
|
||||
"refreshTooltip": "Live-Routen neu laden",
|
||||
"destExtra": "CIDR — z.B. 10.0.5.0/24 oder 0.0.0.0/0 für Default-Route.",
|
||||
@@ -711,6 +958,10 @@
|
||||
"testDone": "Test gesendet — {{ok}}/{{total}} Channels erfolgreich",
|
||||
"emptyChannels": "Keine Channels. Lege einen Webhook oder eine Email an.",
|
||||
"emptyEvents": "Noch keine Alarme — Triggers haben noch keinen Event gefeuert.",
|
||||
"emptyChannelsTitle": "Noch keine Alert-Channels.",
|
||||
"emptyChannelsDesc": "Ohne Channels werden gefeuerte Events nur in die Datenbank (Tab \"Events\") geschrieben — niemand wird benachrichtigt. Lege einen Webhook (Mattermost/Slack/Discord/Custom) oder eine SMTP-Email an.",
|
||||
"emptyEventsTitle": "Noch keine Alert-Events.",
|
||||
"emptyEventsDesc": "Triggers (Cert-Expiry, Backup-Fail, Cluster-Drift, License-Invalid, etc.) haben noch keinen Event gefeuert. Wenn sie feuern, landen sie hier und werden an die konfigurierten Channels zugestellt.",
|
||||
"noChannels": "kein Channel aktiv",
|
||||
"confirmDelete": "Channel {{name}} wirklich löschen?",
|
||||
"col": {
|
||||
@@ -766,6 +1017,12 @@
|
||||
"scopeTitle": "Was wird gesichert?",
|
||||
"scopeDesc": "DB-Dump (pg_dump --clean), setup.json, license_key, license.cache, .jwt_fingerprint, acme-account/. Konfig-Dateien (haproxy.cfg, nft, …) sind aus der DB regenerierbar und werden NICHT mitgesichert.",
|
||||
"tabs": { "history": "Sicherungen", "remotes": "Off-Site-Ziele" },
|
||||
"statLastSuccess": "Letzte erfolgreiche Sicherung",
|
||||
"statTotal": "Erfolgreiche Sicherungen",
|
||||
"statSize": "Gesamtgröße",
|
||||
"statFails24h": "Fehlschläge (24 h)",
|
||||
"statHoursAgo": "vor {{n}} h",
|
||||
"statDaysAgo": "vor {{n}} Tagen",
|
||||
"runNow": "Backup jetzt erstellen",
|
||||
"created": "Backup erstellt: {{file}}",
|
||||
"failed": "Backup fehlgeschlagen",
|
||||
@@ -821,7 +1078,8 @@
|
||||
"filter": {
|
||||
"sources": "Quellen wählen (alle wenn leer)",
|
||||
"levels": "Level filtern",
|
||||
"grep": "Volltext-Suche"
|
||||
"grep": "Volltext-Suche",
|
||||
"reset": "Filter zurücksetzen"
|
||||
}
|
||||
},
|
||||
"fwlog": {
|
||||
@@ -861,5 +1119,34 @@
|
||||
"dst": "Ziel-IP",
|
||||
"rule": "Rule-ID"
|
||||
}
|
||||
},
|
||||
"audit": {
|
||||
"title": "Audit-Log",
|
||||
"intro": "Wer hat was wann geändert. Jede Mutation in der API (Domain anlegen, Backend deaktivieren, Cert ausstellen, …) ist hier nachvollziehbar.",
|
||||
"filter": {
|
||||
"actor": "Actor",
|
||||
"action": "Aktion",
|
||||
"subject": "Subjekt",
|
||||
"range": "Zeitraum",
|
||||
"search": "Suchen",
|
||||
"reset": "Zurücksetzen"
|
||||
},
|
||||
"col": {
|
||||
"time": "Zeit",
|
||||
"actor": "Actor",
|
||||
"action": "Aktion",
|
||||
"subject": "Subjekt",
|
||||
"detail": "Details"
|
||||
},
|
||||
"detailShow": "Details anzeigen",
|
||||
"empty": {
|
||||
"title": "Keine Treffer",
|
||||
"desc": "Mit diesen Filtern wurden keine Einträge gefunden. Filter ändern oder zurücksetzen."
|
||||
},
|
||||
"page": {
|
||||
"prev": "Zurück",
|
||||
"next": "Weiter",
|
||||
"showing": "Zeile {{from}}–{{to}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user