Skip Navigation
2 Jun 2024 • 6 min read • 1

Development - Solving Custom 404 Error Pages with Cloudflare Workers

Ever had one of those days where nothing seems to go right? You’re trying to make your website perfect, but instead, it’s like the universe is playing a cruel joke on you. That was me recently, tangled in a web (pun intended) of frustrations while trying to set up a custom 404 error page for my website. Hosted with Docker and NGINX, my site stubbornly displayed the default NGINX ‘Page Not Found’ message instead of my sleek, custom 404 page. After countless failed attempts to fix it, I decided to call in reinforcements—Cloudflare Workers. If you’re nodding your head in sympathy, keep reading. This post is for you.

The Problem: NGINX Custom 404 Pages

Let’s set the scene: You’ve got your website hosted with Docker and NGINX. Everything’s going smoothly until you try to set up a custom 404 error page. Despite trying every configuration under the sun, NGINX insists on showing its own ‘Page Not Found’ message. Not only is this frustrating, but it also creates a jarring user experience. And let’s be honest, it’s not the impression you want to leave on your visitors.

This issue is more common than you might think, especially with custom hosting solutions. While a deep dive into NGINX configurations might eventually yield results, sometimes you just need a quick and effective solution. That’s where Cloudflare Workers come into play.

Image

What are Cloudflare Workers?

Think of Cloudflare Workers as your secret weapon. They are serverless functions that run on Cloudflare’s edge servers, allowing you to execute JavaScript code to handle requests and responses. This means you can manipulate traffic before it even hits your server, providing a faster and more flexible way to manage your website’s content. Since I was already using Cloudflare for DNS, DDoS protection, and security, adding Workers to my arsenal was an easy decision.

Image

The Solution: Cloudflare Workers to the Rescue

Instead of endlessly tweaking NGINX configurations, I decided to let Cloudflare Workers handle my custom 404 page. Here’s how I did it:

  1. Set Up a Worker: First, I created a Cloudflare Worker to handle the incoming request and check for a 404 status.
  2. Fetch and Stream the 404 Page: If the response was a 404 and the request accepted HTML content, the worker would fetch my custom 404 page and return it.
  3. Deploy the Worker: Finally, I deployed the worker and set up a route rule to intercept 404 responses.

Here’s the magic code for my Cloudflare Worker:

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});

async function fetchAndStreamNotFoundPage(resp) {
  const { status, statusText } = resp;
  const { readable, writable } = new TransformStream();

  const response = await fetch("https://dillonbaird.io/404.html");
  const { headers } = response;

  response.body.pipeTo(writable);

  return new Response(readable, {
    status,
    statusText,
    headers
  });
}

function isHTMLContentTypeAccepted(request) {
  const acceptHeader = request.headers.get("Accept");
  return (
    typeof acceptHeader === "string" && acceptHeader.indexOf("text/html") >= 0
  );
}

async function handleRequest(request) {
  const response = await fetch(request);

  if (response.status === 404 && isHTMLContentTypeAccepted(request)) {
    return fetchAndStreamNotFoundPage(response);
  }

  return response;
}

Step-by-Step Guide

1. Create a Cloudflare Worker:

  • Log in to your Cloudflare account.
  • Navigate to the Workers page and create a new Worker.
  • Copy and paste the above code into the Worker script (modify your domain / 404 page path obviously).
Cloudflare Worker Setup

2. Set Up a Route Rule:

  • On your website/domain page, go to the “Worker routes” section.
  • Add a new route to match all requests to your domain (e.g., *dillonbaird.io/*).
  • Select the Worker you just created.
Cloudflare Route Rule

3. Deploy and Test:

  • Save your Worker and route rule.
  • Test your website by navigating to a non-existent page. You should now see your custom 404 page.
Custom 404 Page in Action

Why This Works

Leveraging Cloudflare Workers allowed me to quickly and efficiently solve my custom 404 error page issue. Let’s break down how the code achieves this.

Event Listener for Fetch Requests

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});

This snippet sets up an event listener that listens for fetch events. Whenever a request is made to your site, this event listener triggers and calls the handleRequest function, passing the request object to it.

Handling Requests and Fetching the Custom 404 Page

async function fetchAndStreamNotFoundPage(resp) {
  const { status, statusText } = resp;
  const { readable, writable } = new TransformStream();

  const response = await fetch("https://dillonbaird.io/404.html");
  const { headers } = response;

  response.body.pipeTo(writable);

  return new Response(readable, {
    status,
    statusText,
    headers
  });
}

This function handles fetching and streaming the custom 404 page. It first extracts the status and status text from the original response. Then, it creates a TransformStream to handle the readable and writable streams for the response body. It fetches the custom 404 page, pipes the response body into the writable stream, and returns a new Response object containing the custom 404 page with the original status and headers.

Checking for HTML Content Type

function isHTMLContentTypeAccepted(request) {
  const acceptHeader = request.headers.get("Accept");
  return (
    typeof acceptHeader === "string" && acceptHeader.indexOf("text/html") >= 0
  );
}

This function checks if the request accepts HTML content by examining the Accept header. If the header contains text/html, it returns true; otherwise, it returns false. This ensures that the worker only serves the custom 404 page to requests expecting HTML content.

Handling the Request

async function handleRequest(request) {
  const response = await fetch(request);

  if (response.status === 404 && isHTMLContentTypeAccepted(request)) {
    return fetchAndStreamNotFoundPage(response);
  }

  return response;
}

The handleRequest function fetches the original request and checks if the response status is 404 and if the request accepts HTML content. If both conditions are met, it calls fetchAndStreamNotFoundPage to fetch and return the custom 404 page. Otherwise, it returns the original response.

Conclusion

Using Cloudflare Workers to handle custom 404 error pages is a game-changer. It’s quick, efficient, and leverages the power of Cloudflare’s edge network. Plus, it saves you from the headache of fiddling with server configurations. Give it a shot, and let me know how it works for you!

FAQs

Answers to the most frequently asked questions.

What is a Cloudflare Worker?

A Cloudflare Worker is a serverless function that runs on Cloudflare’s edge servers, allowing you to execute JavaScript code to handle requests and responses.

How does Cloudflare Workers help with custom 404 error pages?

Cloudflare Workers can intercept 404 responses from your server and return custom error pages, improving user experience and SEO.

How do I set up a Cloudflare Worker?

Log in to your Cloudflare account, navigate to the Workers tab, create a new Worker, and paste the provided JavaScript code. Set up a route rule to match requests to your domain, select the Worker, and deploy it.

Can I use Cloudflare Workers for other tasks?

Yes, Cloudflare Workers can be used for various tasks such as caching, redirecting traffic, modifying responses, and enhancing security. They provide a powerful way to manage your website’s behavior at the edge.

Is using Cloudflare Workers cost-effective?

Cloudflare Workers offer a pay-as-you-go pricing model, making them cost-effective for both small and large-scale applications. Free up to 100,000 requester per day. 10m request per day on standard subscription @ $5 per month, with additional $0.30/month per additional 1m requests.

Latest Blog Posts

Hi, my name is Dillon Baird, and I’m a progress bar-aholic. There, I said it. It feels good to get that off my chest. It’s a problem, I know. But like any true addiction, I can’t help myself. Those little bars, those tiny digital beacons of hope, they’re my kryptonite. “I’m a progress bar enthusiast, a connoisseur of digital waiting.” - Dillon

June 15, 2024 • 5 min read

Large language models (LLMs) are powerful tools, but running them on your own can be a challenge. Ollama simplifies this process, allowing you to run these advanced models directly on your local machine, without the need for expensive cloud services or specialized hardware. With Ollama, you gain complete control over your AI tools. Customize them to your specific needs and experiment freely without worrying about high costs. Plus, you can break free from reliance on cloud providers.

May 11, 2024 • 16 min read

I’ve encountered countless scenarios where sticking rigidly to best practices wasn’t the optimal path. These experiences have underscored the value of flexibility and its critical role in navigating complex software environments. Today, I’m eager to share insights on when to adhere to these practices and when deviating can enhance innovation and ensure project success. This guide explores how adopting a more adaptable approach can enhance team dynamics and improve project outcomes.

April 24, 2024 • 14 min read

Join My Newsletter
Stay in the loop with all of my latest content.
Subscribe to Feed
Still using an old-school RSS reader like me?
1 comment

GitHub-flavored Markdown & a sane subset of HTML is supported.