How to Use CloudFront to do WordPress Page Caching

Previously, we looked at WordPress page caching using a content delivery network (CDN). This is an essential tool for speeding up a WordPress site at a global scale. That said, it’s still not commonly used by a lot of WordPress hosts.

With Ymir, you get a CloudFront (Amazon’s CDN) distribution set up to do page caching on production environments by default. This is a great feature of the product. But what if you want to configure CloudFront to do page caching yourself?

Well, this isn’t talked a lot about. In my research, the only article I found was this one on an AWS blog. This article will use that article as a baseline, but will discuss in more detail how to set up CloudFront.

You don’t need to host your WordPress site on AWS

Before we begin, it’s worth nothing that to do this you don’t need to host your site on AWS. This is another problem with AWS article. It only shows you how to do it if you use S3 for assets and an EC2, elastic load balancer or a lightsail instance.

While Ymir only supports AWS, this article won’t use a WordPress site hosted on it. Instead, we’ll use a WordPress site configured on DigitalOcean with Sail. But you could use a WordPress site hosted anywhere.

One handy reason to use Sail is that it comes with a vanity URL. (Something Ymir does as well!) So there’s no need to mess with any DNS configuration for the WordPress server. We’ll still need to add a domain name to use with CloudFront, but it simplifies things a bit!

Architecture overview

For this article, we’re going to keep the architecture simple. It’ll be similar to what the AWS article does. Here’s what it’ll look like.

As you can see in the above diagram, we’re going to use CloudFront to cache static WordPress assets on top of HTML. These are any files found in /wp-content and /wp-includes. This is also what the AWS article does.

The big difference is that we’re not using AWS services like S3 to store static assets. (Something Ymir manages automatically for you each time you deploy.) Instead, we’re going to use the same origin for both regular content and static assets. We’ll go over what an origin and other CloudFront terminology when we configure CloudFront next.

Creating a distribution

The first step is to go to the CloudFront console and create a distribution.

A CloudFront distribution is the entity representing our configured CloudFront CDN with its origins and cache behaviours. To create a distribution, just click the Create distribution button in CloudFront console, as shown above. This will bring up the distribution creation page.

It’s quite big! So we’re going to go through each section and explain what we’re trying to do.

Configuring the origin

The first thing you have to configure when creating a CloudFront distribution is the origin. An origin is a location where CloudFront can go get the original version of a piece of content that it’ll cache.

While the distribution creation page only lets you configure one origin, you can have more than one. That said, for this article, we’ll only need one. For the Origin domain, we enter the vanity domain of the droplet that Sail configured for us.

Once you enter a domain name, you’ll see the origin options change. You’ll have to make a few changes to the default origin configuration. You can see the full configuration below.

First, you’ll want to change the Protocol to HTTPS only since Sail configures our droplet with a Let’s Encrypt SSL certificate.

Next, it’s a good idea to bump up the Minimum origin SSL protocol. That’s because anything other than TLSv1.2 is deprecated. So that’s why I change it to that.

The last small change is optional. By default, AWS will use the domain name as the name of the origin. I change it to sail-droplet.

Configuring the default behavior

The next part of distribution creation form centers on configuring the default cache behavior. A cache behavior defines how CloudFront will cache content. Here we’re defining the default caching behavior, but we’ll configure another one for static assets later.

Above is the default behavior configuration. It’s pretty massive! That said, a lot of it will make sense as we go through it.

The first setting relates to whether CloudFront will compress anything it caches if it can. This great to have! The default is to have that on, so there’s nothing to change.

For Viewer protocol policy, you want to configure it to do HTTP-to-HTTPS redirection for you. Your WordPress site can do that, but it’ll be faster if you have CloudFront handle it.

Next is Allowed HTTP methods. This is an important configuration option because it tells which HTTP methods CloudFront will handle. We want it to handle all HTTP methods, but it’ll only cache GET and HEAD methods. We also added the OPTIONS which is optional.

Cache key

Finally, we want to configure how CloudFront caches content. We do this in the Cache key and origin requests section. The standard way to do this now is to use a cache policy, but, to keep things simple, we’re going to use the legacy cache settings.

Now, how CloudFront generates a cache key is the most important configuration element of a cache behavior. (That’s why it gets its own section!) That’s because this cache key determines if CloudFront will return a cached response or not. You want it to be as generic as possible so that you hit a cache key as often as possible. But you also need to keep the elements that make a WordPress site dynamic.

First, we want to decide which HTTP header to use in your cache key. The only one we want is Origin, which we want for security reasons.

Next, we need to choose which query string values to use for the cache key. WordPress uses query strings pretty extensively. So we’re going to use them all for our cache keys.

Finally, we have cookies. We don’t want to create cache keys using all cookies. Instead, we want to limit it to WordPress cookies. The good thing is that CloudFront supports wildcards in the cookie name, so we don’t have to list them all.

By default, the three WordPress cookies prefixes you want to use for your cache key are:

  • comment_*
  • wordpress_*
  • wp-settings-*

This list will be different depending on the plugins you use. It’s not any different from what you’d exclude with a page caching plugin. You need to exclude all plugin cookies your site needs.

At the end of this, you want to decide how long CloudFront will keep things cached for. By default, we set it to 300 seconds or 5 minutes. This strikes the right balance between keeping things cached for performance, but still keeping things dynamic.


The last section of distribution creation form groups miscellaneous settings. You’ll find a screenshot below, but we want to keep all the default values for now. We’ll revisit some of them later in the article.

Adding additional cache behaviors

Once you press on Create distribution, you’ll go back to the page describing the new distribution. It’s worth noting that it can take up to 20 minutes for AWS to create or update a distribution. So please keep that in mind as we make some changes to it.

On that page, you want to go to the Behaviors tab. This is where we’re going to define additional cache behaviors besides our default one. To begin, click on Create behavior.

Caching static assets

First, we’re going to create behaviors for static assets. This process is a bit tedious because we have to do it for each path that we want to do. Below is the configuration for /wp-includes/*.

We’re going to focus on the settings that differ from the default cache behavior. But first, make sure that you select sail-droplet as the origin. Or if you named your origin something else, find the origin with that name.

Moving on from that. The first thing that’s different in our settings is the Allowed HTTP methods. We only want to allow GET, HEAD, OPTIONS HTTP methods, since we’re only dealing with assets.

The next set of differences are around the cache key. We still want to use headers to generate the cache key. That said, we’re going to add two more: Access-Control-Request-Headers and Access-Control-Request-Method.

But for the rest, we’re going to disable everything. So we won’t use any query string for cache keys. We also won’t use any cookies either. This will ensure that CloudFront aggressively caches our static assets.

And since we want to aggressively cache these assets, we’re going to change the how long they stay cached. The new default is 86400 seconds, which is a day. The maximum is 604800 seconds or a week.

You can adjust this however you see fit. But this is a pretty good baseline. You then want to repeat the process to create a cache behavior for /wp-content/*. This is where using a cache policy can make sense.

After you’re done, you should have something like this:

Never cache the WordPress admin pages

The second set of cache behaviors revolves around the WordPress admin. In no circumstance should you ever cache WordPress admin pages. So let’s look at how we do that.

Above is the cache behavior for /wp-admin/*. This cache behavior is a lot closer to our default one. We go back to allowing all HTTP methods.

The cache is also very similar. We only use the origin header and all query strings to make the cache key. The difference is that we also use all cookies to generate the cache key.

The behavior to not cache any requests comes from the last section, where we set the minimum, maximum and default TTL values. We want to set all these values to zero. This prevents CloudFront from returning cached responses to these requests.

So that’s it for not caching responses for the WordPress admin! Next, you’ll want to create a second cache behavior for the /wp-login.php page as well. Once you’ve done this, you should have these five cache behaviors: