Skip to content

Support serving the web UI under a reverse-proxy subpath (iframe embedding) #1387

Description

@csillag

What feature would you like to see?

Make the built web UI servable under a reverse-proxy path prefix (subpath), so kimi web can be embedded in an iframe mounted at a non-root path (e.g. https://host/some/prefix/…).

Today the SPA assumes it is served from the origin root, which breaks under a prefix in three ways:

  1. Assets 404index.html and chunks reference /assets/… (absolute). Behind a prefix the browser requests https://host/assets/…, which the proxy doesn't route to the daemon.
  2. REST/WS miss the prefix — the SPA builds API/WS URLs from window.location.origin (apps/kimi-web/src/api/config.ts), so calls go to /api/v1/… without the prefix and never reach the daemon.
  3. Deep-link routing — session routing reads/writes location.pathname at the origin root, so /sessions/<id> isn't recognised under a prefix.

Proposed approach (small, direct-serve-safe):

  1. apps/kimi-web/vite.config.tsbase: './' (relative asset URLs).
  2. apps/kimi-web/index.html — a static <base href="/"> (+ relative favicon) so a direct-serve deep-link hard-refresh still resolves ./assets/* to /assets/*; an embedder injects its own <base href="<prefix>/"> earlier in <head>, and the first <base href> wins, so the prefix takes precedence in-frame.
  3. apps/kimi-web/src/api/config.ts — resolve the server base from document.baseURI instead of location.origin, so REST + WS URLs carry the prefix. At direct-serve document.baseURI === origin + '/', i.e. behavior is unchanged.

No effect on the normal same-origin serve; direct-serve deep-link refresh stays correct via the static <base href="/">.

Additional information

Reproduce: serve the built dist-web behind any path-prefix reverse proxy (or a same-origin iframe mounted at a subpath) → blank frame; the console shows /assets/* 404s followed by /api/v1/* 404s.

Out of scope for this SPA change: a cross-origin embedder must still authorize the browser Origin for the daemon's WebSocket/POST same-origin checks — that's an embedder-side concern (the proxy strips/rewrites Origin, or the daemon is launched with a CORS allowlist), not part of the SPA changes above.

I have a branch ready (~26 lines across the 3 files), verified end-to-end in a headless-browser iframe harness (assets load, REST + WS connect, session deep-link honored, zero console errors). Happy to open a PR if the direction looks good — following the "discuss first" guidance, waiting for maintainer feedback before sending it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions