Cache static pages in Laravel by Cloudflare CDN

Published 02 December 2019 12:00

Some of the websites I made don't need to be updated very often, but they receive in some periods a lot of traffic within minutes. To make the website faster and reduce the amount of database queries executed I want my CDN (in this case, Cloudflare) to cache those static pages for 5 minutes.

When you use Cloudflare CDN you can enable caching for specific DNS records within the Dashboard. But what does Cloudflare caching?

Caching is the process of storing copies of files in a cache, or temporary storage location, so that they can be accessed more quickly. Technically, a cache is any temporary storage location for copies of files or data, but usually the term is used in reference to Internet technologies. DNS servers cache DNS records for faster lookups, CDN servers cache content to reduce latency, and web browsers cache HTML files, JavaScript, and images in order to load websites more quickly.

More information can be found at https://www.cloudflare.com/learning/cdn/what-is-caching/.

Enable caching in Laravel

I've made a middleware (CachePagesMiddleware) that set the correct headers for Cloudflare to cache the response and let them serve the next requests. This means the servers of Cloudflare will serve the page before it hits my application.

<?php

namespace App\Http\Middleware;

use Closure;
use Symfony\Component\HttpFoundation\Response;

class CachePagesMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        if ($this->shouldCacheResponse($request, $response)) {
            $response->headers->add([
                'Cache-Control' => 'max-age=1800, public'
            ]);
        }

        return $response;
    }

    public function shouldCacheResponse($request, Response $response)
    {
        if (!config('app.env') == 'production') {
            return false;
        }

        if (auth()->check()) {
            return false;
        }

        if ($request->method() !== 'GET') {
            return false;
        }

        if (! $response->isSuccessful()) {
            return false;
        }

        return true;
    }
}

To use this, I've added the middleware to all the routes I wanted to be cached. I have not enabled this by default because I want to have the control about which routes are being cached and if I forget to disabled the caching for the specific route it can possibly leak information (of course, you never want this to happen!).

In the HTTP kernel (app/Http/Kernel.php) I added them as a route middleware:

protected $routeMiddleware = [
    'cache' => \App\Http\Middleware\CachePagesMiddleware::class,
    ...
];

And added them to the routes that I wanted to be cached:

Route::get('/my-pages', '[email protected]')
    ->middleware('cache');

Help! Cloudflare is not caching my HTML pages

That can be possible, by default Cloudflare doesn't cache HTML pages. If Cloudflare didn't cache the page you have to take a look at the "CF-Cache-Status" header in the response. If this is "DYNAMIC" you have to create a page rule to cache the page. By default Cloudflare isn't caching html content.

When do you not need to cache the response?

Some pages doesn't need to be cached, this can be a form request, when you are authenticated or when the request isn't successful.

How to test if Cloudflare caches the response?

There is a site for this that checks how Cloudflare. It looks at the "CF-Cache-Status" header send by the response to verify if the page is cached by Cloudflare. More information can be found here: https://cf-cache-status.net/

Robin Dirksen

Robin Dirksen

On my blog, you can find articles that I've found useful or wanted to share with anyone else.

If you want to know more about this article or just want to talk to me, don't hesitate to reach out.