I Left Cloudflare to Get Faster

I asked whether to move the whole backend to Cloudflare. Before moving, I measured, and a page that never calls the backend and a static PNG were both the same 0.47 seconds. The free plan was killing 1 in 5 requests, and the conclusion was the exact opposite direction

The disclosure-summary service’s web runs on the Cloudflare free plan, and the backend and database sit on Railway. It felt slow from Korea, which I put down to every server being overseas, so moving all of it to the edge looked like the fix. I measured before moving, and the numbers pointed the opposite way.

What I set out to do

I asked at 11:41 at night.

In another session I was trying to make things faster, and I thought about moving the whole backend to Cloudflare. Would that work? I’m on the 20-dollar-a-month Railway plan.

The disclosure-summary service’s web runs as SSR on the Cloudflare Workers free plan, and the backend and DB are on Railway. I figured that with all the servers overseas it was bound to be slow, and if so, moving everything to the CDN edge might make it faster. The same night, in the legislative-activity tracker session, I was throwing out the same question.

How I asked

The agent said to measure the bottleneck first, before moving. It measured three things under the same conditions. The home page, which calls the backend several times; the privacy-policy page, which calls the backend 0 times; and a static PNG that goes through neither the Worker nor the backend.

All three were the same 0.47 seconds. It was a number that came out even with 0 computation. Move the backend and this 0.47 seconds stays as is.

The measurement itself was wrong once too. The custom domain was behind the CF proxy, so the first value measured included the proxy, and I split the targets and measured again.

Where it broke

There were two causes.

The free-plan zone can’t ride the Seoul PoP. Connect from Korea was 144ms. Another site on the same Cloudflare was 7ms. The free-plan zone’s requests were going to California. The paid plan came up, and the answer was “No. We don’t even get that much traffic.”

SSR can’t stay within the free plan’s 10ms of CPU. CPU p50 was 23.9ms. 2.4x the budget. Requests that exceed it die with Error 1102. The 3-day tally was 85,413 successes and 20,890 resource exceeded, 19.4%. 1 in 5 requests was dying quietly.

There was a reason this suddenly got worse. A few days earlier I had grown the sitemap from 100 entries to 172,433. Once crawling doubled, the failure rate quadrupled from 5.9% to 23.3%. Work done to show up better in search was killing the search crawlers.

How I fixed it

The conclusion came out the exact opposite. Not moving the backend to CF, but pulling the web out of CF and onto Railway.

Cost was the first worry. “If I hand what I was using for free over to Railway, it seems like it’ll cost a lot more.” The estimate was 6 dollars added on top of 25.32 dollars a month. After moving and measuring, the web container’s idle RAM was 63MB, so the actual figure was 4 dollars.

In the process of moving I stepped on five traps. railpack beat the Dockerfile. Railway injects PORT, so the web was 8080 but the backend was also 8080 instead of 8000, which produced 502 and ECONNREFUSED. An empty DSN passed the ?? operator and Sentry quietly turned off. Next’s data cache came back to life and the sitemap went stale. A “notice 7 days in advance” gate went into the privacy policy and was then reverted as excessive.

After moving, connect went from 181ms to 35ms, and TTFB from 0.51 seconds to 0.21 seconds. The next morning I deleted the Worker.

Lessons