github dmellok/tesserae v0.49.4
v0.49.4 — Public URL override for reverse-proxy installs

latest releases: v0.259.0, mcp-v0.12.0, mcp-v0.11.0...
one month ago

Added

"Public URL" setting under Settings → App. Operator-supplied override for the URL Tesserae uses when building external links (OAuth callbacks, HA discovery image URLs, etc.). Use this when running behind a reverse proxy whose `X-Forwarded-*` headers don't reach Flask cleanly.

Background

0.49.3 added ProxyFix to honour `X-Forwarded-Proto` / `X-Forwarded-Host` / `X-Forwarded-Port` from upstream reverse proxies. That works for proxies that send those headers as standard, but NGINX Proxy Manager has an undocumented quirk: it silently ignores `proxy_set_header` directives in its Advanced tab unless they're inside a Custom Location block. NPM's own warning text says "any add_header or set_header directives added here will not be used by nginx," but it's easy to miss, and the Custom Location workaround is non-obvious.

Setting Public URL bypasses that mess entirely. One value, applied at the WSGI layer, force-overrides scheme + host + port on every request.

Usage

In Tesserae:

  1. Settings → App
  2. Find the new Public URL field at the top
  3. Paste the full public URL: scheme + host + port if non-standard
  4. Save

Example values:

  • `https://tesserae.example.org\` (standard 443)
  • `https://tesserae.example.org:8443\` (non-standard port, e.g. when ISP blocks 443 inbound)
  • `https://homeassistant.tail1234.ts.net\` (Tailscale Funnel)

Leave blank for the existing auto-detect behaviour (ProxyFix + request headers). Malformed values silently fall back to auto-detect so a typo doesn't lock you out.

Implementation

Thin WSGI middleware reads the setting per request (no Tesserae restart needed when changing it), parses the URL, and rewrites `wsgi.url_scheme` + `HTTP_HOST` on the environ. Trailing slashes are stripped tolerantly.

Tests

+4 regression tests in `tests/test_proxyfix.py` covering override, trailing-slash tolerance, empty-falls-back-to-ProxyFix, and graceful fallback when the value is malformed. 979 passing, ruff + mypy strict clean.

Don't miss a new tesserae release

NewReleases is sending notifications on new releases.