Skip to content

feat(web): support a reverse-proxy base URL - #381

Open
mtiller wants to merge 1 commit into
Ark0N:masterfrom
mtiller:feat/reverse-proxy-base-url
Open

feat(web): support a reverse-proxy base URL#381
mtiller wants to merge 1 commit into
Ark0N:masterfrom
mtiller:feat/reverse-proxy-base-url

Conversation

@mtiller

Copy link
Copy Markdown

I’m using tail scale and it allows mounting multiple applications on a single TLS protected Magic DNS name. But Codeman couldn’t be configured to operate at a non / base URL…until now. 😉

Codeman can now be mounted under a sub-path behind a reverse proxy that forwards the prefix unchanged (e.g. https://host/codeman/). Default is / (root), which is byte-identical to the historical behavior.

Design — few choke points, mirrored ingress/egress:

  • src/config/base-path.ts: pure single-source normalize/validate/join/strip.
  • Server ingress: stripBasePath() inside Fastify rewriteUrl, so routes stay declared prefix-agnostic; un-prefixed requests (hooks, health, docker bridge hitting the raw port) pass through unchanged.
  • Server egress: one onSend hook prepends the base to root-absolute Location headers (covers all redirects).
  • HTML: renderIndexHtml points at the mount and injects window.CODEMAN_BASE — ONLY when a base is set (inert at root).
  • Frontend runtime URLs: CodemanBase.url() route builder in constants.js, applied transparently by a fetch wrapper and explicitly at the EventSource/WebSocket/window.open/<img|iframe|a>-src sites.
  • sw.js derives its base from self.location; manifest uses relative start_url/scope.
  • Web-tab proxy: proxyPrefixFor(cap, basePath) is the single base-aware root that cascades to the injected , HTML/attr rewrites, runtimeUrlShim, Set-Cookie Path and Location; capabilityFromReferer strips the base off the browser Referer, while the ingress parsers stay base-agnostic (rewriteUrl already stripped it).

--base-url rides the daemon relaunch (buildWebArgs) and the service unit (resolveServicePlan). constants.js is guarded against a missing window for isolated unit-test contexts.

Tests: test/base-path.test.ts (pure helpers), base-path coverage in webview-proxy/render-index-html/daemon-control; CodemanBase stubbed in the vm-isolated panels-ui test contexts. Docs: Remote-Access.md (sub-path section + nginx example), security-architecture.md env table, CLAUDE.md pattern.

…E_URL)
Codeman can now be mounted under a sub-path behind a reverse proxy that
forwards the prefix unchanged (e.g. https://host/codeman/). Default is `/`
(root), which is byte-identical to the historical behavior.
Design — few choke points, mirrored ingress/egress:
- src/config/base-path.ts: pure single-source normalize/validate/join/strip.
- Server ingress: stripBasePath() inside Fastify rewriteUrl, so routes stay
declared prefix-agnostic; un-prefixed requests (hooks, health, docker bridge
hitting the raw port) pass through unchanged.
- Server egress: one onSend hook prepends the base to root-absolute Location
headers (covers all redirects).
- HTML: renderIndexHtml points <base href> at the mount and injects
window.__CODEMAN_BASE__ — ONLY when a base is set (inert at root).
- Frontend runtime URLs: CodemanBase.url() route builder in constants.js,
applied transparently by a fetch wrapper and explicitly at the
EventSource/WebSocket/window.open/<img|iframe|a>-src sites.
- sw.js derives its base from self.location; manifest uses relative start_url/scope.
- Web-tab proxy: proxyPrefixFor(cap, basePath) is the single base-aware root that
cascades to the injected <base>, HTML/attr rewrites, runtimeUrlShim, Set-Cookie
Path and Location; capabilityFromReferer strips the base off the browser Referer,
while the ingress parsers stay base-agnostic (rewriteUrl already stripped it).
--base-url rides the daemon relaunch (buildWebArgs) and the service unit
(resolveServicePlan). constants.js is guarded against a missing `window` for
isolated unit-test contexts.
Tests: test/base-path.test.ts (pure helpers), base-path coverage in
webview-proxy/render-index-html/daemon-control; CodemanBase stubbed in the
vm-isolated panels-ui test contexts. Docs: Remote-Access.md (sub-path section +
nginx example), security-architecture.md env table, CLAUDE.md pattern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUkPBxbumnct6qSrx4JDju
Sign up for freeto 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.

1 participant

@mtiller