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
+13
View File
@@ -0,0 +1,13 @@
// Menus close on a click elsewhere; forms with data-confirm ask first.
// Close an open menu when the click is somewhere else.
document.addEventListener("click", function (e) {
document.querySelectorAll("nav details[open]").forEach(function (d) {
if (!d.contains(e.target)) d.removeAttribute("open");
});
});
// Ask before a form marked data-confirm is sent.
document.addEventListener("submit", function (e) {
var q = e.target.getAttribute("data-confirm");
if (q && !confirm(q)) e.preventDefault();
});
+6
View File
@@ -7,6 +7,12 @@ body { margin: 0; font: 15px/1.5 system-ui, sans-serif; color: var(--fg); backgr
header { display: flex; gap: 1.5rem; align-items: center; padding: .75rem 1rem; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
nav { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
nav form { display: inline; }
nav details { position: relative; }
nav summary { cursor: pointer; color: var(--accent); list-style: none; }
nav summary::-webkit-details-marker { display: none; }
nav summary::after { content: " \25BE"; }
nav details > div { position: absolute; z-index: 10; top: 1.6rem; left: -.75rem; min-width: 11rem; display: flex; flex-direction: column; gap: .35rem;
padding: .6rem .75rem; background: var(--bg); border: 1px solid var(--line); border-radius: 6px; box-shadow: 0 4px 12px rgba(0, 0, 0, .15); }
a { color: var(--accent); }
main { max-width: 72rem; margin: 0 auto; padding: 1rem; }
h1 { font-size: 1.4rem; margin: .5rem 0 1rem; }