Requirements
Your proxy must do all four of these things:1
Pass the Host header unchanged
Do not rewrite the
Host header. Set PUBLIC_BASE_URL in .env to the https:// address your users see in their browser bar.Without this, every browser save returns 403 ingress.origin_not_allowed. The browser sends an Origin header with the https:// scheme, but the instance’s socket is plain HTTP — without PUBLIC_BASE_URL those don’t match and plamotrack rejects the write. Reads and logins still work; only writes fail. Fix it by setting the line, then docker compose up -d. Nothing is lost.2
Set X-Forwarded-For
Set the
X-Forwarded-For header, and add the proxy’s address to TRUSTED_PROXIES in .env. Use 127.0.0.1 if the proxy is on the same host; use the proxy’s own IP if it’s on a different machine.Without this, plamotrack sees the proxy’s address as the source of every request. Rate limits and the audit log key on that one address instead of your real visitors — a degradation, not a security hole, but it makes the audit log useless and can trigger rate limits for all users at once.3
Don't buffer text/event-stream, and don't set a short timeout on /mcp
MCP is a streaming protocol. A proxy that buffers
text/event-stream responses holds the entire response body before forwarding it, which causes the AI client to hang silently — no error, no output, just nothing. A short read timeout on /mcp has the same effect.Disable response buffering for the MCP path and set a generous read and send timeout (an hour is not unreasonable). See frontend/nginx/default.conf.template in the plamotrack repo for a working reference configuration — buffering off, an hour’s timeout, and the Connection hop-by-hop header cleared.4
Keep WEB_BIND on 127.0.0.1
If the proxy is on the same host, keep
WEB_BIND at its default of 127.0.0.1. The proxy should be the only way into the stack — not a firewall rule, not a Docker network configuration, but the bind address itself.A proxy on a different machine reaches the instance at its LAN or mesh address; in that case set WEB_BIND to that address and keep it off the public internet.Minimum .env settings
At minimum, add these two lines to your.env:
docker compose up -d.
MCP streaming configuration
The/mcp/ path needs special attention in any proxy configuration:
- Buffering off — the proxy must not buffer
text/event-streamresponses - Generous timeouts — the MCP connection stays open while an AI client is working; a 30- or 60-second read timeout will cut it off mid-session
Connectionheader cleared — hop-by-hop headers should not be forwarded
frontend/nginx/default.conf.template in the plamotrack repo. It’s the bundled ingress configuration, and it handles all three of these correctly.
If you reach the instance by an internal name that differs from the public
hostname in
PUBLIC_BASE_URL — for example, a container name or a local
alias — add that internal name to ALLOWED_HOSTS in .env as well.
Otherwise plamotrack returns 421 Misdirected Request for requests arriving
with that Host header. Nothing is lost while it’s wrong: add the name and
run docker compose up -d.