Background
I registered a domain for a new project. Shortly after launch, Google Search Console started flooding with mysterious 404 errors — URLs like /post/xxx and /category-xxx, the classic WordPress path patterns. Turns out the domain had a previous owner who ran a WordPress site, and Google still had those old pages indexed.
When search engines see 404s on old URLs, they keep retrying. Better to tell them unequivocally: "This content is gone for good" — that's what 410 Gone is for.
The Pitfall: _redirects Only Supports 3xx
My first instinct was to add rules to _redirects:
/post/* 410
/category-* 410
Deployed it. Nothing happened — those URLs still returned 404.
After digging into the Cloudflare Pages docs, the answer emerged: _redirects only supports five status codes — 301, 302, 303, 307, and 308. Writing 410 gets silently ignored. No warning, no error, nothing.
As a bonus facepalm: my test 301 redirect wasn't working either, because I had the format backwards:
/test-redirect 301 / ← Wrong: destination and status code are swapped
/test-redirect / 301 ← Correct: source → destination → status code
The Fix: Cloudflare Pages Functions
Use a Cloudflare Pages Function as middleware. Create functions/[[path]].js at the project root:
// Intercept old WordPress URLs, return 410 Gone
// Pass everything else through to static assets
const GONE_PATTERNS = [
/^\/post\//,
/^\/category-/,
/^\/author-/,
/^\/page_/,
/^\/date-/,
];
const GONE_EXACT = [
'/.IGV0hOcNusVJOgqoD1HuWTk0PssdueKB',
];
export async function onRequest(context) {
const { pathname } = new URL(context.request.url);
if (GONE_PATTERNS.some((p) => p.test(pathname))
|| GONE_EXACT.includes(pathname)) {
return new Response('410 Gone — This content has been permanently removed.', {
status: 410,
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
return context.next();
}
- Matches old WordPress URL patterns → returns 410
- Everything else →
context.next()passes through to static assets with zero overhead
Deployment
Place the functions/ directory at the project root (not inside src/ or public/). Cloudflare Pages auto-detects it and enables the Functions runtime — no extra configuration needed.
✨ Uploading _redirects
✨ Uploading Functions bundle
Verification
$ curl -s -o /dev/null -w "HTTP %{http_code}" https://example.com/post/hello-world
HTTP 410
$ curl -s -o /dev/null -w "HTTP %{http_code}" https://example.com/category-tech
HTTP 410
$ curl -s -o /dev/null -w "HTTP %{http_code}" https://example.com/
HTTP 200
TL;DR
| Need | Solution |
|---|---|
| 3xx redirects |
_redirects file |
| 4xx / 5xx status codes | Cloudflare Pages Functions |
| Complex routing (rate limiting, auth, etc.) | Functions or Workers |
This was a real-world pitfall encountered while building BGM Box, a free online BRSTM converter and player for Nintendo game audio. Convert 100+ formats (MP3, WAV, OGG, FLAC, ADX, HCA, FSB, WEM...) to BRSTM, BCSTM, and BFSTM — all in your browser with no sign-up and no file uploads. Give it a try!
Top comments (0)