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:
+35
-67
@@ -17,7 +17,6 @@ from daemon.iface import (
|
||||
POST_NGINX_CONFIG,
|
||||
POST_NGINX_DOMAINS_ADD,
|
||||
POST_NGINX_DOMAINS_UPDATE,
|
||||
POST_NGINX_MANAGEMENT,
|
||||
POST_NGINX_SSL_APPLY,
|
||||
POST_NGINX_TEST,
|
||||
)
|
||||
@@ -140,7 +139,13 @@ def add_domain_bp():
|
||||
|
||||
POST /api/proxy/domains
|
||||
|
||||
Body fields:
|
||||
Body fields (paths mode):
|
||||
domain: Domain name.
|
||||
paths: Path-to-config map (e.g. ``{"/": {"backend": {...}}, "/app": {...}}``).
|
||||
cert: Optional certificate type.
|
||||
force_ssl: Optional SSL redirect flag (default ``true``).
|
||||
|
||||
Body fields (legacy mode):
|
||||
domain: Domain name.
|
||||
backend_host: Upstream host.
|
||||
backend_port: Upstream port.
|
||||
@@ -153,29 +158,37 @@ def add_domain_bp():
|
||||
"""
|
||||
body = request.get_json(silent=True) or {}
|
||||
domain = body.get("domain", "").strip()
|
||||
backend_host = body.get("backend_host", "").strip()
|
||||
backend_port = body.get("backend_port")
|
||||
backend_proto = body.get("backend_proto", "http").strip() or "http"
|
||||
cert = body.get("cert")
|
||||
extra_headers = body.get("extra_headers")
|
||||
if not domain:
|
||||
return _error("'domain' is required", 400)
|
||||
if not backend_host:
|
||||
return _error("'backend_host' is required", 400)
|
||||
if backend_port is None:
|
||||
return _error("'backend_port' is required", 400)
|
||||
|
||||
paths = body.get("paths")
|
||||
if paths is not None:
|
||||
payload = {
|
||||
"domain": domain,
|
||||
"paths": paths,
|
||||
"cert": body.get("cert"),
|
||||
"force_ssl": body.get("force_ssl", True),
|
||||
}
|
||||
else:
|
||||
backend_host = body.get("backend_host", "").strip()
|
||||
backend_port = body.get("backend_port")
|
||||
backend_proto = body.get("backend_proto", "http").strip() or "http"
|
||||
cert = body.get("cert")
|
||||
extra_headers = body.get("extra_headers")
|
||||
if not backend_host:
|
||||
return _error("'backend_host' is required", 400)
|
||||
if backend_port is None:
|
||||
return _error("'backend_port' is required", 400)
|
||||
payload = {
|
||||
"domain": domain,
|
||||
"backend_host": backend_host,
|
||||
"backend_port": int(backend_port),
|
||||
"backend_proto": backend_proto,
|
||||
"cert": cert,
|
||||
"extra_headers": extra_headers,
|
||||
}
|
||||
try:
|
||||
post(
|
||||
POST_NGINX_DOMAINS_ADD,
|
||||
{
|
||||
"domain": domain,
|
||||
"backend_host": backend_host,
|
||||
"backend_port": int(backend_port),
|
||||
"backend_proto": backend_proto,
|
||||
"cert": cert,
|
||||
"extra_headers": extra_headers,
|
||||
},
|
||||
)
|
||||
post(POST_NGINX_DOMAINS_ADD, payload)
|
||||
logger.info("Proxy domain added via API: %s", domain)
|
||||
return _ok({"domain": domain})
|
||||
except BadRequest as exc:
|
||||
@@ -272,48 +285,3 @@ def test_bp():
|
||||
except RuntimeError as exc:
|
||||
logger.error("nginx config test failed: %s", exc)
|
||||
return _error(str(exc), 500)
|
||||
|
||||
|
||||
@bp.route("/management", methods=["POST"])
|
||||
def management_bp():
|
||||
"""Configure the management reverse proxy for the WebUI.
|
||||
|
||||
POST /api/proxy/management
|
||||
|
||||
Body fields:
|
||||
domain: Management domain name.
|
||||
flask_host: Upstream Flask host (default ``127.0.0.1``).
|
||||
flask_port: Upstream Flask port (default 9090).
|
||||
auth_user: Optional basic-auth username.
|
||||
auth_pass: Optional basic-auth password.
|
||||
|
||||
Returns:
|
||||
``{"ok": true}`` on success.
|
||||
"""
|
||||
body = request.get_json(silent=True) or {}
|
||||
domain = body.get("domain", "").strip()
|
||||
if not domain:
|
||||
return _error("'domain' is required", 400)
|
||||
flask_host = body.get("flask_host", "127.0.0.1").strip() or "127.0.0.1"
|
||||
flask_port = body.get("flask_port", 9090)
|
||||
auth_user = body.get("auth_user")
|
||||
auth_pass = body.get("auth_pass")
|
||||
try:
|
||||
post(
|
||||
POST_NGINX_MANAGEMENT,
|
||||
{
|
||||
"domain": domain,
|
||||
"flask_host": flask_host,
|
||||
"flask_port": int(flask_port),
|
||||
"auth_user": auth_user,
|
||||
"auth_pass": auth_pass,
|
||||
},
|
||||
)
|
||||
logger.info("Management proxy configured via API: %s", domain)
|
||||
return _ok(None)
|
||||
except BadRequest as exc:
|
||||
logger.info("Management proxy config rejected: %s", exc)
|
||||
return _error(str(exc), 400)
|
||||
except RuntimeError as exc:
|
||||
logger.error("Failed to set management proxy: %s", exc)
|
||||
return _error(str(exc), 500)
|
||||
|
||||
Reference in New Issue
Block a user