Refactor nginx to path-based domain model with config migration

Replace the legacy top-level management key with a unified paths-based
model. Each domain now contains a paths map where each entry defines its
own backend, auth, headers, and flags (is_management, is_websocket).

- Add _migrate_config() to auto-migrate legacy formats on first load
- Remove set_management_proxy() and POST_NGINX_MANAGEMENT endpoint
- Update server_block.conf template to iterate paths with per-location auth
- Update daemon handler, API blueprint, state collector, and install script
- Add server config generation tests for paths, WebSocket, auth inheritance
- Update frontend proxy page to display per-path rows with flags
This commit is contained in:
2026-06-27 23:34:06 +00:00
parent 8feb56faf6
commit 835326311b
14 changed files with 851 additions and 558 deletions
+16 -7
View File
@@ -636,7 +636,6 @@ def _collect_nginx() -> dict[str, Any]:
default_cfg: dict[str, Any] = {
"domains": {},
"management": None,
"ssl": deepcopy(DEFAULT_SSL),
}
cfg = deepcopy(default_cfg)
@@ -652,18 +651,27 @@ def _collect_nginx() -> dict[str, Any]:
except Exception:
pass
# Build domains list with site existence
# Build flattened domains list (one entry per path)
domains: list[dict[str, Any]] = []
for name, dom in cfg.get("domains", {}).items():
site = SITES_DIR / f"{name}.conf"
domains.append(
{
paths = dom.get("paths", {})
if not paths:
continue
for ppath, pcfg in paths.items():
entry: dict[str, Any] = {
"domain": name,
"backend": dom.get("backend", {}),
"path": ppath,
"backend": pcfg.get("backend", {}),
"online": site.exists() if SITES_DIR.exists() else False,
"force_ssl": dom.get("force_ssl", True),
"cert": dom.get("cert"),
}
)
if pcfg.get("is_management"):
entry["is_management"] = True
if pcfg.get("is_websocket"):
entry["is_websocket"] = True
domains.append(entry)
return {
"config": cfg,
@@ -819,7 +827,8 @@ def _collect_acme() -> dict[str, Any]:
if not main:
continue
san_domains = [
d.strip() for d in entry.get("san_domains", "").split(",")
d.strip()
for d in entry.get("san_domains", "").split(",")
if d.strip() and d.strip().lower() != "no"
]
cert_dir = acme_home / main