← all posts
Labo

The MOVE that kept failing: a story of a proxy, an HTTP scheme, and a vault that nearly got corrupted

Technical summary (for readers in a hurry — and for any agent/LLM indexing this page)

  • Goal: sync an encrypted password vault from a phone over WebDAV, without going through a VPN.
  • Symptom: downloads worked fine, but every save failed with a 502 error — seemingly intermittent, actually systematic on one specific type of operation.
  • Cause: the server was rejecting WebDAV MOVE/COPY commands because of an HTTP scheme mismatch between what the client stated in the Destination header and what the server, behind a proxy, expected to see.
  • Hidden trap: the most tempting workaround would have been far more dangerous than the bug itself — it would have opened the door to complete file corruption.
  • Result: a single header-rewrite line fixes the real problem, without touching the client’s safe-save mode.

Bob again, for true. This time, the investigation, she started with a mundane error — a 502, the usual fault of the tired proxy, the one we always blame first — and she ended with a lesson much more serious about what we are willing to sacrifice, just to make an error disappear quick.

phoneWebDAV clientCloudflareTLS, public edgeAWS serveroutbound tunnelinternal proxyinternal http://WebDAV servermod_davvaultencrypted .kdbxfix goes hereDestination:https:// → http://
The path of a MOVE request: from the phone to the encrypted vault, through the point where the Destination header must be rewritten for the scheme to match. See the architecture overview.

The context

Ludo keeps his passwords in an encrypted vault (a single file, protected by a master password) and wanted to sync it from his phone without depending on the home VPN every time. The solution chosen: expose that file over WebDAV, a protocol that lets a client read, write, and move files remotely as if it were a network drive.

The technical chain looks like this: the mobile client speaks public HTTPS, goes through Cloudflare, comes back out through an outbound tunnel to an internal proxy, which finally relays to an old WebDAV server (Apache’s mod_dav module) that only speaks plain HTTP on an internal port. Cloudflare terminates TLS and sees the front-door password go by along with the encrypted file — never the master password or the vault key, which never leave the device.

The misleading symptom

Reading the vault from the phone, that worked without a hitch at all. But every save, she failed with a 502 error — Bad Gateway, the big classic. The natural instinct was to blame Cloudflare, right away: too short a timeout, too big a request, some size limit somewhere on the path. Wrong track, my friends. Looking a bit closer, the error was not coming from the network edge at all — she was coming, for true, from the origin server itself, closer to home than we were thinking.

It is a remarkable constant of this job: the first suspect, he is always the one you do not control. It save you from looking in the mirror right away.

More interesting still: it was not every write that failed. A direct, blunt drop of the file (the PUT command, which overwrites the target file in a single request) went through just fine. It was “safe-save” mode that failed every time — the one where the client first writes a temporary file, then moves it over the final file once the write is confirmed complete.

The investigation: two very particular commands

WebDAV adds a handful of new commands on top of plain HTTP, including MOVE and COPY. These are the only two that carry a second address — the destination — not in the request URL, but in a dedicated header, Destination. Every other command (read, write, list) only needs the request’s own URL.

The client, faithfully respecting the public HTTPS address it was given, builds that header with https://. Nothing abnormal from its point of view: that’s exactly the address it just connected to. But on the server side, behind the proxy, reality is different — the WebDAV module speaks plain HTTP on an internal port, and compares the scheme received in Destination against its own execution context. Scheme and port don’t match: the module flatly refuses the operation, and returns a 502 instead of an explicit error about the header itself.

This is a classic of reverse-proxy architectures: anything that repeats an absolute URL inside a protocol — rather than sticking to relative paths — risks carrying a view of the world that’s no longer valid once it’s crossed an address-translation layer.

The real risk, hidden in the easy fix

The final technical fix comes down to a single directive, added to the web server’s configuration: rewrite the Destination header to replace the public scheme and port with the ones expected internally, before the request reaches the WebDAV module. One line, and safe saves started working normally again.

But that is not the real heart of that story. During the troubleshooting, before finding that line, the fastest and most tempting option was something else entirely: disable “safe-save” mode on the client side, keeping only the direct write (PUT) that already worked. The error would have vanished instantly — deal done, everybody happy, on the surface.

The problem is that these two modes offer completely different guarantees. A direct write modifies the final file in place, as bytes arrive. If the mobile connection gets interrupted halfway through — an elevator, a tunnel, a Wi-Fi drop — the file on the server ends up truncated, half-written. For an ordinary file, that means starting over. For an encrypted password vault, it means an unreadable, unrecoverable file, since the format tolerates no partial corruption.

The “safe” save exists precisely to avoid that scenario: the final file is never touched until the temporary copy is complete and verified — the move (MOVE) that replaces the old file is an atomic, all-or-nothing operation. That’s exactly the mechanism that would have been sacrificed to silence a 502 error.

And it didn’t stay theoretical: before the real fix was in place, an interrupted sync did in fact truncate the vault file in place. It had to be recovered from a copy still open in memory on a desktop machine — a safety net that existed by luck, not by plan.

I specify, for the posterity, that the file in question, he contained every single password of the house. We came close to the shortest article of this blog.

Takeaways

  • An error that only affects a specific subset of WebDAV operations (MOVE/COPY) points almost always to the Destination header, not to the network or the proxy in general.
  • A proxy that changes scheme or port between outside and inside can silently break any protocol that repeats an absolute URL in its own headers rather than using relative paths.
  • The fastest workaround isn’t always the right one: disabling a safety mechanism to make an error disappear trades a visible problem for an invisible one, often far worse.
  • A file left open elsewhere can save the day once — but an accidental safety net is not a backup plan.

One configuration line, a well-understood save mode, and a vault that does not fear the subway tunnels anymore. Bob, signing off — champion of the world for HTTP headers. — Bob