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:
test.kevquirk.com- the domain configured in the Bunny pull zonesrc.qrk.one- the origin domain on my VPS, where the site actually lives
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:
- I visited
test.kevquirk.com/feed. - Bunny checked its cache. It wasnโt there, so it asked my origin for the file.
- But Bunny made that request using its own hostname (
src.qrk.one), not the one I typed. - Apache saw the request coming from
src.qrk.one/feedand applied the.htaccessredirect to/feed.xml. - Apache then rebuilt the redirect URL using the hostname it was given, which was
src.qrk.one.
So Apache went:
โOh, you want
/feed? Sure. Thatโs atsrc.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:
- Enable Forward Host Headers in my Bunny pull zone.
- Add
test.kevquirk.comas a domain alias ofsrc.qrk.oneon 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, notsrc.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!)
I've managed to get my Jekyll based site working behind Bunny CDN, while maintaining my .htaccess redirects. Here's how I did itโฆ