Configuring CloudFlare with Drupal 8 to protect the Pi Dramble

In a prior post on the constraints of in-home website hosting, I mentioned one of the major hurdles to serving content quickly and reliably over a home Internet connection is the bandwidth you get from your ISP. I also mentioned one way to mitigate the risk of DoSing your own home Internet is to use a CDN and host images externally.

At this point, I have both of those things set up for www.pidramble.com (a Drupal 8 site hosted on a cluster of Raspberry Pis in my basement!), and I wanted to outline how I set up Drupal 8 and CloudFlare so almost all requests to www.pidramble.com are served through CloudFlare directly to the end user!

CloudFlare Configuration

Before anything else, you need a CloudFlare account; the free plan offers the minimal necessary features (though you should consider upgrading to a better plan if you have anything beyond the simplest use cases in mind!). Visit the CloudFlare Plans page and sign up for a Free account.

If you have a CloudFlare Enterprise subscription, it would be much more efficient to use Cache Tags along with the Cloudflare module for Drupal 8. Free or Pro users could also use the Cloudflare module to purge content by URL. Since most readers of this post use the free, this post is geared towards a very simple implementation for that audience.

Once there, you can add your site and use all the default settings for security, SSL, DNS, etc. You'll have to configure your website's DNS to point to CloudFlare, then CloudFlare will have some DNS records that point to your 'origin' (the server IP where your Drupal 8 site is running).

After all that's done, go to the Caching section and choose the 'Standard' level of caching, as well as 'Always Online' (so CloudFlare keeps your static site up even if your server goes down).

The most important part of the configuration is adding 'Page Rules', which will allow you to actually enable the cache for certain paths and bypass cache for others (e.g. site login and admin pages). Free accounts are limited to only 3 rules, so we have to be a bit creative to make the site fully cached but not accidentally lock ourselves out of it!

We'll need to add three rules total:

  1. A rule to 'cache everything' on www.pidramble.com/*
  2. A rule to 'bypass cache' on www.pidramble.com/user/login (allows us to log into the site)
  3. A rule to 'bypass cache' on www.pidramble.com/admin/* (allows content management and administration)

The free account 3-rule limitation means that we have to do a little trickery to bypass the cache on non-admin paths when we're working on the site. Otherwise, our options would be to have some sort of alternate URL for editing (e.g. edit.example.com) that bypasses CloudFlare, or turn off caching entirely while doing development work through the CloudFlare-powered URL!

One major downside to this approach—URLs like node/[id]/edit, if accessed by someone who is not logged in, will be cached in CloudFlare as a '403 - Access Denied' page, and then you won't be able to edit that content (even when logged in) unless you purge that path from CloudFlare or use a different workaround mentioned above).

www.pidramble.com CloudFlare caching rules for Drupal 8

For the three rules, set the following options (only the non-default options you should change are shown here):

'cache everything' on /*:

  • Custom caching: Cache everything
  • Edge cache expire TTL: Respect all existing headers
  • Browser cache expire TTL: 1 hour (adjust as you see fit)

'bypass cache' on /user/login:

  • Custom caching: Bypass cache
  • Browser cache expire TTL: 4 hours (adjust as your see fit)

'bypass cache' on /admin/*:

  • Custom caching: Bypass cache
  • Browser cache expire TTL: 4 hours (adjust as you see fit)

Drupal 8 Configuration

To make sure CloudFlare (or any other reverse proxy you use) caches your Drupal site pages correctly, you need to make the following changes to your Drupal 8 site:

  1. Make sure the 'Internal Page Cache' module is enabled.
  2. Set a 'Page cache maximum age' on the Performance configuration page (/admin/config/development/performance).
  3. Add a few options to tell Drupal about your reverse proxy inside your settings.php file:

Inside sites/default/settings.php, add the following configuration to tell Drupal it is being served from behind a reverse proxy (CloudFlare), and also to make sure the trusted_host_patterns are configured:

<?php
// Reverse proxy configuration.
$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = array($_SERVER['REMOTE_ADDR']);
$settings['reverse_proxy_header'] = 'HTTP_CF_CONNECTING_IP';

$settings['omit_vary_cookie'] = TRUE;

// Trusted host settings.
$settings['trusted_host_patterns'] = array(
 
'^pidramble\.com$',
 
'^.+\.pidramble\.com$',
);
?>

Once you've added this configuration, open another browser or an incognito browser session so you can access your site as an anonymous user. Click around on a few pages so CloudFlare gets a chance to cache your pages.

You can check that pages are being served correctly by CloudFlare by checking the HTTP headers returned by a request. The quickest way to do this is using curl --head in your terminal:

$ curl -s --head http://www.pidramble.com/ | grep CF
CF-Cache-Status: HIT
CF-RAY: 25bf2a08a7f425a3-ORD

If you see a value of HIT for the CF-Cache-Status, that means CloudFlare is caching the page. You should also notice it loads very fast now; for this site, I'm seeing the page load in < .3 seconds when cached through CloudFlare; it takes almost twice as long without CloudFlare caching!

2022 Update: It looks like Cloudflare reports headers using all lowercase now, e.g. cf-cache-status and cf-ray. So you should use grep cf instead of grep CF.

Comments

Hi, I haven't tried this yet but in the Cloudflare cache rules docs I see read that:
"CloudFlare Cache Everything will automatically respect any default cache headers set by the web server"
This would mean that you don't really need the Cloudflare page rules as you can just use a module like CacheExclude or some custom code to disable page cache on urls that should not be cached. If you try that let me know if it works :)

source: https://support.cloudflare.com/hc/en-us/articles/200172266-What-do-the-…-

Good idea; I remember trying this briefly but running into a couple weird issues, which is why I went back to the rules. Honestly, I was only able to devote part of an evening to it, which is why I gave up once I got an easy/workable solution. It looks like it's been ~3 years since the module has last been updated, though, so hopefully there are some other simple ways to try this out with D8.

The three rules you specified are far more complex than is necessary. Furthermore, they are guaranteed to result in stale content for anonymous users. Finally, some kinds of interactivity is simply not going to work for anonymous users.

In other words: your proposed solution is in fact broken. It's the best we could do in Drupal 7. In Drupal 8, we can do much better, thanks to cache tags.

See my talk about Drupal 8 + CloudFlare (http://wimleers.com/talk/caching-at-the-edge-cdns-for-everyone) and the live demo (http://cachetags.demo.wimleers.com/).

Unfortunately, this only holds true for Enterprise CloudFlare subscriptions (at least according to this doc), which for many are prohibitively expensive. The free tier has to live with the same caching limitations as a D7 site.

But I will add a note that you can bypass much of this halfway-solution if you have an Enterprise CloudFlare subscription, using Cache Tags.

Manually configuring the CloudFlare is a pain. A better alternative is to use a managed hosting platform, like Cloudways, where CloudFlare can be enabled or disabled by just clicking a button. I think this is a better option than manually configuring it and going through all the trouble of writing commands in CLI.

I see you are using name.com for your domain name register. How do you update your IP address when your internet provider changes your IP address?
Mike

I'm fortunate to have a plan where the IP address remains at least relatively static. I have only had to change the IP address in CloudFlare once in the past two years, and that was after upgrading my cable modem.

Hey Jeff! It's been a minute since this post, but it's still helpful and relevant.

I wanted to share that we ran into issues with password reset links with these rules and we needed to change the user bypass rule from user/login to user/* so that user/reset/... URLs would bypass cache and not result in "Access denied".

Do these settings (format & syntax) still work in settings.php for Drupal 9 & 10?