Files
edgeguard-native/management-ui/src/i18n/locales/en/common.json
Debian e4d83d226e feat: NTP-Server (Chrony) — vollständig
Stub raus, vollständige Implementierung analog Unbound/Squid:

* Migration 0015: ntp_settings (single-row mit listen_addresses,
  allow_acl, serve_clients, makestep, rtcsync) + ntp_pools (kind
  pool|server, address, iburst/prefer, minpoll/maxpoll). Default
  4 deutsche pool.ntp.org-Server seeded.
* Models DNSSettings/NTPPool, services/ntp Repo, handlers/ntp.go
  REST /api/v1/ntp/{settings,pools} mit Auto-Restart nach Mutation.
* internal/chrony/chrony.cfg.tpl + chrony.go: Renderer schreibt
  /etc/chrony/conf.d/edgeguard.conf direkt (analog unbound — distro
  chrony.conf included conf.d automatisch). Listen-bind nur wenn
  serve_clients=true; sonst port 0 (= Client-only).
* main.go: ntpRepo + chronyReloader injiziert.
* render.go: chrony als sechste generator.
* postinst:
  - chrony als hard Depends im control file.
  - Conf-Datei /etc/chrony/conf.d/edgeguard.conf wird als
    edgeguard:edgeguard 0644 angelegt.
  - Sudoers für systemctl reload + restart chrony.
* Auto-FW-Rule-Generator: udp/123 wenn serve_clients=true und
  listen_addresses non-loopback enthält.
* Frontend /ntp: PageHeader + Quellen-Tab + Settings-Tab. Listen-
  Addresses als Multi-Select aus Kernel-IPs (analog DNS).
* Sidebar-Eintrag unter Network.
* i18n DE/EN für ntp.* Block.

chrony.service hat kein 'reload' — Renderer ruft RestartService auf.

Verified: 4 default-pool-server connected (chronyc sources zeigt
sie nach erstem render).

Version 1.0.40.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:58:54 +02:00

530 lines
22 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"app": {
"title": "EdgeGuard",
"subtitle": "Native reverse-proxy / VPN / firewall"
},
"nav": {
"dashboard": "Dashboard",
"domains": "Domains",
"backends": "Backends",
"routing": "Routing",
"networks": "Network interfaces",
"ipAddresses": "IP addresses",
"ssl": "SSL certificates",
"vpn": "VPN",
"wireguard": "WireGuard",
"forwardProxy": "Forward proxy",
"dns": "DNS",
"ntp": "Time (NTP)",
"firewall": "Firewall",
"cluster": "Cluster",
"settings": "Settings",
"section": {
"overview": "Overview",
"routing": "Routing",
"network": "Network",
"security": "Security",
"system": "System"
}
},
"fw": {
"title": "Firewall",
"intro": "Fortigate-style: rules built from zones × address objects/groups × services/service groups × action. NAT is separate. Top-down, first-match.",
"tabs": {
"rules": "Rules",
"nat": "NAT",
"zones": "Zones",
"addrObj": "Address objects",
"addrGrp": "Address groups",
"services": "Services",
"svcGrp": "Service groups"
},
"zone": {
"name": "Name",
"description": "Description",
"builtin": "built-in",
"builtinHint": "Built-in zones cannot be deleted — the renderer and anti-lockout rules depend on them.",
"builtinNameLocked": "Name is built-in — cannot be changed because existing rules and interfaces reference it.",
"namePattern": "Lowercase letters, digits, _ and -; must start with a letter, up to 32 chars.",
"add": "Add zone",
"edit": "Edit zone",
"deleteConfirm": "Really delete zone {{name}}?"
},
"ao": {
"name": "Name", "kind": "Kind", "value": "Value", "description": "Description",
"add": "Add address object", "edit": "Edit address object",
"deleteConfirm": "Really delete address object {{name}}?"
},
"ag": {
"name": "Name", "members": "Members", "description": "Description",
"add": "Add address group", "edit": "Edit address group",
"selectMembers": "Select address objects",
"deleteConfirm": "Really delete address group {{name}}?"
},
"svc": {
"name": "Name", "proto": "Protocol", "ports": "Ports",
"portStart": "Port (start)", "portEnd": "Port (end)",
"description": "Description", "builtinHint": "Built-in — not editable",
"add": "Add service", "edit": "Edit service",
"deleteConfirm": "Really delete service {{name}}?"
},
"sg": {
"name": "Name", "members": "Members", "description": "Description",
"add": "Add service group", "edit": "Edit service group",
"selectMembers": "Select services",
"deleteConfirm": "Really delete service group {{name}}?"
},
"rule": {
"name": "Name", "priority": "Priority", "enabled": "Enabled", "log": "Log",
"action": "Action", "src": "Source", "dst": "Destination", "service": "Service",
"srcZone": "Source zone", "dstZone": "Dest. zone",
"srcKind": "Source kind", "dstKind": "Dest. kind",
"object": "Address object", "group": "Address group",
"serviceKind": "Service kind", "serviceGroup": "Service group",
"comment": "Comment",
"add": "Add rule", "edit": "Edit rule",
"deleteConfirm": "Really delete this rule?"
},
"nat": {
"name": "Name", "priority": "Priority", "kind": "Kind", "enabled": "Enabled",
"match": "Match", "target": "Target",
"inZone": "Ingress zone", "outZone": "Egress zone", "proto": "Protocol",
"matchSrcCidr": "Source CIDR (match)", "matchDstCidr": "Dest. CIDR (match)",
"matchDstCidrHint": "empty = any dest IP (e.g. box's public IP)",
"dportStart": "Port (start)", "dportEnd": "Port (end)",
"targetAddr": "Target address", "targetPortStart": "Target port (start)", "targetPortEnd": "Target port (end)",
"comment": "Comment",
"add": "Add NAT rule", "edit": "Edit NAT rule",
"deleteConfirm": "Really delete this NAT rule?"
},
"sys": {
"title": "System rules (always active)",
"chain": "Chain", "match": "Match", "action": "Action", "note": "Note",
"policy": "Default policy",
"policyValue": "Input DROP — everything must be explicitly allowed.",
"order": "Evaluation",
"orderValue": "System rules first, then operator rules top-down (priority asc, first-match).",
"lockout": "Anti-lockout",
"lockoutValue": "SSH (22) and the management UI (443) are always reachable — even the operator can't accidentally lock themselves out."
}
},
"networks": {
"title": "Network interfaces",
"intro": "Manage WAN, LAN, VLAN and bond interfaces. Read-only kernel discovery above; declared configuration below — runtime apply via systemd-networkd lands in a later release.",
"systemDiscovered": "System interfaces (read-only)",
"addInterface": "Add interface",
"editInterface": "Edit interface",
"name": "Name",
"type": "Type",
"parent": "Parent interface",
"selectParent": "Select parent",
"vlan": "VLAN",
"vlanId": "VLAN ID",
"composition": "Composition",
"members": "Member interfaces",
"selectMembers": "Select physical interfaces",
"membersRequired": "At least one member interface is required",
"membersHintBridge": "A bridge joins multiple physical ports at L2 — typically two ports for a software switch.",
"membersHintBond": "A bond aggregates multiple physical ports into one logical link (LACP / active-backup).",
"role": "Zone",
"roleHint": "Zones are managed in Firewall → Zones. Custom zones (e.g. iot, guest) can be added there.",
"mtu": "MTU",
"active": "Active",
"description": "Description",
"actions": "Actions",
"deleteConfirm": "Really delete interface {{name}}?"
},
"ips": {
"title": "IP addresses",
"intro": "Addresses the kernel currently has (read-only above) plus addresses EdgeGuard additionally manages — including VIPs that follow the active cluster node on failover.",
"systemDiscovered": "Kernel addresses (read-only)",
"managedTitle": "Managed addresses",
"family": "Family",
"addAddress": "Add address",
"editAddress": "Edit address",
"interface": "Interface",
"selectInterface": "Select interface",
"address": "Address",
"prefix": "Prefix",
"vip": "VIP",
"vipFlag": "Mark as VIP",
"vipPriority": "VIP priority (cluster failover)",
"active": "Active",
"description": "Description",
"actions": "Actions",
"deleteConfirm": "Really delete address {{addr}}?"
},
"auth": {
"loginTitle": "Sign in",
"email": "Email",
"password": "Password",
"login": "Sign in",
"logout": "Sign out",
"loginFailed": "Sign-in failed",
"loggedInAs": "Signed in as"
},
"setup": {
"title": "First-time setup",
"intro": "Create the admin account, declare the public FQDN, and — optionally — paste a license key. Without one, a 30-day trial starts.",
"adminEmail": "Admin email",
"adminPassword": "Admin password",
"passwordRule": "At least 12 characters.",
"fqdn": "Public FQDN",
"acmeEmail": "ACME / Let's Encrypt email",
"licenseKey": "License key (optional)",
"submit": "Finish setup",
"successTitle": "Setup complete",
"successHint": "Redirecting you to sign-in."
},
"dashboard": {
"title": "Dashboard",
"welcomeHint": "Overview of all running EdgeGuard components."
},
"domains": {
"title": "Domains",
"intro": "Manage FQDNs that HAProxy terminates. Optional primary backend as catch-all; path-based routing via routing rules.",
"addDomain": "Add domain",
"editDomain": "Edit domain",
"name": "Name",
"active": "Active",
"primaryBackend": "Primary backend",
"primaryBackendHint": "Catch-all backend for requests with no matching routing rule. Optional — leave empty if all traffic is routed via routing rules.",
"selectBackend": "Select backend",
"noBackend": "no backend",
"httpToHttps": "HTTP→HTTPS",
"hsts": "HSTS",
"notes": "Notes",
"actions": "Actions",
"edit": "Edit",
"delete": "Delete",
"deleteConfirm": "Really delete domain {{name}}?"
},
"backends": {
"title": "Backends",
"intro": "Upstream servers HAProxy proxies to. Optional health-check path enables TCP + HTTP probes every 5s.",
"addBackend": "Add backend",
"editBackend": "Edit backend",
"name": "Name",
"scheme": "Scheme",
"address": "Address",
"port": "Port",
"target": "Target",
"healthCheck": "Health check path",
"active": "Active",
"usedBy": "Used by",
"noDomain": "no domain",
"attachedDomains": "Domains",
"attachedDomainsHint": "Domains that use this backend as their primary. Selecting domains here reconfigures them directly — same source of truth as the Domain modal's backend picker.",
"selectDomains": "Select domains",
"actions": "Actions",
"deleteConfirm": "Really delete backend {{name}}?"
},
"routing": {
"title": "Routing rules",
"intro": "Path-prefix → backend mapping per domain. Lowest priority wins; catch-all via domain.primary_backend.",
"addRule": "Add rule",
"editRule": "Edit rule",
"domain": "Domain",
"pathPrefix": "Path prefix",
"backend": "Backend",
"priority": "Priority",
"active": "Active",
"actions": "Actions",
"selectDomain": "Select domain",
"selectBackend": "Select backend",
"deleteConfirm": "Really delete this routing rule?"
},
"cluster": {
"title": "Cluster",
"intro": "{{count}} node(s) registered. Multi-node cluster (KeyDB Active-Active + PG streaming replication) coming in a later release.",
"id": "Node ID",
"fqdn": "FQDN",
"role": "Role",
"joinedAt": "Joined",
"self": "this node"
},
"ssl": {
"title": "SSL certificates",
"intro": "Manage TLS certs — let EdgeGuard issue them via Let's Encrypt or upload your own PEM. HAProxy reloads automatically after each change.",
"tabLE": "Let's Encrypt",
"tabUpload": "Custom certificate",
"leIntro": "Pick a domain, click Issue — EdgeGuard solves HTTP-01 over the ACME webroot, writes the PEM into /etc/edgeguard/tls/, and reloads HAProxy.",
"uploadIntro": "Upload your own certificate. Format: PEM-encoded. Cert + optional chain + private key. EdgeGuard validates cert/key match before writing.",
"uploadHint": "Tip: for Let's Encrypt renewals don't upload here — use the LE tab.",
"domain": "Domain",
"selectDomain": "Pick or type a domain",
"domainExtra": "Includes the management FQDN (from Setup), cluster nodes and operator domains. You can also type any other domain — as long as DNS resolves to this box.",
"fqdnHintMgmt": "management FQDN",
"fqdnHintCluster": "cluster · {{role}}",
"issuer": "Issuer",
"status": "Status",
"expiresIn": "Expires in",
"expiredAgo": "expired {{days}} days ago",
"actions": "Actions",
"issueButton": "Issue certificate",
"uploadButton": "Upload",
"issueSuccess": "Certificate issued + installed.",
"uploadSuccess": "Certificate uploaded + installed.",
"deleteConfirm": "Delete certificate for {{domain}}? HAProxy falls back to the default cert for this domain.",
"installedTitle": "Installed certificates",
"certPem": "Certificate (PEM)",
"chainPem": "Chain (PEM, optional)",
"keyPem": "Private key (PEM)"
},
"settings": {
"title": "Settings",
"intro": "System information and setup status. Editable values come in a later release.",
"systemInfo": "System",
"version": "Version",
"status": "Status",
"setupInfo": "Setup",
"adminEmail": "Admin email",
"fqdn": "FQDN",
"setupCompleted": "Setup completed"
},
"update": {
"available": "Update available: {{pkg}} {{installed}} → {{available}}",
"applyNow": "Apply now",
"applying": "Update in progress …",
"started": "Update has started — the server will restart shortly."
},
"wg": {
"title": "WireGuard",
"intro": "WireGuard VPN tunnels. Server mode = we listen for peers; client mode = we dial out to a fixed upstream. Private keys are encrypted at rest.",
"tabs": { "servers": "Server tunnels", "clients": "Client tunnels" },
"serverIntro": "Server tunnels host a peer roster — typically employee devices or branch sites. Each peer can be downloaded as a wg-quick.conf or scanned as a QR code.",
"clientIntro": "Client tunnels connect EdgeGuard to a remote WireGuard server (e.g. HQ datacenter). Allowed IPs control which traffic is routed through the tunnel.",
"iface": {
"name": "Name",
"namePattern": "wg followed by lowercase letters/digits/-, max 15 chars",
"nameExtra": "Suggested: wg0, wg1, wg-hq …",
"address": "Address (CIDR)",
"addressExtra": "Box's tunnel IP, e.g. 10.99.0.1/24 for a /24 pool",
"listenPort": "Listen port",
"publicKey": "Public key",
"privateKey": "Private key (paste)",
"privateKeyExtra": "Fill in only if not auto-generating — base64 32 bytes. Stored encrypted.",
"peerEndpoint": "Peer endpoint",
"peerPublicKey": "Peer public key",
"peerPSK": "Pre-shared key (PSK)",
"peerPSKExtra": "Optional extra layer",
"allowedIPs": "Allowed IPs",
"allowedIPsExtra": "What gets routed through the tunnel. Default = full tunnel.",
"keepalive": "Persistent keepalive (sec)",
"mtu": "MTU",
"zone": "Firewall zone",
"description": "Description",
"addServer": "Add server tunnel",
"editServer": "Edit server tunnel",
"addClient": "Add client tunnel",
"editClient": "Edit client tunnel",
"upstream": "Upstream peer",
"deleteConfirm": "Really delete tunnel {{name}}? wg-quick will be stopped.",
"keys": "Keys",
"generateExtra": "If on: server generates a fresh Curve25519 keypair on save.",
"generateOn": "Server-generated",
"generateOff": "Manual paste",
"editKeyWarning": "Warning: new keys invalidate all existing peer configs. Only change if intentional."
},
"peers": {
"button": "Peers",
"drawerTitle": "Peer roster"
},
"peer": {
"name": "Name",
"publicKey": "Public key",
"publicKeyExtra": "Generated by the peer device; only paste here if the peer already has a keypair.",
"allowedIPs": "Allowed IPs",
"allowedIPsExtra": "Which tunnel IPs this peer is allowed to use. Typically /32 = one IP.",
"keepalive": "Keepalive (sec)",
"keepaliveExtra": "0 = off. Recommended 25 behind NAT.",
"lastHandshake": "Last handshake",
"never": "never",
"description": "Description",
"add": "Add peer",
"edit": "Edit peer",
"deleteConfirm": "Really remove peer {{name}}?",
"keys": "Keys",
"generateExtra": "If on: server generates a keypair for this peer and can hand out the config / QR. If off: paste the peer's public key only — no config download.",
"pskExtra": "If on: server generates a 32-byte PSK for this peer.",
"pskOn": "Generate PSK",
"pskOff": "no PSK",
"downloadConf": "Download wg-quick.conf",
"qrTitle": "WireGuard QR",
"qrHint": "Scan with the WireGuard app (iOS/Android): \"Add tunnel\" → \"Scan QR code\". Replace the Endpoint placeholder in the downloaded conf before use.",
"online": "Online",
"offline": "Offline",
"traffic": "Traffic"
}
},
"dashboard": {
"title": "Dashboard",
"welcomeHint": "EdgeGuard overview — health, counts, live status of the major services.",
"kpi": {
"domains": "Domains",
"backends": "Backends",
"ifaces": "Interfaces",
"fwRules": "FW rules",
"natRules": "NAT rules",
"wg": "WG connections"
},
"wgCard": {
"title": "WireGuard",
"empty": "No WG tunnel configured yet."
},
"firewallCard": {
"title": "Firewall",
"zones": "Zones",
"activeRules": "{{rules}} active rules · {{nat}} NAT"
},
"sslCard": {
"title": "SSL certificates",
"total": "Managed certificates",
"expiringSoon": "{{count}} expiring soon (< 30 days)",
"allFresh": "All certs have > 30 days remaining."
},
"clusterCard": {
"title": "Cluster",
"nodes": "Nodes"
},
"routingCard": {
"title": "Routing",
"domains": "Domains",
"backends": "Backends",
"attached": "{{count}}/{{total}} domains have a primary backend"
},
"systemCard": {
"title": "System",
"version": "Version",
"api": "API",
"ifaces": "Interfaces",
"wg": "WireGuard"
}
},
"ntp": {
"title": "Time server (Chrony)",
"intro": "Chrony as time-sync daemon (NTP). Sources on top, listen/serve config on the settings tab. With 'serve_clients' on and LAN-IPs bound, the box itself becomes an NTP server for the LAN.",
"tabs": { "pools": "Sources", "settings": "Settings" },
"pool": {
"kind": "Type",
"kindPool": "pool — DNS round-robin (multiple servers from A records)",
"kindServer": "server — single host",
"address": "Address / host",
"addressExtra": "FQDN (for pool: 0.de.pool.ntp.org) or IP.",
"iburst": "iburst",
"prefer": "prefer",
"minpoll": "min-poll",
"maxpoll": "max-poll",
"options": "Options",
"description": "Description",
"add": "Add source",
"edit": "Edit source",
"deleteConfirm": "Really delete NTP source {{addr}}?"
},
"settings": {
"intro": "Global chrony settings. Saves reload chrony automatically.",
"serveClients": "Act as NTP server for clients",
"serveClientsExtra": "If off: chrony acts as client only (port 0). If on + listen IP: binds UDP/123.",
"listenAddresses": "Listen addresses",
"listenAddressesPlaceholder": "Pick IPs (or type)",
"listenAddressesExtra": "Which IPs chrony binds :123/UDP on. 127.0.0.1+::1 = local only; LAN IPs open for LAN clients (FW rule auto-generated).",
"allowACL": "Allow ACL (CIDRs)",
"allowACLExtra": "Who is allowed to ask for NTP time.",
"makestepSecs": "makestep secs",
"makestepSecsExtra": "Allow step (vs. slew) when offset > N seconds.",
"makestepLimit": "makestep limit",
"rtcsync": "Sync RTC with system time",
"rtcsyncExtra": "Keep hardware clock in sync every 11 min — after reboot time is roughly correct.",
"leapsectz": "Leap-sec TZ",
"leapsectzExtra": "Optional, e.g. 'right/UTC' for leap-sec via tzdata."
}
},
"dns": {
"title": "DNS (Unbound)",
"intro": "Unbound resolver on :53. Local zones (authoritative from DNS records) and forward zones (stub-zone to remote resolvers). Default forwarders catch everything else.",
"tabs": { "zones": "Zones", "settings": "Resolver settings" },
"zone": {
"name": "Zone name",
"nameExtra": "FQDN without leading/trailing dot — e.g. internal.netcell-it.de",
"type": "Type",
"typeLocal": "local — authoritative (records here)",
"typeForward": "forward — stub-zone to remote resolver",
"forwardTo": "Upstream resolvers",
"forwardToExtra": "Comma-separated IP list — e.g. '10.0.0.53, 8.8.8.8'",
"description": "Description",
"records": "Records …",
"add": "Add zone",
"edit": "Edit zone",
"deleteConfirm": "Really delete zone {{name}} and all its records?"
},
"record": {
"name": "Name",
"nameExtra": "Relative to zone (e.g. 'mailcow') or FQDN with trailing dot.",
"type": "Type",
"value": "Value",
"valueExtra": "RDATA in text form: A → IP, CNAME → FQDN, MX → 'priority host', TXT → 'string'.",
"ttl": "TTL (sec)",
"drawerTitle": "DNS records",
"add": "Add record",
"edit": "Edit record",
"deleteConfirm": "Really delete record {{name}}?"
},
"settings": {
"intro": "Global resolver settings. Saves reload Unbound automatically.",
"listenAddresses": "Listen addresses",
"listenAddressesPlaceholder": "Pick IPs (or type)",
"listenAddressesRequired": "At least one address required.",
"listenAddressesExtra": "Multi-select from kernel-discovered IPs. 127.0.0.1 + ::1 = local only; LAN iface IPs (e.g. 10.10.20.3) open the resolver to LAN clients. You can also type custom IPs (Enter).",
"listenPort": "Port",
"upstreamForwards": "Default forwarders",
"upstreamForwardsExtra": "Where everything not local goes. Default 1.1.1.1 + 9.9.9.9.",
"accessACL": "Access ACL (CIDRs)",
"accessACLExtra": "Who is allowed to use this resolver.",
"dnssec": "DNSSEC validation",
"qnameMin": "QName minimisation (privacy)",
"cacheMin": "Cache min-TTL",
"cacheMax": "Cache max-TTL"
}
},
"fwd": {
"title": "Forward proxy (Squid)",
"intro": "Squid-based forward proxy on :3128. ACLs are evaluated top-down by priority — first match wins. If no rule matches, the default permits only localnet (10/8, 172.16/12, 192.168/16).",
"helpTitle": "ACL ordering tip",
"helpBody": "Higher priority = evaluated first. Example: 'deny .badsite.com' (priority 200) before 'allow .com' (priority 100). Values can be lists (multiple lines), regex depending on acl_type.",
"name": "Name",
"nameExtra": "Squid-conformant identifier — lowercase + _, no spaces.",
"aclType": "Type",
"aclTypeExtra": "What Squid matches (source, domain, port, …).",
"value": "Value",
"valueExtra": "Format depends on type — IPs/CIDRs for src/dst, domain with leading dot for dstdomain (.example.com also matches sub.example.com), regex for *_regex types.",
"action": "Action",
"priority": "Priority",
"priorityExtra": "Higher = evaluated first.",
"comment": "Comment",
"add": "Add ACL",
"edit": "Edit ACL",
"deleteConfirm": "Really delete ACL {{name}}?"
},
"common": {
"yes": "Yes",
"no": "No",
"save": "Save",
"cancel": "Cancel",
"loading": "Loading …",
"error": "Error",
"edit": "Edit",
"delete": "Delete",
"deleteConfirm": "Really delete?",
"search": "Search …",
"totalRows": "{{count}} rows",
"active": "Active",
"inactive": "Inactive",
"noData": "No data",
"actions": "Actions",
"add": "Add",
"download": "Download",
"copy": "Copy",
"copied": "Copied"
}
}