Self-hosted: the api's public origin is baked at build time, so it is wrong behind a proxy
Split out of #5697 (single-port dev proxy), which surfaced this but deliberately doesn't fix it.
Root cause
The self-hosted api's public origin is fixed at build time. <Infra.ApiUrl> emits the WEBINY_API_URL build param, and everything that needs to hand a client an absolute URL reads that param.
Behind a proxy that stops being knowable at build time. The api listens on a private port under a path prefix it never sees, and the origin the browser actually used only exists per request, in the forwarding headers.
Three symptoms
1. Existing projects show broken images behind the proxy. Confirmed. srcPrefix is persisted into File Manager settings by SettingsInstaller, which only runs when an install is requested (alwaysRun means "include this installer in an install", not "run every boot"). A project installed before the proxy keeps its old prefix:
sqlite> select value from webiny_core_key_value where key = 'FileManager/General';
{"srcPrefix":"http://localhost:3002/files/"}Uploads succeed, but the <img> src is http://localhost:3002/files/... and nothing is listening there. New projects install the right prefix, so this is a migration problem, not a fresh-install one.
2. Uploads should break under portless. Expected, not yet verified against a real portless setup. GetUploadPayloadUseCase returns ${config.apiUrl}/webiny-file-upload, where apiUrl is the build param, so with the proxy on it's http://localhost:<port>/api/webiny-file-upload. The page under portless is https://admin6.localhost, so that's an active mixed-content request and browsers block it.
3. serve behind the proxy needs a matching build. webiny serve runs what webiny build produced, so the admin bundle's API URL was fixed then. Serving it behind the proxy only works if the build already used a URL that works there.
What was tried and rejected
#5697 initially added a RequestOrigin per-request holder, filled from x-forwarded-proto / -host / -prefix by a Node HTTP decorator, read as a fallback by FileManagerServerConfig and SettingsInstaller.
It was removed, because it never ran. Both consumers check the build param first, and the dev proxy always sets it, so the fallback was unreachable in every path the proxy exercises. Inverting the precedence would make it run, but then a client-supplied header would override an origin a deployment pinned on purpose, which is worse.
Sketch of a real fix
Probably: the proxy stops setting WEBINY_API_URL, <Infra.ApiUrl> becomes genuinely optional, and the api derives its origin per request when none is configured. That needs the project templates to stop defaulting to http://localhost:3002, otherwise the build param is present-but-wrong and the per-request path is still dead.
Symptom 1 is separate and needs a decision of its own: srcPrefix is user-editable settings and also where a CDN origin goes, so self-healing it would clobber deliberate values. Options are a migration, a release note, or leaving it.
Source: webiny/webiny-js