.TH MAGLEVD\-FRONTEND 8 "April 2026" "vpp\-maglev" "System Administration" .SH NAME maglevd\-frontend \- web dashboard for one or more running maglevd instances .SH SYNOPSIS .B maglevd\-frontend \fB\-server\fR \fIaddr\fR[,\fIaddr\fR...] [\fB\-listen\fR \fIaddr\fR] [\fB\-log\-level\fR \fIlevel\fR] [\fB\-version\fR] .SH DESCRIPTION .B maglevd\-frontend is a single\-binary web dashboard that connects to one or more running .BR maglevd (8) instances over gRPC and renders a live view of frontends, backends, health checks, and VPP load\-balancer state. The SolidJS SPA is embedded into the Go binary via .BR embed.FS , so no runtime file dependencies are required; pointing the binary at one or more maglevds with .B \-server is enough to serve the dashboard. .PP For each configured maglevd, .B maglevd\-frontend maintains: .IP \(bu 2 A long\-lived .B WatchEvents gRPC stream subscribed at .BR log_level=debug , which delivers backend transitions, frontend transitions, per\-probe log records (used to drive the live probe heartbeat), and per\-mutation VPP LB sync records so the UI reflects every dataplane change in real time. .IP \(bu 2 A 30\-second refresh loop that re\-fetches .BR ListFrontends / GetFrontend , .BR ListBackends / GetBackend , .BR ListHealthChecks / GetHealthCheck , and .B GetVPPInfo as a safety net against missed events. .IP \(bu 2 A 5\-second health probe that surfaces maglevd connection drops quickly and flips the scope\-selector indicator dot red. .PP Browsers connect to .B maglevd\-frontend over HTTP. State is hydrated once via REST and then kept live via a Server\-Sent Events stream. Short SSE disconnects (nginx idle timeout, wifi flap, laptop wake) are handled silently via a 30\-second replay ring buffer; longer outages fall through to a full refetch. The SPA is stateless on reload so refreshing the page at any time returns a consistent view. .PP The frontend exposes two base paths: .B /view/ is the read\-only dashboard and serves without authentication; .B /admin/ is a basic\-auth\-protected variant of the same SPA that exposes lifecycle mutations (pause / resume / enable / disable a backend, set configured weight within a pool). The admin surface is only mounted when both .B MAGLEV_FRONTEND_USER and .B MAGLEV_FRONTEND_PASSWORD are set to non\-empty values at startup; otherwise .B /admin/ returns 404 and the SPA hides the admin\-toggle button entirely. .PP Per\-user persistent state lives in two cookies: .B maglev_scope remembers which maglevd the user was last looking at (hydrated on page load and reconciled against the fetched server list, so a removed/renamed maglevd falls through cleanly instead of leaving a ghost selection), and .B maglev_zippy_open remembers which collapsible cards are open, scoped per\-maglevd so opening a frontend card on one server doesn't affect the equivalent card on another. Both are .BR "Path=/; Max-Age=1y; SameSite=Lax" , are best\-effort (a missing or corrupt value just falls back to "everything closed" / "first maglevd"), and hold no sensitive data. .PP The SPA shows a health\-cascade icon next to every frontend name: .B \(OK for fully healthy, a double\-bang for a control\-plane vs dataplane disagreement (eff_weight > 0 but zero VPP buckets), an exclamation mark for a fully\-drained primary pool, a warning triangle for any backend not in .B up state, and a question mark as a fallthrough for logic bugs in the cascade. The .B "lb buckets" column on each backend row reports VPP's Maglev hash table share for that AS, debounced to at most one .B GetVPPLBState fetch per second per maglevd and refreshed live on every backend transition or weight edit. .SH OPTIONS Each flag may also be supplied via an environment variable (shown in parentheses); the flag takes precedence when both are set. All env vars are prefixed with .B MAGLEV_FRONTEND_ so a single env file can be shared with .BR maglevd (8) without variables leaking across processes. .TP .BI \-server " addr[,addr...]" Comma\-separated list of maglevd gRPC addresses. Required. Each entry is in .I host:port form; a short display name is derived from the hostname label (for IP literals the full address is used). .RI "(env: " MAGLEV_FRONTEND_SERVERS ) .TP .BI \-listen " addr" HTTP bind address for the dashboard. .RI "(default: " :8080 "; env: " MAGLEV_FRONTEND_LISTEN ) .TP .BI \-log\-level " level" Structured\-log verbosity: .BR debug , .BR info , .BR warn , or .BR error . Affects .B maglevd\-frontend 's own logs, not the log level it subscribes to on the upstream maglevd (which is always .BR debug so the probe heartbeat can animate). .RI "(default: " info "; env: " MAGLEV_FRONTEND_LOG_LEVEL ) .TP .B \-version Print version, commit hash, and build date, then exit. .SH HTTP ENDPOINTS .TP .I /view/ Static SPA (HTML, JS, CSS, assets). Read\-only. .TP .I /view/api/maglevds JSON array describing the configured maglevds and their current connection status. .TP .I /view/api/state Full JSON state snapshot for every maglevd. .TP .I /view/api/state/{name} Full JSON state snapshot for a single maglevd. .TP .I /view/api/version Build version, commit hash, and build date, plus an .B admin_enabled flag the SPA uses to decide whether to show the admin toggle. .TP .I /view/api/events Server\-Sent Events stream. Long\-lived HTTP/1.1 chunked response fanning out log, backend, frontend, maglevd\-status, and vpp\-status events to every connected browser. Supports .B Last\-Event\-ID replay from a 30\-second / 2000\-event ring buffer, plus a .B resync control event emitted after every maglevd config reload so the SPA re\-hydrates from the now\-fresh server cache. .TP .I /healthz Liveness endpoint; returns 200 if the HTTP server is up. .TP .I /admin/ SPA shell served behind basic auth when .B MAGLEV_FRONTEND_USER and .B MAGLEV_FRONTEND_PASSWORD are configured. Returns 404 when they're not. .TP .I "/admin/api/{maglevd}/backend/{name}/{action}" Backend lifecycle POST. Action is .BR pause ", " resume ", " enable ", or " disable . Returns the fresh backend snapshot as JSON. .TP .I "/admin/api/{maglevd}/frontend/{fe}/pool/{pool}/backend/{name}/weight" Weight change POST. Body is .B {"weight": 0\-100, "flush": bool} . Returns the fresh frontend snapshot as JSON. .SH SIGNALS .TP .BR SIGTERM ", " SIGINT Graceful shutdown: active gRPC streams are closed, the HTTP server drains, then the process exits. .TP .B SIGHUP Explicitly ignored. A controlling\-terminal disconnect (closing the SSH session the dashboard was started from, for example) would otherwise deliver .B SIGHUP under Go's default handler and terminate the process with .BR Hangup . Since .B maglevd\-frontend has no config file beyond its command\-line flags there is nothing meaningful to .I reload on .BR SIGHUP , and inheriting the default "exit on hangup" semantics is the wrong behaviour for a long\-running network daemon. Use .B SIGTERM for clean shutdown instead. .SH REVERSE PROXY NOTES The SSE stream has a handful of operational requirements that every reverse proxy must satisfy: .IP \(bu 2 Disable buffering on the events endpoint. Nginx honours .B X\-Accel\-Buffering: no (sent by .BR maglevd\-frontend ) but a global .B proxy_buffering off; in the server block is the more robust answer. .IP \(bu 2 Raise .B proxy_read_timeout to at least .BR 300s so the stream isn't torn down between the 15\-second .B :\ ping heartbeats that .B maglevd\-frontend sends. .IP \(bu 2 Do not wrap the events endpoint in a gzip/brotli middleware — response compression buffers until its window fills and destroys the live\-stream property. .SH ENVIRONMENT All environment variables are prefixed with .B MAGLEV_FRONTEND_ so this daemon can share .I /etc/default/vpp-maglev (or a container env file) with .BR maglevd (8) — whose env vars use only the shorter .B MAGLEV_ prefix — without cross\-contamination. .TP .B MAGLEV_FRONTEND_SERVERS Default value of .BR \-server . .TP .B MAGLEV_FRONTEND_LISTEN Default value of .BR \-listen . .TP .B MAGLEV_FRONTEND_LOG_LEVEL Default value of .BR \-log\-level . .TP .B MAGLEV_FRONTEND_USER HTTP basic\-auth username for .BR /admin/ . When set together with .B MAGLEV_FRONTEND_PASSWORD the admin surface is enabled; when either is missing or empty the admin surface is hidden entirely (the SPA doesn't render the admin toggle button and .B /admin/ itself returns 404). .TP .B MAGLEV_FRONTEND_PASSWORD HTTP basic\-auth password for .BR /admin/ . See .B MAGLEV_FRONTEND_USER above. .TP .B MAGLEV_FRONTEND_ARGS Extra command\-line arguments picked up by the systemd unit's .B ExecStart line. Not read directly by the process — the unit expands it before exec\-ing the binary. .SH FILES .TP .I /etc/default/vpp-maglev Environment file sourced by the systemd unit before starting .BR maglevd\-frontend . The same file is shared with .BR maglevd (8); the .B MAGLEV_FRONTEND_ARGS variable there is passed on the command line to .BR maglevd\-frontend , and .B MAGLEV_FRONTEND_USER / MAGLEV_FRONTEND_PASSWORD are read from the process environment. .SH SEE ALSO .BR maglevd (8), .BR maglevc (1) .SH "FULL DOCUMENTATION" .PP .RS https://git.ipng.ch/ipng/vpp-maglev/docs/user-guide.md .RE .SH AUTHOR Pim van Pelt