We recently enabled CloudFlare CDN on our domain and noticed that resources always show as EXPIRED or MISS in the response header. Basically this means that the CDN flagged the origin resource as expired and fetched an updated copy from the origin server and served it. Basically, cache is completely being bypassed by CDN.
We posted a support entry the the CloudFlare community and they provided some insight on how to fix this: https://community.cloudflare.com/t/website-images-are-always-miss/202265
Basically this was the issue:
- Our origin server was a node.js server serving our websites and assets (images, css, js etc)
- We deployed our app into a Dokku container running on a server. Dokku is basically an open source Heroku. Dokku serves the app via an NGINX proxy and our domain.
- We then put CloudFlare in front of that.
- When hitting the website via the browser, CloudFlare shows all resources as EXPIRED or MISS but the Cache-Control header in the browser debugger seemed accurate (cache-control: public, max-age=14400)
- Digging deeper into it, it seemed that the origin server (the node.js app) was sending Cache-Control as "Cache-Control: public, max-age=0". CloudFlare then honoured that and EXPIRED the resource and appended the "cache-control: public, max-age=14400" from CDN to Browser. But the real benefit of caching on the CDN was missed.
So, how do you fix it?
1) Find out the origin header but running this command on your terminal. Replace values as needed (including [your origin server ip] which should be your server IP)
curl -k --dump-header - -o /dev/null -H "origin: http://yourdomain.com/" http://yourdomain.com/dist/hero-img.png --connect-to ::[your origin server ip]
2) You will see something like this which shows the origin response headers. Which will show you the issue.
HTTP/1.1 200 OK Server: nginx Content-Type: image/jpeg Content-Length: 41326 Connection: keep-alive X-Powered-By: Express Accept-Ranges: bytes Cache-Control: public, max-age=0 Last-Modified: Mon, 31 Aug 2020 03:18:52 GMT ETag: W/"a16e-17442864d60"
3) Finally, set the correct cache-control header in your node/express server. Once you do this - CloudFlare will pick it up and honour the cache on the CDN.
Happy coding!