Headers & CSP: the silent killers.
Most proxies "work" until the upstream returns a header that breaks the illusion. Three categories matter: host-bound headers, caching headers, and Content-Security-Policy.
Host-bound headers
The Worker should send a clean Host to the origin and never echo upstream
Set-Cookie domains that mention the origin host. Cloudflare handles Host
rewriting automatically when you fetch() the upstream URL, so the main worry is cookies.
// Strip Domain= from Set-Cookie so cookies are scoped to the canonical host.
const cookies = upstream.headers.getSetCookie?.() ?? [];
const cleaned = cookies.map(c => c.replace(/;\s*Domain=[^;]+/i, ''));
upstream.headers.delete('set-cookie');
cleaned.forEach(c => upstream.headers.append('set-cookie', c)); Caching headers
If the secondary origin sets Cache-Control: private, Cloudflare won't cache.
If you trust the upstream's cacheability, you can leave it alone; if you want to cache
aggressively at the edge, override it for static paths.
Content-Security-Policy
CSP is the most common silent breakage when proxying. The upstream typically allows
scripts from its own host: script-src 'self' https://legacy.example.com.
Once served from www.example.com, the browser computes 'self' as the
canonical host — and may now block scripts that load from the (correct) origin.
Three pragmatic options:
- Rewrite: replace the origin host inside the CSP with the canonical host.
- Strip: drop
Content-Security-Policyentirely. Easiest. Loses the protection it offered. - Replace: set your own CSP that covers both origins explicitly.
// Option: rewrite origin host inside the upstream CSP
const csp = upstream.headers.get('content-security-policy');
if (csp) {
upstream.headers.set(
'content-security-policy',
csp.replaceAll(originHost, canonicalHost),
);
} Try it: with and without stripping CSP
Edit the config, then enter a request URL to see what the Worker would do. Nothing is sent over the network — this is a faithful reimplementation of the same rules in the browser.
Path rules (first match wins)
content-security-policy header. Useful as a temporary unblocker; not a long-term answer.
Other headers worth a look
X-Frame-Options— may need to be aligned across origins.Strict-Transport-Security— set this at the canonical host, ignore the upstream's.Server,X-Powered-By— fine to drop; less fingerprinting.