Cloudflare Cache Always MISS When Reverse Proxied From Vercel

I am having an almost identical issue to the problem that was discussed at

We’re an enterprise Vercel customer and an enterprise Cloudflare customer. We’re running a NextJS app at which is being reversed proxied and DNS resolved by Vercel. Vercel sends these requests via NextJS rewrites to This subdomain is being reversed proxied and DNS resolved by Cloudflare.

If I go directly to, my CF-Cache-Status headers always return HIT. If I go to, they are always MISS. The closed discussion linked to above references a forwarded header and says the issue was resolved in Discord. I checked the Cloudflare Discord channel and the duplicate post has been deleted (along with its responses).

Does anyone know the details on how to resolve this?

Wasn’t deleted, maybe a bit hard to find though: Discord

Assuming your issue is exactly the same, Vercel’s Nextjs rewrites proxies the request and sends a forwarded header far too changing (it includes client ip, and a signature), fragmenting the cache like crazy to the point where you might never see a HIT.

I just had him configure a modify request header rule to drop it before cache tries to use it, you’d configure it on Under transform rules → Modify request headers → New (Magic Link:

If that doesn’t work, I would create a Cache Rule forcing cache on that hostname, and setting some custom edge ttl, and capturing all the request headers on your origin. Everything that makes up the Default Cache Key (for how a resource is cached by) is documented here: Cache Keys · Cloudflare Cache (CDN) docs

Thanks, I read through the conversation on Discord and this seems like the exact same scenario we’re facing. One thing that Hirvesh was able to do was trace all the headers (including the forwarded header which should eventually be removed via a Cloudflare rule). I think he did so with a CURL statement in his terminal, but I unable to reproduce it.

I ran for i in seq 1 20; do curl -sS -D - -o /dev/null; done in my terminal and got back:

HTTP/2 308 
cache-control: public, max-age=0, must-revalidate
content-type: text/plain
date: Wed, 29 May 2024 21:35:04 GMT
refresh: 0;url=
server: Vercel
strict-transport-security: max-age=63072000
x-vercel-id: sfo1::w55qt-1717018504179-9b808086d97b

The header responses he got back was much more all encompassing and it was also a 200 (which is strange since I thought he should also be getting back a 308 since he’s rewriting from his Vercel reversed proxy URL to his CF subdomain).

I am planning on adding that CF rule to strip out the forwarded header for our subdomain, but we’re a big org here and I have read only permission to our CF dashboard - so it might take a few days before the request goes through. In the meantime, if I can see the same level of headers that Hirvesh was able to see, it would help me more confidently pinpoint the problem

No, he was logging the actual request headers his origin got in the request from Vercel. Your origin wouldn’t be reflecting back forwarded or many other headers unless you did something custom. Lots of layers to the onion. In your case, you’d want to log on the origin behind

1 Like

Wanted to give an update on this. I was able to chase down someone from our infra team to apply the header modification rule and it was indeed the forwarded header. After adding the rule, our static JS and CSS assets started hitting with Cloudflare.

One thing I noticed was that while JS and CSS assets are hitting, images hosted by our origin servers are still missing the cache. I can see that Cloudflare is trying to find a cache for them since they all have the Cf-Cache-Status response header.

Do you know what maybe causing the images to not hit?