feat: support serving WebUI under a configurable URL sub-path#113
feat: support serving WebUI under a configurable URL sub-path#113tittuvarghese wants to merge 2 commits into
Conversation
Make the WebUI serveable under an arbitrary reverse-proxy prefix (e.g. https://host/gpu-ui/) in addition to the site root, without rebuilding the frontend image per deployment. Modelled on Grafana's serve_from_sub_path and ArgoCD's server.rootpath. The base path is resolved at request time from, in precedence order: the X-Forwarded-Prefix header, the HAMI_WEBUI_BASE_PATH env var, then default "/". This works for both a path-stripping proxy (sets the header) and an ingress that passes the full prefixed path through. BFF (NestJS): - Add utils/base-path.ts: normalize (leading/trailing slash, sanitized), resolve (header > env), and inject <base href> + window.__BASE_PATH__ into index.html at send time. - main.ts: strip the configured prefix up-front so static assets, the /api proxy, and the SPA fallback keep matching root-relative paths; serve static with index/redirect disabled so requests fall through to the injecting controller; allow PORT override. - app.controller.ts: render index.html with the resolved base path. Frontend (Vue): - index.html: drop the hard-coded <base href="/">; make favicon and entry refs relative. - Add utils/base-path.js (getBasePath) and use it for the router history base, the axios baseURL, and the socket.io path. Helm chart: - Add basePath value (default "/") wired to HAMI_WEBUI_BASE_PATH. Docs: - Add docs/installation/sub-path.md (config, both proxy modes, manual test plan); document the chart value and X-Forwarded-Prefix behavior. Root-serving behavior is unchanged and default installs are unaffected. Signed-off-by: tittu.varghese <tittu.varghese@npci.org.in>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: tittuvarghese The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Welcome @tittuvarghese! It looks like this is your first PR to Project-HAMi/HAMi-WebUI 🎉 |
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughHAMi-WebUI now supports runtime URL base paths. The BFF resolves and injects the path, the frontend applies it to routing and network clients, and the Helm chart and documentation describe configuration and proxy modes. ChangesBase-path serving
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant ReverseProxy
participant FrontendBFF
participant VueRouter
participant Axios
participant SocketIO
Browser->>ReverseProxy: Request WebUI under a URL prefix
ReverseProxy->>FrontendBFF: Forward request and optional X-Forwarded-Prefix
FrontendBFF-->>Browser: HTML with resolved runtime base path
Browser->>VueRouter: Initialize history with base path
Browser->>Axios: Send API requests using base path
Browser->>SocketIO: Connect using prefixed socket.io path
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app.controller.ts`:
- Around line 24-28: Update the index method to set the response Vary header to
X-Forwarded-Prefix before sending the dynamically rendered HTML, while
preserving the existing resolveBasePath and renderIndex flow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a4fba224-70f1-4089-b083-5e793be1b42b
📒 Files selected for processing (14)
README.mdcharts/hami-webui/README.mdcharts/hami-webui/templates/deployment.yamlcharts/hami-webui/values.yamldocs/installation/sub-path.mdpackages/web/index.htmlpackages/web/src/components/Socket/index.jspackages/web/src/router/index.jspackages/web/src/utils/base-path.jspackages/web/src/utils/request.jssrc/app.controller.tssrc/main.tssrc/utils/base-path.spec.tssrc/utils/base-path.ts
The index.html body varies by the X-Forwarded-Prefix header (it drives the injected <base href> and window.__BASE_PATH__). Without a matching Vary header, a CDN or intermediate proxy could cache one prefix's response and serve it to users on a different prefix — a cache-poisoning vector that breaks routing / causes a denial of service. Advertise the header so caches key responses per-prefix. Signed-off-by: tittu.varghese <tittu.varghese@npci.org.in>
What this does
Makes the HAMi WebUI serveable under an arbitrary URL sub-path behind a reverse
proxy (e.g.
https://host/gpu-ui/) in addition to the site root (/), withoutrequiring a frontend image rebuild per deployment. The base path is configurable
at deploy time. The design follows Grafana's
serve_from_sub_pathand ArgoCD'sserver.rootpath.How it works
The base path is resolved at request time (never baked into the JS bundle),
from — in precedence order:
X-Forwarded-Prefixrequest header (set by a path-stripping proxy), thenHAMI_WEBUI_BASE_PATHenvironment variable, then/(root, unchanged historical behavior).On serving
index.html, the BFF injects<base href="{basePath}">and awindow.__BASE_PATH__global. The SPA reads that global for its router historybase, its axios
baseURL, and its socket.iopath.Both proxy modes are supported:
X-Forwarded-Prefix(leave the chart at itsdefault), and
base path so the BFF strips its own prefix internally).
The Go API server is untouched — it is always reached via the
/api/vgpuproxyand remains path-agnostic.
Changes
BFF (NestJS,
src/)utils/base-path.ts(new): normalize (leading/trailing slash, sanitized),resolve (header > env), and inject the
<base>tag + global intoindex.html.main.ts: strip the configured prefix up-front so static assets, the/apiproxy, and the SPA fallback keep matching root-relative paths; serve static
with
index/redirectdisabled so requests fall through to the injectingcontroller; allow
PORToverride for local runs.app.controller.ts: renderindex.htmlwith the resolved base path (templatecached).
Frontend (Vue,
packages/web/)index.html: drop the hard-coded<base href="/">; make favicon/entry refsrelative.
utils/base-path.js(new,getBasePath) used for the router history base, theaxios
baseURL, and the socket.iopath.Helm chart (
charts/hami-webui/)basePathvalue (default"/") wired toHAMI_WEBUI_BASE_PATH. Ingressdefault and base path both remain
/, so existing installs are unaffected.Docs
docs/installation/sub-path.md: configuration, both proxy modes, and a manualtest plan. Chart
README.mdsection + values row; root README link.Testing
nest build, ESLint (BFF + frontend), and the full Jest suite (incl. newsrc/utils/base-path.spec.ts) pass./, non-stripping/gpu-ui/, and header-based stripping: index injection,hashless deep-link refresh, static assets, favicon,
/api/vgpuproxy match,/health_check, and header-XSS sanitization all behave correctly.helm templaterendersHAMI_WEBUI_BASE_PATHas/(default) and/gpu-ui/(override).
Root-serving behavior is unchanged; default installs are unaffected.
Summary by CodeRabbit
New Features
Documentation
Bug Fixes
Tests