I hate configuring cache. My Laravel, Nginx, Cloudflare hell.

Laravel, nginx and cloudflare. I love it when it works...

I've just about recovered from the headache that was caused from configuring cache for a side project recently.

My original setup:

  • nginx cache expires
  • Laravel as the application
  • Cloudflare saving the cache

I have my main website which I wanted to cache for X number of hours, with some pages needing less time than others. I also had some API routes for even less time. The site in the end would also be cached by Cloudflare to reduce server origin requests.

Things I tried and failed:

  • Countless attempts at setting different expires for different location blocks within the nginx conf.
  • Setting headers in the response within Laravel controllers to having it not update at all.


Nothing was working and nothing was updating.

Giving up on handling this within nginx, I moved to see how I could just handle this within my Laravel codebase, and looked to see how Laravel handles cache control headers.

Configuring Laravel with SetCacheHeaders middleware

It turns out there's a less known middleware (not mentioned in the documentation) specifically to handle cache on routes. You can find your middlewares within your App\Http\Kernel.php and see 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class under the route middleware group.

  • This enabled me to apply custom cache headers to my route groups or endpoints Route::get('/','SiteController@index')->name('home')->middleware('cache.headers:public;max_age=1800');
  • Thinking I'd cracked it I went to check my response headers, and saw 14400 coming out of the response headers, even though my value was 1800.
  • Convinced this was actually working and something was being overwritten, I looked into what Cloudflare was doing.

Configuring Cloudflare to respect origin headers

  • Under Page Rules within Cloudflare, it's important when you're wanting to set custom cache levels that within Cloudflare you have "Origin Cache Control", switched on.
  • Also under Caching > Configuration, also make sure you have "Browser Cache TTL" set to "Respect Existing Headers".
  • If either of those are not set, Cloudflare will set its own cache level and will ignore anything you've set.

After taking cache into my own hands, and configuring Cloudflare to work with it correctly I've now got different endpoints with different levels of cache time.

The TLDR:

  • Disabled nginx cache headers
  • Handled cache control headers with Laravel
  • Made sure Cloudflare respected my headers


I hate configuring cache, but it's awesome when it finally works.