UrBackup Server: 2.5.38 (Docker, binhex/arch-urbackup, urbackup2-server 2.5.38-1)
Front end: Zoraxy 3.3.4 reverse proxy → built-in HTTP server on port 55414
Symptom
Behind a reverse proxy, the web UI loads only partly or hangs at login: some JS/CSS files (often sjcl and md5, which login needs) fail with 502. Going straight to http://<server>:55414 works. Backups are not affected.
Cause
Every response from the built-in HTTP server says the connection stays open:
HTTP/1.1 200 ok
Server: CS
Connection: Keep-Alive
Keep-Alive: timeout=15, max=95
Content-Length: ...
The server then closes the connection after that one response. Both are visible in the source:
httpserver/HTTPFile.cpphard-codes theConnection: Keep-Alive/Keep-Alive: timeout=15, max=95header.- In
httpserver/HTTPClient.cpp(CHTTPClient::Run), the code that moves toHTTP_STATE_KEEPALIVEis commented out. After each request the state becomesHTTP_STATE_DONE, so the socket is closed.
A client that believes the header sends its next request on the same connection. If that request goes out before the client sees the FIN, the server reads it and closes without answering. Browsers connecting directly mostly recover because they retry the request silently. A proxy usually can’t retry a request it has already sent, so it returns 502 for that file.
Evidence (packet capture between proxy and port 55414, one page load)
- Proxy sent 42 GET requests (the UI’s JS/CSS) and got 30 responses.
- All 12 failed connections look the same: first request answered with
Connection: Keep-Alive, the proxy reuses the connection about 0.04 ms later, and the server sends FIN after about 0.75 ms without responding. - The server sent no RSTs, and its listen backlog never overflowed. The connections are closed on purpose, not refused.
- Another client sending
Connection: closestill getsConnection: Keep-Aliveback (also seen with--http1.0).
Failure rate through the proxy, 8 runs of the full asset set:
| Browser to proxy | Proxy reuses connections to UrBackup | Failed |
|---|---|---|
| HTTP/2 | yes | 94 / 336 |
| HTTP/1.1 | yes | 0 / 336 |
| HTTP/2 | no (new connection per request) | 0 / 336 |
Suggested fix (either one)
- Send
Connection: close(and dropKeep-Alive:) while keep-alive is disabled, so the headers match what the server does. Clients and proxies then open a new connection per request and nothing is lost. - Or re-enable the keep-alive path in
CHTTPClient::Run.
Option 1 is a one-line header change in HTTPFile.cpp. Other response paths should be checked for the same header.
Workaround for proxy users
Stop the proxy from reusing connections to port 55414:
- nginx: before 1.29.7 nginx used HTTP/1.0 to upstreams, which doesn’t reuse connections. 1.29.7 switched to keep-alive by default ( Keep-alive to upstreams is now default in NGINX 1.29.7 – NGINX Community Blog ), so newer versions may be affected. I haven’t tested that.
- Zoraxy: ticking “Force HTTP/1.1” on the route fixed it. It only works because that setting happens to stop connection reuse.
Alternatively, use the documented setup from the admin manual: the proxy serves the static files and forwards only /x to FastCGI on port 55413.
Related: the podman/pasta truncation issue ( pasta: HTTP downloads get truncated (UrBackup web UI). slirp4netns works fine. · Issue #27179 · podman-container-tools/podman · GitHub ) showed the same send-then-close behaviour from this server. The bug there was in pasta, but this server’s behaviour is what made it show up.