Giving My Jekyll Site a CDN Front End

I've managed to get my Jekyll based site working behind Bunny CDN, while maintaining my .htaccess redirects. Here's how I did it...

Since switching back to Jekyll recently, Iโ€™ve been running this site on a Ionos-hosted VPS, then using a little deploy script to build the site and rsync it up.

This all worked fine, but I really wanted to use Bunny CDN for more than just hosting a few images and my custom font. Being a static site, I could have dumped everything onto their storage platform, but I have a metric tonne of redirects in a .htaccess file from various platform migrations over the years.

Bunnyโ€™s Edge Platform could have handled these, but with the number of redirects I have, it would have been a slog to maintain. So I assumed Iโ€™d never be able to put Bunny in front of my Jekyll site easily and went about my business.

๐Ÿ’ก Then I had an epiphany.

What if I created a Bunny pull zone that uses kevquirk.com as the public domain, then set up a separate domain on my VPS, host the site there, and use that as the pull zone origin?

My theory was that Bunny would still be requesting content from the VPS, so my .htaccess redirects might still work.

โ€ฆturns out, they did.

Some small bugs

I duplicated my live site so I could experiment safely. The setup looked like this:

The first thing I had to do was update the url field in my Jekyll _config.yml from kevquirk.com to test.kevquirk.com, rebuild the site, and upload it to src.qrk.one.

Now, you might be thinking, โ€œKev, why build the site with the wrong domain?โ€

But I havenโ€™t. By building the site with the test domain, all links point to test.kevquirk.com/.... If I built it with the origin domain, all internal links would lead to the wrong place. They would still work, but the site would be served from src.qrk.one, which is not what I want.

Next up was redirect testing. I visited /feed, which should hit .htaccess and redirect to /feed.xml. The redirect worked fine, but the resulting URL was being served from the origin domain.

So instead of seeing test.kevquirk.com/feed.xml I saw src.qrk.one/feed.xml.

This happened because Bunny requested the file from the origin using its own hostname, not the hostname I typed. In simple terms:

So Apache went:

โ€œOh, you want /feed? Sure. Thatโ€™s at src.qrk.one/feed.xml. Here ya goโ€ฆโ€

Fixing the problem

This would not break anything for visitors, but I didnโ€™t want src.qrk.one appearing anywhere. It looked messy.

Two changes fixed it:

  1. Enable Forward Host Headers in my Bunny pull zone.
  2. Add test.kevquirk.com as a domain alias of src.qrk.one on my VPS.

Forward Host Headers makes Bunny tell the VPS the hostname the visitor used. So instead of:

โ€œIโ€™m asking for this on behalf of src.qrk.one.โ€

Bunny says:

โ€œIโ€™m asking for this on behalf of test.kevquirk.com, not src.qrk.one.โ€

The domain alias ensures Apache accepts that hostname and serves it correctly.

Magic. ๐Ÿช„๐Ÿ‡

The other thing to double-check is that every page sets a proper canonical URL. The origin domain is publicly accessible, so crawlers need to know which domain is the real one. That should always be the Bunny pull zone domain.

In Jekyll this is simple. Add the following to the head section of your layout:

<link rel="canonical" href="{{ page.url | absolute_url }}">

The final straight

With the redirect behaviour sorted, the last step was to add a purge step to my deploy script so Bunny knows to fetch the latest version whenever I publish a new post or update something.

Hereโ€™s the snippet I added:

# --- Clear Bunny Cache ---
echo "๐Ÿ—‘ Clearing Bunny Cache..."
PURGE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
  -H "AccessKey: $BUNNY_ACCESS_KEY" \
  "https://api.bunny.net/pullzone/$PULL-ZONE-ID/purgeCache")

if [ "$PURGE_RESPONSE" -ne 200 ] && [ "$PURGE_RESPONSE" -ne 204 ]; then
  echo "โš ๏ธ  Bunny purge failed (HTTP $PURGE_RESPONSE)"
  exit 1
fi

I set my Bunny API key and Pull Zone ID as variables at the top of the script. The if statement simply says, โ€œIf the response isnโ€™t 200 or 204, tell Kev what went wrong.โ€

And that is it. Last night I flipped the switch. Bunny CDN now sits in front of the live site. I also moved the VPS from Ionos to Hetzner because Ionos now charge extra for a Plesk licence. I went with Hestia as the control panel on the new server.

If you spot any bugs, please do let me know, but everything should be hopping along nicely now. (See what I did there? God Iโ€™m funny!)

โœ‰๏ธ Reply by email

I've managed to get my Jekyll based site working behind Bunny CDN, while maintaining my .htaccess redirects. Here's how I did itโ€ฆ

kevquirk.com/blog/giving-my-jekyll-site-a-cdn-front-end/

๐Ÿ‘ˆ๐Ÿป The one before
Email Is Amazing, but People Try Their Best to Ruin It