Add DNS accounts, Let's Encrypt, password change, reboot, HTTP redirect

- router.dnsProviders: named accounts at DNS providers, used by dynamic
  DNS and certificates (ddclient and lego provider lists in
  pkgs/router-webui/providers.json). Schema 2 migrates router.ddns.
- router.acme: a Let's Encrypt certificate for the web UI via
  security.acme (DNS-01, resolver 1.1.1.1), served and reloaded by the
  web UI; Certificate page.
- Web UI: password change (web UI and root), reboot button, HTTP to HTTPS
  redirect (router.webui.httpPort), grouped menu.
- Latest kernel (linuxPackages_latest); 7.3 and 7.3.0 are the same kernel
  for the reboot hint.
- SPECS.md: wanted later (REST API, GraphQL, MCP).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
2026-10-30 19:27:49 +01:00
co-authored by Claude Sonnet 5.5
parent a32bf42777
commit caf2c6b26d
33 changed files with 1985 additions and 224 deletions
+6
View File
@@ -114,6 +114,12 @@ Learned along the way:
- IPv6 has no NAT: it is opened only by explicit pinholes (`from = "wan"`, IPv6 `destination`). The prefix is dynamic, so v6 destinations are not checked against the zone.
- Tested in `basic`/`pppoe` (source preserved, toPort, ranges, sources, rate limit, v6 pinhole, hairpin, log lines) and in `assertions`; mutation-tested (source match, hairpin masquerade, rate limit).
## DNS accounts, dynamic DNS and certificates
- `router.dnsProviders` holds accounts at DNS providers by name (`type`, `username`, `server`, `secretFile`); the token is a private file (web UI: `/var/lib/router/dns-secrets/NAME`), never in settings or the store. `router.ddns.provider` and `router.acme.provider` refer to one. Schema 2 (`migrations/2.jq`) moves the old `ddns.protocol/server/username/passwordFile` into an account named after the protocol.
- `router.acme`: a Let's Encrypt certificate for the web UI through `security.acme` (lego), DNS-01 only (no open port, wildcards work), with providers that have one token: cloudflare, desec, digitalocean, duckdns, hetzner. Staging by default; `acceptTerms` must be set. The web UI serves `/var/lib/acme/<first name>/{fullchain,key}.pem` when present (reloaded when the files change, so renewals need no restart) and its self-signed certificate otherwise.
- Tested: assertions, the web UI forms (Go and VM), the certificate source and the migration. **Not tested: an order against Let's Encrypt** (needs a pebble test server or a real zone).
## Deployment and rollback (confirmed)
- **Router on a stick**: `wan.interface` may also carry LANs, but only for PPPoE on a VLAN with IPv6 disabled (the untagged link is then free for a LAN; native IPv6 needs an untagged uplink). In that mode only the PPP device is an uplink in the firewall, so LAN traffic can never match WAN rules; the WAN VLAN is created from the LAN's/trunk's networkd unit. A LAN VLAN may not reuse the PPPoE VLAN id.