Summary
When JSS is deployed behind a reverse proxy (Caddy / nginx / Cloudflare etc.) — the recommended --single-user + reverse-proxy pattern documented in #348 / #349 — the "open in databrowser" link points to the wrong location. Observed on a wild deployment running JSS upstream.
Reproduction
- Deploy JSS in
--single-user mode behind a reverse proxy (e.g., Caddy on :443 proxying to JSS on a local port)
- Visit the deployed pod URL (e.g.,
https://pod.example.com/)
- Observe the generated "open in databrowser" link
- Link resolves to a URL using the internal listening host/port rather than the public request host
Real-world example: https://pod.mpeters.dev/ (Caddy + JSS, HTTPS 443, HTTP/2+3) — the databrowser link is incorrect for the public-facing URL.
Likely root cause
JSS likely constructs the databrowser link using the internal request.hostname / listening port rather than honoring reverse-proxy headers:
X-Forwarded-Host — the original Host header before the proxy
X-Forwarded-Proto — the original scheme (https)
X-Forwarded-Port (less standardized but used by some proxies)
On a direct (non-proxied) single-host deployment, internal and external URLs coincide so the bug is invisible. On reverse-proxy deployments — which is the recommended pattern for production — the internal and external URLs diverge.
Acceptance criteria
- "Open in databrowser" link is generated from the public-facing URL when reverse-proxy headers are present
- Trust
X-Forwarded-Host and X-Forwarded-Proto (and X-Forwarded-Port if present) when constructing the link
- Fall back to the request's own
Host header / scheme when no proxy headers present (preserves existing direct-deployment behavior)
- Add a regression test simulating reverse-proxy headers
- Consider whether the fix should also apply to other generated URLs (links in container listings, redirect targets, IDP issuer URL, etc.) — likely yes; reverse-proxy URL discipline is server-wide, not databrowser-specific
Notes for implementation
- Fastify exposes proxy headers via
request.headers['x-forwarded-host'] etc. directly
- Or
app.set('trust proxy', true) if Fastify supports an equivalent
- Care needed: trusting
X-Forwarded-* blindly is a security concern if JSS is internet-exposed without a proxy in front. The existing --baseDomain / --idp-issuer config patterns suggest a reasonable default: trust proxy headers when configured to (e.g., --trust-proxy flag), default to off for direct-exposure safety.
Strategic context (informational)
This is the kind of bug that affects voluntary-adoption operators specifically (those running the recommended --single-user + reverse-proxy pattern). Fixing it removes friction for the architectural deployment pattern JSS upstream recommends.
Summary
When JSS is deployed behind a reverse proxy (Caddy / nginx / Cloudflare etc.) — the recommended
--single-user+ reverse-proxy pattern documented in #348 / #349 — the "open in databrowser" link points to the wrong location. Observed on a wild deployment running JSS upstream.Reproduction
--single-usermode behind a reverse proxy (e.g., Caddy on:443proxying to JSS on a local port)https://pod.example.com/)Real-world example:
https://pod.mpeters.dev/(Caddy + JSS, HTTPS 443, HTTP/2+3) — the databrowser link is incorrect for the public-facing URL.Likely root cause
JSS likely constructs the databrowser link using the internal
request.hostname/ listening port rather than honoring reverse-proxy headers:X-Forwarded-Host— the originalHostheader before the proxyX-Forwarded-Proto— the original scheme (https)X-Forwarded-Port(less standardized but used by some proxies)On a direct (non-proxied) single-host deployment, internal and external URLs coincide so the bug is invisible. On reverse-proxy deployments — which is the recommended pattern for production — the internal and external URLs diverge.
Acceptance criteria
X-Forwarded-HostandX-Forwarded-Proto(andX-Forwarded-Portif present) when constructing the linkHostheader / scheme when no proxy headers present (preserves existing direct-deployment behavior)Notes for implementation
request.headers['x-forwarded-host']etc. directlyapp.set('trust proxy', true)if Fastify supports an equivalentX-Forwarded-*blindly is a security concern if JSS is internet-exposed without a proxy in front. The existing--baseDomain/--idp-issuerconfig patterns suggest a reasonable default: trust proxy headers when configured to (e.g.,--trust-proxyflag), default to off for direct-exposure safety.Strategic context (informational)
This is the kind of bug that affects voluntary-adoption operators specifically (those running the recommended
--single-user+ reverse-proxy pattern). Fixing it removes friction for the architectural deployment pattern JSS upstream recommends.