Taking Plex off Cloudflare’s proxy

For a while my media server was reached from outside the house the same way as everything else: through Cloudflare and down the tunnel. In October 2026 I moved it off that path, onto a small cloud machine of my own that passes the encrypted stream through untouched. This is why, what I weighed, and what the new path looks like.

The terms

Cloudflare’s terms for its application services, in the version last updated on 28 September 2026, say that unless you are an Enterprise customer you must use specific paid services to serve video and other large files through the CDN, and that Cloudflare may disable or limit access to the CDN if you serve video without them. Video is what a media server does. Running it through the proxy was, at best, a thing nobody had noticed yet, and the downside of being noticed would land on the whole zone, not only on one hostname.

That reading of the terms is the whole reason. There was no outage and no warning. I’d rather move before the letter than after it.

The options

I wrote the choices down before picking one.

  • Leave it and hope. Cheap and, at my volume, probably fine for a long time. But the risk falls on every site in the zone, and “probably” is not a rule I can write down.
  • Relay only. Drop the custom address and let the media server’s own relay carry remote streams. Costs nothing, but the relay caps bandwidth low, forces transcodes above the cap, and removes remote downloads. For the people who use it from away, that is a regression.
  • IPv6. Let clients that have it reach the house directly. It helps only those clients and it turns IPv6 on for the whole house, which is a household change that deserves its own plan. Deferred, and still open.
  • A small machine in front. A new cloud machine, the smallest size, with a DNS-only record pointing at it, forwarding over a new WireGuard link to the house. Chosen.

Two machines I already had were ruled out: not the one that runs the NFL platform in production, and not the monitoring machine, which has a standing rule of no private peers so that it can watch the rest without depending on them.

The path

A client asks for the media server’s name and gets the address of plexfront, a DNS-only record, so Cloudflare’s proxy never sees the traffic. On plexfront, HAProxy runs in TCP mode. It reads only the first bytes of the connection, and it drops anything that is not a TLS handshake naming the media server. What passes goes over a WireGuard link to cs, into a dedicated entrypoint on the reverse proxy that speaks the PROXY protocol, and from there to the media server.

TLS still ends at home. The small machine holds no certificate, no secret and no state; it can’t read the stream it forwards. It is a filter and a pipe.

Keeping the client’s real address

The forwarder prefixes each connection with the client’s real address, using the PROXY protocol, and the entrypoint at home replaces the peer with it. The current rule is that this entrypoint trusts the PROXY header from the forwarder’s address only, and it trusts no forwarded HTTP headers at all, so whatever a client claims about itself in a header is discarded. Only the media server’s route is on that entrypoint, and remote sessions show the client’s own public address. The block list on that route now sees real client addresses rather than Cloudflare’s.

Trade-offs

  • A separate entrypoint, not the existing one. Turning the PROXY protocol on for the entrypoint every LAN request uses would have changed the path of every service at once. A new entrypoint changes nothing already running, and it can carry the stricter rule about headers without touching the LAN. The cost is one more entrypoint to remember and one more router.
  • A machine with nothing on it. No tunnel, no secrets, no state, no backup. A rebuild is running the plan again. I gave up the convenience of a general-purpose box for one whose loss costs nothing but a rebuild.
  • Rollback is small. The old path’s tunnel rule is in the repository’s history. Restoring it and pointing the DNS record back at the tunnel brings the old path back.
  • Slightly slower to start, no slower to stream. The TLS handshake now crosses to the house and back instead of ending at Cloudflare’s nearest edge, so starting a stream and seeking cost a little more than before. Once playing, a stream doesn’t feel it. It came out slower to start than I’d predicted, because I hadn’t counted the handshake. It’s still the trade I’d make.

What it gave up

Cloudflare’s proxy did real work for that hostname, and some of it is gone: the edge cache rule that guarded it no longer applies because there is nothing to cache, and the proxy’s own filtering is replaced by HAProxy’s narrower one. I’ve accepted that for a service whose clients authenticate before they get anything, and whose traffic the proxy wasn’t supposed to carry anyway.

The media server’s row is on the public status page, checked from outside the house, so the new path is watched the same way the old one was. The rest of the infrastructure still goes through the tunnels, which A tunnel for each server describes.

← All writing