Skip to content

docs: document serving the kagent UI under a sub-path (#535) - #555

Open
boxcee-interview wants to merge 2 commits into
kagent-dev:mainfrom
boxcee-interview:fix/issue-535
Open

boxcee-interview wants to merge 2 commits into
kagent-dev:mainfrom
boxcee-interview:fix/issue-535

Conversation

@boxcee-interview

Copy link
Copy Markdown
Contributor

Closes #535

The 1.x doc set has no coverage for ui.basePath (added in kagent#2904, shipped in v1.0.0-alpha3). This adds a dedicated setup page, as the issue asks.

The new page covers:

  • the ui.basePath value, its default, and its no-op-when-unset behavior
  • both proxy shapes (strips the prefix vs. forwards it unchanged), with a working example of each
  • both Helm render rejections with their exact messages, and the full reserved set (api, a2a, assets, health, env-config.js, index.html, mockServiceWorker.js)
  • the oauth2-proxy OIDC_REDIRECT_URL step and the pod restart it requires, with the reason
  • the fact that publicBackendUrl and the other root-relative URLs inherit the prefix
  • a verification checklist

installation.md gets a link to the new page at the point where a reader meets the UI service.

How to Test

Hugo 0.160.1 extended build of docs-site (hugo --config hugo.yaml --gc --minify) succeeds, and both the new page (docs-site/public/kagent/1.x/setup/reverse-proxy/) and the installation.md link to it resolve to a real output file.

@boxcee-interview

Copy link
Copy Markdown
Contributor Author

CI note: the deploy check failed with In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. — this looks like a missing secret in the Preview workflow rather than something the docs changes affect (the PR only touches two .md files). All other checks pass. Flagging so the maintainer can confirm or set the token.

Signed-off-by: Moritz Schmitz von Hülst <mschmitzvonhuelst@gmail.com>
@Rachael-Graham

Copy link
Copy Markdown
Contributor

yeah i think the deploy preview doesnt work on forks right now... ill look into that soon

author: kagent.dev
---

The kagent UI is served by an nginx sidecar that answers on port `8080` inside the pod. By default it serves at the root (`/`). When a reverse proxy fronts the UI and you want it reachable under a prefix such as `/ui`, set `ui.basePath` in the Helm values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking. nginx is not a sidecar here. ui-deployment.yaml defines a single container named ui, and the Dockerfile's runtime stage is nginx only. nginx is the UI container itself.

Suggested change
The kagent UI is served by an nginx sidecar that answers on port `8080` inside the pod. By default it serves at the root (`/`). When a reverse proxy fronts the UI and you want it reachable under a prefix such as `/ui`, set `ui.basePath` in the Helm values.
The kagent UI is a static bundle served by nginx, which answers on port `8080` inside the pod. By default it serves at the root (`/`). When a reverse proxy fronts the UI and you want it reachable under a prefix such as `/ui`, set `ui.basePath` in the Helm values.

Comment on lines +10 to +17
## The `ui.basePath` value

| Setting | Default | Effect |
|---------|---------|--------|
| `ui.basePath` | `""` (empty) | UI served at `/`. All existing behaviour unchanged. |
| `ui.basePath` | e.g. `/ui` | UI served under the prefix. One value moves every root-relative URL the UI emits. |

The value is purely additive: leaving it unset leaves the installation exactly as it is today.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fix. A table must not open a section: the h2 needs a framing sentence first, and that sentence must add something the table does not. Line 17 already is that sentence, so it mainly needs to move up, with one more line of prose to carry it. I have also dropped "today", which the page outlives.

Suggested change
## The `ui.basePath` value
| Setting | Default | Effect |
|---------|---------|--------|
| `ui.basePath` | `""` (empty) | UI served at `/`. All existing behaviour unchanged. |
| `ui.basePath` | e.g. `/ui` | UI served under the prefix. One value moves every root-relative URL the UI emits. |
The value is purely additive: leaving it unset leaves the installation exactly as it is today.
## The `ui.basePath` value
One Helm value controls the whole sub-path, and it is purely additive: leaving it unset leaves an existing installation serving at the root exactly as before. Set it, and the prefix reaches every URL the UI emits, not only the pages a reader navigates to.
| Setting | Default | Effect |
|---------|---------|--------|
| `ui.basePath` | `""` (empty) | UI served at `/`. All existing behaviour unchanged. |
| `ui.basePath` | e.g. `/ui` | UI served under the prefix. One value moves every root-relative URL the UI emits. |


The value is purely additive: leaving it unset leaves the installation exactly as it is today.

When set, a single value controls the `<base href>` tag, the client-side router basename, and the root-relative API, SSO, userinfo, and share-link URLs that the browser uses. A reader who expects to adjust `publicBackendUrl` by hand should know that the base path already covers it: root-relative URLs such as `publicBackendUrl` inherit the prefix automatically.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fix. This addresses "a reader" and describes what they ought to know, which reads as scoping notes rather than documentation. State the behavior directly.

Suggested change
When set, a single value controls the `<base href>` tag, the client-side router basename, and the root-relative API, SSO, userinfo, and share-link URLs that the browser uses. A reader who expects to adjust `publicBackendUrl` by hand should know that the base path already covers it: root-relative URLs such as `publicBackendUrl` inherit the prefix automatically.
When set, a single value controls the `<base href>` tag, the client-side router basename, and the root-relative API, SSO, userinfo, and share-link URLs that the browser uses. `publicBackendUrl` and the other root-relative URLs inherit the prefix, so do not adjust them by hand.


When set, a single value controls the `<base href>` tag, the client-side router basename, and the root-relative API, SSO, userinfo, and share-link URLs that the browser uses. A reader who expects to adjust `publicBackendUrl` by hand should know that the base path already covers it: root-relative URLs such as `publicBackendUrl` inherit the prefix automatically.

## Proxy shapes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking. The page never shows how to set the value. --set ui.basePath=/ui appears only in passing on line 93, so a reader arrives here knowing what the value does but not how to apply it.

Please add a short section before this heading showing the command that sets it. House convention puts a required non-default Helm value on the install step rather than a follow-up helm upgrade, so frame it as installing kagent with the value, and link back to the install page's prerequisites.


## Proxy shapes

Both of the following proxy configurations work. Choose the one that matches your infrastructure.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking. True without SSO, but not with it, and the sentence is unqualified.

Tested on v1.0.0-alpha8 with oauth2-proxy.enabled=true: the forwarding shape returns 403 for /ui/login, /ui/health, /ui/env-config.js and /ui/oauth2/start, because --skip-auth-regex and --skip-auth-route are anchored at the root and --proxy-prefix stays /oauth2. The chart's own sign_in.html points at /ui/login, so sign-in loops. values.yaml describes the value the same way: "Prefix a reverse proxy strips before forwarding".

Suggested change
Both of the following proxy configurations work. Choose the one that matches your infrastructure.
Both of the following proxy configurations work. Choose the one that matches your infrastructure. If you enable oauth2-proxy for SSO, the proxy must strip the prefix: with the prefix forwarded, oauth2-proxy cannot match its own sign-in and skip-authentication paths, and sign-in fails.


## Helm render validation

Two validations run at Helm render time and fail the install rather than producing a broken UI. Both are defined in `helm/kagent/templates/ui-configmap.yaml`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fix. The error an operator actually sees names a different file:

Error: execution error at (kagent/templates/ui-deployment.yaml:21:31): ui.basePath must be a path like /ui

Chart-internal paths also rot — upstream's own init.sh comment already points at the wrong template. Drop the citation.

Suggested change
Two validations run at Helm render time and fail the install rather than producing a broken UI. Both are defined in `helm/kagent/templates/ui-configmap.yaml`.
Two validations run at Helm render time and fail the install rather than producing a broken UI.

Comment on lines +86 to +87
1. Set `OIDC_REDIRECT_URL` to point under the base path (for example `https://example.com/ui/oauth2/start` rather than `https://example.com/oauth2/start`).
2. Restart the oauth2-proxy pod after changing the value.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking. OIDC_REDIRECT_URL becomes oauth2-proxy's --redirect-url, which is the OAuth callback, not the path that starts sign-in. The chart leaves --proxy-prefix at /oauth2, so the callback is /oauth2/callback.

Tested: /ui/oauth2/start?code=…&state=… returns 302 back to the identity provider, ignoring the code, while /ui/oauth2/callback?code=…&state=… attempts the token exchange. As written, this step produces an endless sign-in loop.

Suggested change
1. Set `OIDC_REDIRECT_URL` to point under the base path (for example `https://example.com/ui/oauth2/start` rather than `https://example.com/oauth2/start`).
2. Restart the oauth2-proxy pod after changing the value.
1. Set `OIDC_REDIRECT_URL` under `oauth2-proxy.extraEnv` in your Helm values so that it points under the base path, for example `https://example.com/ui/oauth2/callback` rather than `https://example.com/oauth2/callback`.
2. Register that same URL as a redirect URI with your identity provider.
3. Restart the oauth2-proxy pod after changing the value.

1. Set `OIDC_REDIRECT_URL` to point under the base path (for example `https://example.com/ui/oauth2/start` rather than `https://example.com/oauth2/start`).
2. Restart the oauth2-proxy pod after changing the value.

The restart is required because the chart's sign-in HTML redirects to `{basePath}/login`, and the oauth2-proxy checksum deliberately renders without the `ui` prefix, so a base-path change alone does not roll the oauth2-proxy pod. Without the restart, the proxy keeps using the old redirect URL and sign-in fails.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fix. The restart requirement is correct — I verified that changing ui.basePath updates the ConfigMap to url=/console/login while the checksum stays put and the pod does not roll. The reason is a misreading, though: the checksum renders without the ui values key ((.Values.ui | default dict) is empty in that scope), not without the ui URL prefix.

Suggested change
The restart is required because the chart's sign-in HTML redirects to `{basePath}/login`, and the oauth2-proxy checksum deliberately renders without the `ui` prefix, so a base-path change alone does not roll the oauth2-proxy pod. Without the restart, the proxy keeps using the old redirect URL and sign-in fails.
The restart is required because the chart's sign-in HTML redirects to `{basePath}/login`, but the checksum that would roll the oauth2-proxy pod is computed where the `ui` values key is not in scope. The base path is absent from the hash, so the hash does not change and the pod keeps the old sign-in template and redirect URL until you restart it.

Comment on lines +93 to +99
After installing with `--set ui.basePath=/ui`:

1. Open `/ui/` in a browser. The UI should load.
2. Navigate to an agent list or detail page. The URL should stay under `/ui/...` (for example `/ui/agents`).
3. Open the browser network tab. API calls should go to `/ui/api/...`, not `/api/...`.
4. Reload the page. The SPA router should keep the prefix.
5. If oauth2-proxy is enabled, sign in. The redirect should land under `/ui/oauth2/...`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fix. These are "should" statements rather than steps with expected results, and the rejection path issue #535 asked to be recorded is missing.

Give each check an explicit expected result, and add a step that sets a rejected value such as /api and shows what Helm prints:

Error: execution error at (kagent/templates/ui-deployment.yaml:21:31): ui.basePath cannot start with a path nginx serves, such as /api or /assets

Step 5 also needs the caveat from the "Proxy shapes" thread: the redirect lands under /ui/oauth2/... only when the proxy strips the prefix.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional, take or leave. Every other 1.x page closes with a Next steps cards block. The install page and the identity page would be the obvious cards here.

Signed-off-by: Moritz Schmitz von Hülst <mschmitzvonhuelst@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs: document serving the kagent UI under a sub-path for 1.x

2 participants