Neue Page management-ui/src/pages/FirewallLive — Live-Tail der NFLOG- Events aus /api/v1/firewall/log/live (WebSocket). Features: - Status-Indicator (Live/getrennt), Auto-Reconnect alle 2s nach Drop - Filter-Bar (action/proto/src/dst/rule_id) — bei Änderung wird der WS neu verbunden, Server schickt frischen Snapshot - Pause-Toggle: während Pause werden Events gebuffert (max 1000), beim Resume in die Tabelle gemerged - CSV-Export der aktuellen Tabelle (timestamp/rule/action/proto/src/ dst/iface/size) - Color-coded Action-Tags (ACCEPT=grün, DROP=rot, REJECT=orange) - Ring-Buffer 1000 im UI damit die DOM-Last bei Hochlast bleibt - Sidebar-Eintrag "Firewall-Log" unter Sicherheit (Eye-Icon) - DE/EN i18n haproxy: backend api_backend bekommt `timeout tunnel 1h` damit der WebSocket-Stream nicht nach `timeout server 60s` ohne Events stirbt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
657 lines
29 KiB
JSON
657 lines
29 KiB
JSON
{
|
||
"app": {
|
||
"title": "EdgeGuard",
|
||
"subtitle": "Native Reverse-Proxy / VPN / Firewall"
|
||
},
|
||
"nav": {
|
||
"dashboard": "Dashboard",
|
||
"domains": "Domains",
|
||
"backends": "Backends",
|
||
"routing": "Routing",
|
||
"networks": "Netzwerk-Interfaces",
|
||
"ipAddresses": "IP-Adressen",
|
||
"ssl": "SSL-Zertifikate",
|
||
"vpn": "VPN",
|
||
"wireguard": "WireGuard",
|
||
"forwardProxy": "Forward-Proxy",
|
||
"dns": "DNS",
|
||
"ntp": "Zeit (NTP)",
|
||
"firewall": "Firewall",
|
||
"firewallLive": "Firewall-Log",
|
||
"cluster": "Cluster",
|
||
"license": "Lizenz",
|
||
"settings": "Einstellungen",
|
||
"section": {
|
||
"overview": "Übersicht",
|
||
"routing": "Routing",
|
||
"network": "Netzwerk",
|
||
"security": "Sicherheit",
|
||
"system": "System"
|
||
}
|
||
},
|
||
"fw": {
|
||
"title": "Firewall",
|
||
"intro": "Fortigate-Style: Regeln aus Zonen × Adress-Objekten/Gruppen × Services/Service-Gruppen × Action. NAT separat. Top-down, first-match.",
|
||
"tabs": {
|
||
"rules": "Regeln",
|
||
"nat": "NAT",
|
||
"zones": "Zonen",
|
||
"addrObj": "Adress-Objekte",
|
||
"addrGrp": "Adress-Gruppen",
|
||
"services": "Services",
|
||
"svcGrp": "Service-Gruppen"
|
||
},
|
||
"zone": {
|
||
"name": "Name",
|
||
"description": "Beschreibung",
|
||
"builtin": "vordefiniert",
|
||
"builtinHint": "Vordefinierte Zonen können nicht gelöscht werden — Renderer und Anti-Lockout-Regeln verlassen sich darauf.",
|
||
"builtinNameLocked": "Name vordefiniert — kann nicht geändert werden, weil bestehende Regeln und Interfaces ihn referenzieren.",
|
||
"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?"
|
||
},
|
||
"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?"
|
||
},
|
||
"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?"
|
||
},
|
||
"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?"
|
||
},
|
||
"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?"
|
||
},
|
||
"rule": {
|
||
"name": "Name", "priority": "Priority", "enabled": "Aktiv", "log": "Logging",
|
||
"action": "Aktion", "src": "Quelle", "dst": "Ziel", "service": "Service",
|
||
"srcZone": "Quell-Zone", "dstZone": "Ziel-Zone",
|
||
"srcKind": "Quell-Typ", "dstKind": "Ziel-Typ",
|
||
"object": "Adress-Objekt", "group": "Adress-Gruppe",
|
||
"serviceKind": "Service-Typ", "serviceGroup": "Service-Gruppe",
|
||
"comment": "Kommentar",
|
||
"add": "Regel hinzufügen", "edit": "Regel bearbeiten",
|
||
"deleteConfirm": "Diese Regel wirklich löschen?"
|
||
},
|
||
"nat": {
|
||
"name": "Name", "priority": "Priority", "kind": "Typ", "enabled": "Aktiv",
|
||
"match": "Match", "target": "Ziel",
|
||
"inZone": "Eingangs-Zone", "outZone": "Ausgangs-Zone", "proto": "Protokoll",
|
||
"matchSrcCidr": "Source-CIDR (Match)", "matchDstCidr": "Dest-CIDR (Match)",
|
||
"matchDstCidrHint": "leer = jede dest-IP (z.B. öffentliche IP der Box)",
|
||
"dportStart": "Port (Start)", "dportEnd": "Port (Ende)",
|
||
"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?"
|
||
},
|
||
"sys": {
|
||
"title": "System-Regeln (immer aktiv)",
|
||
"chain": "Chain", "match": "Match", "action": "Aktion", "note": "Hinweis",
|
||
"policy": "Default-Policy",
|
||
"policyValue": "Eingang DROP — alles muss explizit erlaubt werden.",
|
||
"order": "Auswertung",
|
||
"orderValue": "System-Regeln zuerst, danach Operator-Regeln top-down (priority asc, first-match).",
|
||
"lockout": "Anti-Lockout",
|
||
"lockoutValue": "SSH (22) und Management-UI (443) sind immer erreichbar — können auch vom Operator nicht versehentlich gesperrt werden."
|
||
}
|
||
},
|
||
"networks": {
|
||
"title": "Netzwerk-Interfaces",
|
||
"intro": "Verwalte WAN-, LAN-, VLAN- und Bond-Interfaces. Read-only-Discovery der Kernel-Interfaces oben; deklarierte Konfiguration unten — runtime-Apply via systemd-networkd folgt in einem späteren Release.",
|
||
"systemDiscovered": "System-Interfaces (read-only)",
|
||
"addInterface": "Interface hinzufügen",
|
||
"editInterface": "Interface bearbeiten",
|
||
"name": "Name",
|
||
"type": "Typ",
|
||
"parent": "Parent-Interface",
|
||
"selectParent": "Parent wählen",
|
||
"vlan": "VLAN",
|
||
"vlanId": "VLAN-ID",
|
||
"composition": "Zusammensetzung",
|
||
"members": "Member-Interfaces",
|
||
"selectMembers": "Physische Interfaces wählen",
|
||
"membersRequired": "Mindestens ein Member-Interface erforderlich",
|
||
"membersHintBridge": "Eine Bridge bündelt mehrere physische Ports auf L2 — typisch zwei Ports für einen Software-Switch.",
|
||
"membersHintBond": "Ein Bond aggregiert mehrere physische Ports zu einem logischen Link (LACP / active-backup).",
|
||
"role": "Zone",
|
||
"roleHint": "Zonen kommen aus Firewall → Zonen. Eigene Zonen (z.B. iot, guest) lassen sich dort anlegen.",
|
||
"mtu": "MTU",
|
||
"active": "Aktiv",
|
||
"description": "Beschreibung",
|
||
"actions": "Aktionen",
|
||
"deleteConfirm": "Interface {{name}} wirklich löschen?"
|
||
},
|
||
"ips": {
|
||
"title": "IP-Adressen",
|
||
"intro": "Adressen, die das Betriebssystem zeigt (Read-only oben) plus die Adressen, die EdgeGuard zusätzlich verwaltet — inklusive VIPs für Cluster-Failover.",
|
||
"systemDiscovered": "Adressen am Kernel (read-only)",
|
||
"managedTitle": "Verwaltete Adressen",
|
||
"family": "Familie",
|
||
"addAddress": "Adresse hinzufügen",
|
||
"editAddress": "Adresse bearbeiten",
|
||
"interface": "Interface",
|
||
"selectInterface": "Interface wählen",
|
||
"address": "Adresse",
|
||
"prefix": "Prefix",
|
||
"vip": "VIP",
|
||
"vipFlag": "Als VIP markieren",
|
||
"vipPriority": "VIP-Priorität (Cluster-Failover)",
|
||
"active": "Aktiv",
|
||
"description": "Beschreibung",
|
||
"actions": "Aktionen",
|
||
"deleteConfirm": "Adresse {{addr}} wirklich löschen?"
|
||
},
|
||
"auth": {
|
||
"loginTitle": "Anmelden",
|
||
"email": "E-Mail",
|
||
"password": "Passwort",
|
||
"login": "Anmelden",
|
||
"logout": "Abmelden",
|
||
"loginFailed": "Anmeldung fehlgeschlagen",
|
||
"loggedInAs": "Angemeldet als"
|
||
},
|
||
"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.",
|
||
"adminEmail": "Admin-E-Mail",
|
||
"adminPassword": "Admin-Passwort",
|
||
"passwordRule": "Mindestens 12 Zeichen.",
|
||
"fqdn": "Öffentliche FQDN",
|
||
"acmeEmail": "ACME-/Let's-Encrypt-E-Mail",
|
||
"licenseKey": "Lizenzschlüssel (optional)",
|
||
"submit": "Setup abschließen",
|
||
"successTitle": "Setup abgeschlossen",
|
||
"successHint": "Du wirst zur Anmeldung weitergeleitet."
|
||
},
|
||
"dashboard": {
|
||
"title": "Dashboard",
|
||
"welcomeHint": "Übersicht aller laufenden EdgeGuard-Komponenten."
|
||
},
|
||
"domains": {
|
||
"title": "Domains",
|
||
"intro": "Verwalte FQDNs, die HAProxy terminiert. Optionales Primary-Backend als Catch-all; Pfad-Routing via Routing-Regeln.",
|
||
"addDomain": "Domain hinzufügen",
|
||
"editDomain": "Domain bearbeiten",
|
||
"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",
|
||
"httpToHttps": "HTTP→HTTPS",
|
||
"hsts": "HSTS",
|
||
"notes": "Notizen",
|
||
"actions": "Aktionen",
|
||
"edit": "Bearbeiten",
|
||
"delete": "Löschen",
|
||
"deleteConfirm": "Domain {{name}} wirklich löschen?"
|
||
},
|
||
"backends": {
|
||
"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",
|
||
"editBackend": "Backend-Pool bearbeiten",
|
||
"name": "Name",
|
||
"scheme": "Schema",
|
||
"target": "Ziel",
|
||
"healthCheck": "Health-Check-Pfad",
|
||
"active": "Aktiv",
|
||
"usedBy": "Genutzt von",
|
||
"noDomain": "keine Domain",
|
||
"attachedDomains": "Domains",
|
||
"attachedDomainsHint": "Domains, die dieses Backend als Primary verwenden. Auswahl umkonfiguriert die Domains direkt — gleiche Quelle wie der Backend-Picker im Domain-Modal.",
|
||
"selectDomains": "Domains wählen",
|
||
"lbAlgo": "Load-Balancing",
|
||
"lbAlgoHint": "roundrobin = gleichmäßig, leastconn = an den Server mit wenigsten Verbindungen, source = sticky per Client-IP (für stateful Apps ohne shared session).",
|
||
"websocket": "WebSocket-Support",
|
||
"websocketHint": "An: erlaubt langlebige WebSocket-/Long-Poll-Verbindungen (z. B. Proxmox-Console, SSH-WS, AsyncAPI) — Tunnel-Idle 1h statt 60s. Aus: strikte HTTP-Timeouts.",
|
||
"servers": "Server",
|
||
"noServers": "kein Server",
|
||
"nServers": "{{n}} Server",
|
||
"serversIn": "Server in „{{name}}\"",
|
||
"serverHintCreate": "Speichern legt nur den Pool an. Server kommen im nächsten Schritt — Pool öffnen → „Server hinzufügen\".",
|
||
"actions": "Aktionen",
|
||
"deleteConfirm": "Backend-Pool {{name}} wirklich löschen? Alle Server im Pool werden mitentfernt.",
|
||
"server": {
|
||
"intro": "Upstream-Server im Pool. Reihenfolge in HAProxy egal — der LB-Algorithmus entscheidet.",
|
||
"add": "Server hinzufügen",
|
||
"edit": "Server bearbeiten",
|
||
"name": "Server-Name",
|
||
"address": "Adresse",
|
||
"port": "Port",
|
||
"target": "Endpoint",
|
||
"weight": "Gewicht",
|
||
"weightHint": "0–256. Höher = mehr Traffic. 100 = Standard.",
|
||
"backup": "Backup",
|
||
"backupHint": "Backup-Server werden nur angesprochen, wenn alle primären Server (non-backup) down sind.",
|
||
"empty": "Noch keine Server im Pool. „Server hinzufügen\" startet damit.",
|
||
"deleteConfirm": "Server {{name}} wirklich löschen?"
|
||
}
|
||
},
|
||
"routing": {
|
||
"title": "Routing-Regeln",
|
||
"intro": "Pfad-Präfix → Backend-Mapping pro Domain. Niedrige Priority gewinnt; Catch-all per Domain.primary_backend.",
|
||
"addRule": "Regel hinzufügen",
|
||
"editRule": "Regel bearbeiten",
|
||
"domain": "Domain",
|
||
"pathPrefix": "Pfad-Präfix",
|
||
"backend": "Backend",
|
||
"priority": "Priorität",
|
||
"active": "Aktiv",
|
||
"actions": "Aktionen",
|
||
"selectDomain": "Domain wählen",
|
||
"selectBackend": "Backend wählen",
|
||
"deleteConfirm": "Diese Routing-Regel wirklich löschen?"
|
||
},
|
||
"cluster": {
|
||
"title": "Cluster",
|
||
"intro": "{{count}} Node(s) registriert. Multi-Node-Cluster (KeyDB Active-Active + PG Streaming Replication) folgt in einem späteren Release.",
|
||
"id": "Node-ID",
|
||
"fqdn": "FQDN",
|
||
"role": "Rolle",
|
||
"joinedAt": "Beigetreten",
|
||
"self": "diese Node"
|
||
},
|
||
"ssl": {
|
||
"title": "SSL-Zertifikate",
|
||
"intro": "TLS-Zertifikate verwalten — entweder per Let's Encrypt automatisch ausstellen oder eigene PEMs hochladen. HAProxy lädt nach jeder Änderung automatisch neu.",
|
||
"tabLE": "Let's Encrypt",
|
||
"tabUpload": "Eigenes Zertifikat",
|
||
"leIntro": "Domain wählen, Issue klicken — EdgeGuard löst HTTP-01 über die ACME-Webroot, schreibt das PEM nach /etc/edgeguard/tls/ und reloaded HAProxy.",
|
||
"uploadIntro": "Eigenes Zertifikat hochladen. Format: PEM-encoded. Cert + optional Chain + Private Key. EdgeGuard prüft die Cert/Key-Übereinstimmung vor dem Schreiben.",
|
||
"uploadHint": "Tipp: bei Let's-Encrypt-Renewals nicht hier hochladen — den LE-Tab nutzen.",
|
||
"domain": "Domain",
|
||
"selectDomain": "Domain wählen oder eintippen",
|
||
"domainExtra": "Inkludiert Management-FQDN (aus Setup), Cluster-Knoten und Operator-Domains. Du kannst auch eine andere Domain tippen, sofern DNS schon auf die Box zeigt.",
|
||
"fqdnHintMgmt": "Management-FQDN",
|
||
"fqdnHintCluster": "Cluster · {{role}}",
|
||
"issuer": "Issuer",
|
||
"status": "Status",
|
||
"expiresIn": "Gültig noch",
|
||
"expiredAgo": "abgelaufen vor {{days}} Tagen",
|
||
"actions": "Aktionen",
|
||
"issueButton": "Zertifikat anfordern",
|
||
"uploadButton": "Hochladen",
|
||
"issueSuccess": "Zertifikat ausgestellt + installiert.",
|
||
"uploadSuccess": "Zertifikat hochgeladen + installiert.",
|
||
"deleteConfirm": "Zertifikat für {{domain}} löschen? HAProxy fällt für diese Domain auf das Default-Cert zurück.",
|
||
"installedTitle": "Installierte Zertifikate",
|
||
"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.",
|
||
"systemInfo": "System",
|
||
"version": "Version",
|
||
"status": "Status",
|
||
"setupInfo": "Setup",
|
||
"adminEmail": "Admin-E-Mail",
|
||
"fqdn": "FQDN",
|
||
"setupCompleted": "Setup abgeschlossen"
|
||
},
|
||
"update": {
|
||
"available": "Update verfügbar: Version {{version}}",
|
||
"multiPackageHint": "{{count}} Pakete werden aktualisiert.",
|
||
"applyNow": "Jetzt installieren",
|
||
"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",
|
||
"checkDone": "Update verfügbar",
|
||
"noUpdate": "Keine neuen Updates",
|
||
"checkFailed": "Update-Check fehlgeschlagen",
|
||
"running": "Update läuft …",
|
||
"waitHint": "Bitte warten — die Seite lädt automatisch neu sobald die neue Version live ist.",
|
||
"success": "Update auf {{version}} abgeschlossen.",
|
||
"failed": "Update fehlgeschlagen",
|
||
"stepDownload": "Pakete laden",
|
||
"stepInstall": "Installation",
|
||
"stepRestart": "Service-Restart",
|
||
"stepVerify": "Verifizierung"
|
||
},
|
||
"wg": {
|
||
"title": "WireGuard",
|
||
"intro": "VPN-Tunnel über WireGuard. Server-Modus = wir lauschen für Peers; Client-Modus = wir verbinden zu einem festen Upstream. Privater Schlüssel liegt verschlüsselt in der DB.",
|
||
"tabs": { "servers": "Server-Tunnel", "clients": "Client-Tunnel" },
|
||
"serverIntro": "Server-Tunnel hosten ein Peer-Roster — z.B. Mitarbeiter-Geräte oder Niederlassungen. Pro Peer bekommt der Operator eine .conf zum Download (oder QR-Code für Mobile).",
|
||
"clientIntro": "Client-Tunnel verbinden EdgeGuard zu einem fremden WireGuard-Server (z.B. HQ-Datacenter). Allowed-IPs steuert, welcher Traffic durch den Tunnel geroutet wird.",
|
||
"iface": {
|
||
"name": "Name",
|
||
"namePattern": "wg gefolgt von Kleinbuchstaben/Ziffern/-, max. 15 Zeichen",
|
||
"nameExtra": "Empfehlung: wg0, wg1, wg-hq …",
|
||
"address": "Adresse (CIDR)",
|
||
"addressExtra": "Tunnel-IP der Box, z.B. 10.99.0.1/24 für /24-Pool",
|
||
"listenPort": "Listen-Port",
|
||
"publicKey": "Public-Key",
|
||
"privateKey": "Private-Key (paste)",
|
||
"privateKeyExtra": "Nur ausfüllen wenn nicht generieren — base64 32 Byte. Wird verschlüsselt gespeichert.",
|
||
"peerEndpoint": "Peer-Endpoint",
|
||
"peerPublicKey": "Peer Public-Key",
|
||
"peerPSK": "Pre-Shared-Key (PSK)",
|
||
"peerPSKExtra": "Optional, zusätzliche Schicht",
|
||
"allowedIPs": "Allowed IPs",
|
||
"allowedIPsExtra": "Was durch den Tunnel geroutet wird. Default = full-tunnel.",
|
||
"keepalive": "Persistent Keepalive (sec)",
|
||
"mtu": "MTU",
|
||
"zone": "Firewall-Zone",
|
||
"description": "Beschreibung",
|
||
"addServer": "Server-Tunnel hinzufügen",
|
||
"editServer": "Server-Tunnel bearbeiten",
|
||
"addClient": "Client-Tunnel hinzufügen",
|
||
"editClient": "Client-Tunnel bearbeiten",
|
||
"upstream": "Upstream-Peer",
|
||
"deleteConfirm": "Tunnel {{name}} wirklich löschen? wg-quick wird gestoppt.",
|
||
"keys": "Schlüssel",
|
||
"generateExtra": "Wenn an: Server erzeugt ein neues Curve25519-Keypair beim Speichern.",
|
||
"generateOn": "Server generiert",
|
||
"generateOff": "Manuell paste",
|
||
"editKeyWarning": "Achtung: neue Schlüssel = bestehende Peer-Configs ungültig. Nur ändern wenn explizit gewollt."
|
||
},
|
||
"peers": {
|
||
"button": "Peers",
|
||
"drawerTitle": "Peer-Roster"
|
||
},
|
||
"peer": {
|
||
"name": "Name",
|
||
"publicKey": "Public-Key",
|
||
"publicKeyExtra": "Wird vom Peer-Gerät erzeugt; hier nur paste-bar wenn der Peer schon ein Key-Pair hat.",
|
||
"allowedIPs": "Allowed IPs",
|
||
"allowedIPsExtra": "Welche Tunnel-IPs darf dieser Peer benutzen. Typisch /32 = eine IP.",
|
||
"keepalive": "Keepalive (sec)",
|
||
"keepaliveExtra": "0 = aus. Empfohlen 25 hinter NAT.",
|
||
"lastHandshake": "Letzter Handshake",
|
||
"never": "nie",
|
||
"description": "Beschreibung",
|
||
"add": "Peer hinzufügen",
|
||
"edit": "Peer bearbeiten",
|
||
"deleteConfirm": "Peer {{name}} wirklich entfernen?",
|
||
"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.",
|
||
"pskOn": "PSK generieren",
|
||
"pskOff": "kein PSK",
|
||
"downloadConf": "wg-quick.conf herunterladen",
|
||
"qrTitle": "WireGuard-QR",
|
||
"qrHint": "Mit der WireGuard-App (iOS/Android) scannen: \"Tunnel hinzufügen\" → \"QR-Code scannen\". Endpoint im Download-Conf bitte vor Verwendung anpassen.",
|
||
"online": "Online",
|
||
"offline": "Offline",
|
||
"traffic": "Traffic"
|
||
}
|
||
},
|
||
"dashboard": {
|
||
"title": "Dashboard",
|
||
"welcomeHint": "EdgeGuard-Übersicht — Health, Counts, Live-Status der wichtigsten Dienste.",
|
||
"kpi": {
|
||
"domains": "Domains",
|
||
"backends": "Backends",
|
||
"ifaces": "Interfaces",
|
||
"fwRules": "FW-Regeln",
|
||
"natRules": "NAT-Regeln",
|
||
"wg": "WG-Verbindungen"
|
||
},
|
||
"wgCard": {
|
||
"title": "WireGuard",
|
||
"empty": "Noch kein WG-Tunnel angelegt."
|
||
},
|
||
"firewallCard": {
|
||
"title": "Firewall",
|
||
"zones": "Zonen",
|
||
"activeRules": "{{rules}} aktive Regeln · {{nat}} NAT"
|
||
},
|
||
"sslCard": {
|
||
"title": "SSL-Zertifikate",
|
||
"total": "Verwaltete Zertifikate",
|
||
"expiringSoon": "{{count}} läuft bald ab (< 30 Tage)",
|
||
"allFresh": "Alle Zertifikate haben > 30 Tage Restlaufzeit."
|
||
},
|
||
"clusterCard": {
|
||
"title": "Cluster",
|
||
"nodes": "Knoten"
|
||
},
|
||
"routingCard": {
|
||
"title": "Routing",
|
||
"domains": "Domains",
|
||
"backends": "Backends",
|
||
"attached": "{{count}}/{{total}} Domains haben einen Primary-Backend"
|
||
},
|
||
"systemCard": {
|
||
"title": "System",
|
||
"version": "Version",
|
||
"api": "API",
|
||
"ifaces": "Interfaces",
|
||
"wg": "WireGuard"
|
||
},
|
||
"servicesCard": {
|
||
"title": "Service-Status (live, 10s)"
|
||
},
|
||
"activityCard": {
|
||
"title": "Letzte Aktivität (Audit-Log)",
|
||
"empty": "Noch keine Aktivität — Mutationen werden hier protokolliert."
|
||
},
|
||
"haproxyCard": {
|
||
"title": "HAProxy-Backends (live)",
|
||
"empty": "Keine Backend-Stats erreichbar (HAProxy down oder admin.sock-permission)."
|
||
},
|
||
"resCard": {
|
||
"load": "Load",
|
||
"memory": "Memory",
|
||
"disk": "Disk /",
|
||
"free": "frei",
|
||
"conntrack": "Conntrack",
|
||
"uptime": "Uptime"
|
||
}
|
||
},
|
||
"ntp": {
|
||
"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" },
|
||
"pool": {
|
||
"kind": "Typ",
|
||
"kindPool": "pool — DNS-Round-Robin (mehrere Server aus A-Records)",
|
||
"kindServer": "server — einzelner Host",
|
||
"address": "Adresse / Host",
|
||
"addressExtra": "FQDN (für pool: 0.de.pool.ntp.org) oder IP.",
|
||
"iburst": "iburst",
|
||
"prefer": "prefer",
|
||
"minpoll": "min-poll",
|
||
"maxpoll": "max-poll",
|
||
"options": "Optionen",
|
||
"description": "Beschreibung",
|
||
"add": "Quelle hinzufügen",
|
||
"edit": "Quelle bearbeiten",
|
||
"deleteConfirm": "NTP-Quelle {{addr}} wirklich löschen?"
|
||
},
|
||
"settings": {
|
||
"intro": "Globale Chrony-Settings. Save reloaded chrony automatisch.",
|
||
"serveClients": "Als NTP-Server für Clients arbeiten",
|
||
"serveClientsExtra": "Wenn aus: chrony agiert nur als Client (port 0). Wenn an + Listen-IP: bindet UDP/123.",
|
||
"listenAddresses": "Listen-Adressen",
|
||
"listenAddressesPlaceholder": "IPs wählen (oder eintippen)",
|
||
"listenAddressesExtra": "Auf welchen IPs chrony :123/UDP bindet. 127.0.0.1+::1 = nur lokal; LAN-IPs öffnen für LAN-Clients (FW-Rule wird automatisch generiert).",
|
||
"allowACL": "Allow-ACL (CIDRs)",
|
||
"allowACLExtra": "Wer darf NTP-Time anfragen.",
|
||
"makestepSecs": "makestep secs",
|
||
"makestepSecsExtra": "Erlaube step (statt slew) wenn offset > N sec.",
|
||
"makestepLimit": "makestep limit",
|
||
"rtcsync": "RTC mit System-Time syncen",
|
||
"rtcsyncExtra": "Hardware-Clock alle 11 min synchron halten — nach Reboot ist die Zeit grob korrekt.",
|
||
"leapsectz": "Leap-Sec TZ",
|
||
"leapsectzExtra": "Optional, z.B. 'right/UTC' für leap-sec über tzdata."
|
||
}
|
||
},
|
||
"dns": {
|
||
"title": "DNS (Unbound)",
|
||
"intro": "Unbound-Resolver auf :53. Lokale Zonen (authoritativ aus DNS-Records) und Forward-Zonen (per stub-zone weiter zu fremden Resolvern). Default-Forwarder für alles andere.",
|
||
"tabs": { "zones": "Zonen", "settings": "Resolver-Settings" },
|
||
"zone": {
|
||
"name": "Zone-Name",
|
||
"nameExtra": "FQDN ohne führenden/abschließenden Punkt — z.B. internal.netcell-it.de",
|
||
"type": "Typ",
|
||
"typeLocal": "local — authoritativ (records hier)",
|
||
"typeForward": "forward — stub-zone zu fremdem Resolver",
|
||
"forwardTo": "Upstream-Resolver",
|
||
"forwardToExtra": "Komma-separierte IP-Liste — z.B. '10.0.0.53, 8.8.8.8'",
|
||
"description": "Beschreibung",
|
||
"records": "Records …",
|
||
"add": "Zone hinzufügen",
|
||
"edit": "Zone bearbeiten",
|
||
"deleteConfirm": "Zone {{name}} mit allen Records wirklich löschen?"
|
||
},
|
||
"record": {
|
||
"name": "Name",
|
||
"nameExtra": "Relativ zur Zone (z.B. 'mailcow') oder FQDN mit abschließendem Punkt.",
|
||
"type": "Typ",
|
||
"value": "Wert",
|
||
"valueExtra": "RDATA in Textform: A → IP, CNAME → FQDN, MX → 'priority host', TXT → 'string'.",
|
||
"ttl": "TTL (sec)",
|
||
"drawerTitle": "DNS-Records",
|
||
"add": "Record hinzufügen",
|
||
"edit": "Record bearbeiten",
|
||
"deleteConfirm": "Record {{name}} wirklich löschen?"
|
||
},
|
||
"settings": {
|
||
"intro": "Globale Resolver-Settings. Änderungen hier reloaden Unbound automatisch.",
|
||
"listenAddresses": "Listen-Adressen",
|
||
"listenAddressesPlaceholder": "IPs wählen (oder eintippen)",
|
||
"listenAddressesRequired": "Mindestens eine Adresse erforderlich.",
|
||
"listenAddressesExtra": "Mehrfachauswahl aus den IPs die der Kernel kennt. 127.0.0.1 + ::1 = nur lokal; weitere LAN-Iface-IPs (z.B. 10.10.20.3) öffnen den Resolver für LAN-Clients. Eigene IPs lassen sich auch eintippen (Enter).",
|
||
"listenPort": "Port",
|
||
"upstreamForwards": "Default-Forwarders",
|
||
"upstreamForwardsExtra": "Wo geht alles hin was nicht lokal ist. Default 1.1.1.1 + 9.9.9.9.",
|
||
"accessACL": "Access-ACL (CIDRs)",
|
||
"accessACLExtra": "Wer darf diesen Resolver benutzen.",
|
||
"dnssec": "DNSSEC validieren",
|
||
"qnameMin": "QName-Minimisation (privacy)",
|
||
"cacheMin": "Cache min-TTL",
|
||
"cacheMax": "Cache max-TTL"
|
||
}
|
||
},
|
||
"fwd": {
|
||
"title": "Forward-Proxy (Squid)",
|
||
"intro": "Squid-basierter Forward-Proxy auf :3128. ACLs werden top-down nach Priority ausgewertet — first-match wins. Wenn keine Regel passt, gewinnt der Default: nur localnet (10/8, 172.16/12, 192.168/16) darf raus.",
|
||
"helpTitle": "Tipp zur ACL-Reihenfolge",
|
||
"helpBody": "Höhere Priority = wird zuerst geprüft. Beispiel: 'deny .badsite.com' (priority 200) vor 'allow .com' (priority 100). Werte können Listen sein (mehrere Zeilen), Regex je nach acl_type.",
|
||
"name": "Name",
|
||
"nameExtra": "Squid-konformer Bezeichner — Kleinbuchstaben + _, kein Leerzeichen.",
|
||
"aclType": "Typ",
|
||
"aclTypeExtra": "Was Squid prüft (Quelle, Domain, Port, …).",
|
||
"value": "Wert",
|
||
"valueExtra": "Format hängt vom Typ ab — IPs/CIDRs für src/dst, Domain mit führendem . für dstdomain (.example.com matcht auch sub.example.com), Regex für *_regex-Typen.",
|
||
"action": "Aktion",
|
||
"priority": "Priority",
|
||
"priorityExtra": "Höher = wird zuerst geprüft.",
|
||
"comment": "Kommentar",
|
||
"add": "ACL hinzufügen",
|
||
"edit": "ACL bearbeiten",
|
||
"deleteConfirm": "ACL {{name}} wirklich löschen?"
|
||
},
|
||
"common": {
|
||
"yes": "Ja",
|
||
"no": "Nein",
|
||
"save": "Speichern",
|
||
"cancel": "Abbrechen",
|
||
"loading": "Lädt …",
|
||
"error": "Fehler",
|
||
"edit": "Bearbeiten",
|
||
"delete": "Löschen",
|
||
"deleteConfirm": "Wirklich löschen?",
|
||
"search": "Suchen …",
|
||
"totalRows": "{{count}} Einträge",
|
||
"active": "Aktiv",
|
||
"inactive": "Inaktiv",
|
||
"noData": "Keine Einträge",
|
||
"actions": "Aktionen",
|
||
"add": "Hinzufügen",
|
||
"download": "Download",
|
||
"copy": "Kopieren",
|
||
"copied": "Kopiert"
|
||
},
|
||
"license": {
|
||
"title": "Lizenz",
|
||
"status": "Status",
|
||
"product": "Produkt",
|
||
"key": "Lizenz-Schlüssel",
|
||
"noKey": "Kein Schlüssel hinterlegt",
|
||
"validUntil": "Gültig bis",
|
||
"expired": "Abgelaufen",
|
||
"daysLeft": "noch {{days}} Tage",
|
||
"lastVerifiedAt": "Letzte Verifizierung",
|
||
"verifiedBy": "Verifiziert von",
|
||
"limits": "Limits",
|
||
"unlimited": "Unbegrenzt",
|
||
"features": "Features",
|
||
"reverify": "Erneut prüfen",
|
||
"reverified": "Lizenz erfolgreich verifiziert",
|
||
"enterKey": "Schlüssel eingeben",
|
||
"replaceKey": "Schlüssel ersetzen",
|
||
"enterKeyHint": "Lizenz-Schlüssel aus dem Self-Service-Portal von license.netcell-it.com einfügen.",
|
||
"activate": "Aktivieren",
|
||
"saved": "Lizenz gespeichert und verifiziert",
|
||
"savedButVerifyFailed": "Schlüssel gespeichert, aber Server-Verifizierung fehlgeschlagen",
|
||
"clearKey": "Schlüssel entfernen",
|
||
"cleared": "Lizenz entfernt — System fällt auf Trial zurück",
|
||
"confirmClear": "Lizenz-Schlüssel wirklich entfernen?",
|
||
"confirmClearHint": "System fällt auf Trial-Modus zurück, sobald der Schlüssel gelöscht wird.",
|
||
"lastVerifyFailed": "Letzte Server-Verifizierung fehlgeschlagen",
|
||
"trialExpiring": "Trial läuft in {{days}} Tag(en) ab",
|
||
"trialExpiringHint": "Lizenz aktivieren, bevor die Trial-Periode endet."
|
||
},
|
||
"licenseBanner": {
|
||
"expired": "Lizenz abgelaufen oder ungültig.",
|
||
"trialExpiring": "Trial läuft in {{days}} Tag(en) ab.",
|
||
"verifyFailed": "Lizenz-Verifizierung fehlgeschlagen",
|
||
"cta": "Jetzt aktivieren →",
|
||
"openPage": "Lizenz-Seite öffnen →"
|
||
},
|
||
"fwlog": {
|
||
"title": "Firewall-Log (Live)",
|
||
"intro": "Pakete, die in nft-Regeln mit aktivem Log-Flag matchen, fließen via NFLOG → ulogd2 → JSONL hierher. WebSocket-Stream zeigt Live-Events; Ring-Buffer (1000) hält die letzten Treffer auch nach Reconnect.",
|
||
"live": "Live",
|
||
"disconnected": "getrennt",
|
||
"pause": "Pause",
|
||
"resume": "Fortsetzen",
|
||
"queued": "wartend",
|
||
"clear": "Leeren",
|
||
"clearTooltip": "Tabelle leeren (Server-Ringbuffer bleibt unverändert)",
|
||
"export": "CSV",
|
||
"exportTooltip": "Aktuelle Tabelle als CSV exportieren",
|
||
"exportEmpty": "Keine Events zum Exportieren",
|
||
"connError": "WebSocket-Fehler — versuche erneut",
|
||
"empty": "Noch keine Events. Aktiviere bei einer Firewall-Regel den Log-Schalter, dann fließen Treffer hier hinein.",
|
||
"connecting": "Verbinde …",
|
||
"col": {
|
||
"time": "Zeit",
|
||
"action": "Aktion",
|
||
"rule": "Rule",
|
||
"proto": "Proto",
|
||
"src": "Quelle",
|
||
"dst": "Ziel",
|
||
"iface": "Interface",
|
||
"size": "Größe"
|
||
},
|
||
"filter": {
|
||
"action": "Action filtern",
|
||
"proto": "Proto filtern",
|
||
"src": "Quell-IP",
|
||
"dst": "Ziel-IP",
|
||
"rule": "Rule-ID"
|
||
}
|
||
}
|
||
}
|