Browser Headers and WordPress

We’ve been running WordPress using Cloudfront as a full-site front-end cache with a low TTL and it’s been great overall, but one pain point has been which headers to whitelist in the origin configuration. This is pretty important: origin behavior governs what data Cloudfront passes back to the actual containers (or EC2 instances, it doesn’t matter in this case) serving your WordPress site. Omitting the wrong headers can have some fairly drastic consequences, like rich-text editors not displaying or REST API calls failing. This post takes Cloudfront as its example, but this would be relevant with any solution where you’re defining an allowlist of headers instead of just passing everything.

Behaviors

Before tackling headers, let me say a few words about behaviors in Cloudfront. Carl Alexander does a great job on this in How to use CloudFront to do WordPress page caching. For each behavior in Cloudfront you can define a different origin (e.g. Fargate containers, an S3 bucket, a Lambda function), which HTTP methods to allow, which headers to allow, what the caching policy should be. You differentiate behaviors by path. In a WordPress install, that means you could define different behaviors for each of the following paths:

  • /wp-admin/*
  • /wp-content/*
  • /wp-includes/*
  • /wp-json/*
  • /wp-login.php
  • * (default, anything not matched above)

You probably don’t want caching at all on /wp-admin/*, /wp-login.php, or /wp-json/*, but a fairly aggressive cache on /wp-content/*, since it’s mostly static assets.

Headers

Host and Origin

Host and Origin are obvious and your platform won’t work without them, promise.

Referer

Referer (note the spelling) is necessary on wp-login.php if you want to be correctly passed back after login. Jeffrey Everhart mentioned problems with admin-ajax.php if Referer wasn’t allowed on /wp-admin/*; I haven’t seen that behavior.

User-Agent

User-Agent is a pretty common header and a pretty important one, as it turns out. We don’t need it for browser detection per se; we need it because, as Jeffrey Everhart noted back in 2018, the rich-text editor that ships with WordPress won’t display if the User-Agent header is empty. Jeff’s config includes User-Agent with /wp-admin/*, but you may want it with the default case as well. One sample use case: you have a public Gravity Forms form with a text field that allows rich-text editing.

X-WP-Nonce

X-WP-Nonce is a special WordPress-specific header used with authenticated WP REST API requests, and you need to allow it whether you’re doing those or not. Why? Because the WordPress SIte Health functionality that tests the REST API will fail every time if that header isn’t set, and so will any plugin that leverages that functionality. Redirection is one prominent example. Allow it on /wp-admin/* and /wp-json/* at minimum.