{ "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", "logs": "Logs", "backups": "Backups", "diagnostics": "Diagnose", "alerts": "Alarme", "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", "live": "Live-Log", "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", "intro": "Interfaces (Ethernet/VLAN/Bond/Bridge) und Static-Routes. Live-Discovery + deklarative Konfiguration aus der DB.", "tabs": { "interfaces": "Interfaces", "routes": "Routen" }, "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 (KeyDB-AA + PG-Streaming-Replication + Leader-Election) folgt schrittweise.", "id": "Node-ID", "fqdn": "FQDN", "role": "Rolle", "joinedAt": "Beigetreten", "self": "diese Node", "drift": "Drift", "modeSingle": "Single-Node", "modeCluster": "Cluster", "health": { "ok": "OK", "degraded": "degraded", "split-brain": "split-brain" }, "selfTitle": "Dieser Knoten", "noSelf": "Selbst-Registrierung in ha_nodes fehlgeschlagen — Setup-Wizard durchlaufen.", "peersTitle": "Peers ({{count}})", "singleNodeTitle": "Single-Node-Modus", "singleNodeDesc": "Nur diese Box bekannt. Zusätzlicher Knoten? `edgeguard-ctl cluster-join` (kommt in Phase 3.2).", "driftBanner": "Config-Drift erkannt", "driftBannerDesc": "Ein oder mehrere Peers haben einen anderen Config-Hash als dieser Node. Entweder stehen noch Änderungen in der Outbox, oder auf einem Peer wurde direkt in der DB editiert. Warte bis die Outbox leer ist oder starte Diagnostics.", "col": { "node": "Knoten", "status": "Status", "role": "Rolle", "apiUrl": "API-URL", "configHash": "Config-Hash", "version": "Version", "lastSeen": "Last seen", "mgmtIp": "MGMT-IP" } }, "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 →" }, "routes": { "liveTitle": "Live-Routen (Kernel)", "liveIntro": "Aktueller Zustand aus `ip -j route show table all`. proto edgeguard markiert von EdgeGuard verwaltete Routen — andere Quellen (kernel/static/dhcp) bleiben unberührt.", "liveEmpty": "Keine Routen im Kernel.", "managedTitle": "Verwaltete Routen", "managedIntro": "Statische Routen, die EdgeGuard via `ip route … proto edgeguard` beim Boot setzt. Änderung hier triggert sofort `systemctl restart edgeguard-routes.service`.", "add": "Route hinzufügen", "addTitle": "Statische Route anlegen", "editTitle": "Statische Route bearbeiten", "empty": "Keine verwalteten Routen.", "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.", "gatewayExtra": "Optional. Leer = on-link via dev.", "devExtra": "Output-Interface. Bei Gateway-only kann ip das auflösen, explizit ist aber stabiler.", "metricExtra": "Niedriger gewinnt. Default 100. Standard-Linux-Defaults: dhcp 1024, kernel-link 0.", "tableExtra": "Routing-Table. main = Standard. Custom-Tables via /etc/iproute2/rt_tables.", "col": { "destination": "Ziel", "gateway": "Gateway", "dev": "Interface", "metric": "Metric", "table": "Table", "active": "Aktiv", "comment": "Kommentar", "proto": "Protokoll", "scope": "Scope", "src": "Quell-IP" } }, "alerts": { "title": "Health-Alarme", "intro": "Notification-Channels für kritische Events. Webhook (Slack/Discord/Teams/Generic-HTTP) oder Email (SMTP). Triggers: cert.expiring (<14 d), cert.renew_failed, backup.failed, license.invalid.", "scopeTitle": "Was triggert Alarme?", "scopeDesc": "cert.expiring — TLS-Zertifikat <14 Tage Restzeit (dedupe 12h). cert.renew_failed — ACME-Renewer hat Fails. backup.failed — Scheduled Backup konnte nicht erstellt werden. license.invalid — License-Server liefert valid=false. Mehr Triggers folgen (Backend-Down, Disk-Usage).", "tabs": { "channels": "Channels", "events": "History" }, "add": "Channel hinzufügen", "addTitle": "Notification-Channel anlegen", "editTitle": "Channel bearbeiten", "test": "Test-Alert", "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.", "noChannels": "kein Channel aktiv", "confirmDelete": "Channel {{name}} wirklich löschen?", "col": { "name": "Name", "kind": "Typ", "target": "Ziel", "targetWebhook": "Webhook-URL", "targetEmail": "Empfänger-Email", "active": "Aktiv", "time": "Zeit", "severity": "Severity", "subject": "Betreff", "delivered": "Gesendet" } }, "diag": { "title": "Diagnose", "intro": "Operator-Tools direkt aus dem UI: ping, traceroute, DNS, HTTP-Probe, TCP-Connect. Alle Calls laufen authentifiziert auf dieser Box (nicht im Browser).", "run": "Ausführen", "runFromBoxTitle": "Tools laufen auf der EdgeGuard-Box", "runFromBoxDesc": "Diese Aufrufe nutzen die Outbound-Connectivity der EdgeGuard — nicht deinen lokalen Rechner. Wenn ping/curl auf der Box scheitert, ist das Box-Network-Layer das Problem (Firewall-Rules, Default-Route, DNS).", "ping": { "intro": "ICMP echo-request × 4, 2s Timeout pro Paket. Misst Loss + RTT." }, "trace": { "intro": "Hop-by-Hop-Pfad mit UDP-Probes (max 20 Hops, kein reverse-DNS)." }, "dig": { "intro": "DNS-Lookup über unbound (Box-Resolver). Zeigt Antwort + AUTHORITY/ADDITIONAL Section." }, "curl": { "intro": "HTTPS-Probe mit -IsSv: TLS-Handshake-Details + Header. Folgt KEINE Redirects." }, "tcp": { "intro": "Pure TCP-Connect ohne I/O. Ideal um zu prüfen ob ein Backend-Port erreichbar ist." }, "securityTitle": "Sicherheits-Hinweis", "securityDesc": "Endpoints sind hinter Admin-Auth. Targets werden gegen eine strikte Allow-Liste validiert (keine Shell-Metazeichen). curl ist auf http(s) beschränkt — kein file:// / smb:// / data://." }, "backups": { "title": "Backups", "intro": "Sicherungen der PostgreSQL-Datenbank + /var/lib/edgeguard (Setup, License, JWT, ACME-Account). Täglicher Auto-Job + manueller Trigger.", "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.", "runNow": "Backup jetzt erstellen", "created": "Backup erstellt: {{file}}", "failed": "Backup fehlgeschlagen", "deleted": "Backup gelöscht", "download": "Download", "restore": "Wiederherstellen", "restoreOk": "Restore starten", "restoreDone": "Restore abgeschlossen — Seite wird neu geladen.", "restoreFailed": "Restore fehlgeschlagen", "restoreRunning": "Restore läuft …", "restoreHint": "edgeguard-api startet automatisch neu; die UI lädt nach Restart neu.", "confirmRestoreTitle": "Backup wiederherstellen?", "confirmRestoreDesc": "DB-Inhalt wird durch {{file}} ersetzt + State-Dateien zurückgespielt. edgeguard-api + scheduler restarten. Aktuelle Änderungen seit dem Backup gehen verloren.", "step": { "extract": "Tar entpacken", "psql": "DB-Restore (psql)", "render": "Configs re-rendern", "restart": "Services neu starten" }, "downloadTooltip": "tar.gz herunterladen", "refreshTooltip": "Liste neu laden", "confirmDelete": "Backup {{file}} wirklich löschen?", "empty": "Noch keine Backups. Klicke „Backup jetzt erstellen\" oder warte den nächsten Auto-Tick ab.", "failedTag": "FEHLER", "col": { "time": "Zeit", "file": "Datei", "kind": "Typ", "status": "Status", "size": "Größe", "duration": "Dauer" } }, "logs": { "title": "System-Logs", "intro": "Aggregierter Blick auf alle Service-Journals + audit_log. Multi-Source-Auswahl, Level-Filter, Freitext-Suche, Zeit-Range, Auto-Refresh (5s).", "autoOn": "Auto", "autoOff": "Manuell", "refresh": "Aktualisieren", "refreshTooltip": "Einmalig neu laden", "export": "CSV", "exportTooltip": "Aktuelle Tabelle als CSV exportieren", "exportEmpty": "Keine Einträge zum Exportieren", "found": "{{n}} Einträge", "limit": "Limit", "empty": "Keine Einträge gefunden. Quellen-Auswahl ändern oder Zeit-Range erweitern.", "col": { "time": "Zeit", "source": "Quelle", "level": "Level", "message": "Nachricht" }, "filter": { "sources": "Quellen wählen (alle wenn leer)", "levels": "Level filtern", "grep": "Volltext-Suche" } }, "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.", "start": "Live-Log starten", "stop": "Stop", "notStartedTitle": "Live-Log ist aus", "notStartedDesc": "Standardmäßig pausiert — Klick zum Verbinden lässt Events live einfließen.", "live": "Live", "disconnected": "verbinde …", "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" } } }