Skip to content

Databrowser "open in" link generates wrong URL on reverse-proxy deployments #361

Description

@melvincarvalho

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

  1. Deploy JSS in --single-user mode behind a reverse proxy (e.g., Caddy on :443 proxying to JSS on a local port)
  2. Visit the deployed pod URL (e.g., https://pod.example.com/)
  3. Observe the generated "open in databrowser" link
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions