For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Thinking Outside the Box: Rewriting Web Pages with F5 Distributed Cloud (XC)

Welcome to a new article series where we tackle complex application delivery needs and solve tricky requirements with creative solutions in F5 Distributed Cloud (XC). When you're faced with a tricky requirement, sometimes the most elegant solution comes from thinking a little differently about the tools you already have.

Have you ever needed to change something on your website—like updating links from HTTP to HTTPS or replacing a product name—without wanting to touch the backend code? It’s a common requirement, and the solution often involves spinning up a whole new proxy layer like NGINX or BIG-IP just for that one task.

But what if you could do it with the tools you already have in F5 XC?

While XC doesn’t have a big red button labeled "Rewrite My Page," it has a wonderfully clever feature that lets us do just that. We can ask XC to inject a small JavaScript snippet into a web page. This script then acts like a tiny, dynamic editor, making changes on the fly as the page renders in the user’s browser.

In this article, I’ll show you how to set this up in a simple, reusable way, covering three of the most common use cases:

  1. Rewriting in-page links (e.g., changing all http:// links to https://)
  2. General, pattern-based search and replace for any text on the page
  3. Serving interstitial pages 

Let’s dive in.

 

The Two-Step Configuration

Our magic trick involves two main steps:

  1. Hosting the JavaScript: We’ll create a special Route in XC whose only job is to serve our JavaScript code when requested.
  2. Injecting the JavaScript: We’ll create another Route to tell XC which web pages to modify and what rewrite patterns to use.

 

Step 1: Give Your JavaScript a Home

First, we need to make our JavaScript files available. We’ll configure a custom Route object that responds directly to the JavaScript code. It’s best to create this in the Shared namespace so any Load Balancer in your tenant can use it.

 

  1. Get the Code

You can find the necessary JavaScript files in this public GitHub repository:

The repository contains two distinct scripts designed for different tasks. You can use either one by itself or both together on the same page, depending on your requirements:

  • link-rewriter.js: Specifically targets <a> tags to modify URLs.
  • text-replacer.js: Performs a REGEX-based search and replace across the entire page content.

Both scripts are designed to be configurable, so you don’t need to edit the code itself.

 

  1.  Create a Custom Route Object:

A. In the F5 XC Console, go to the Shared Configuration tile.

B. Navigate to Manage > Routes > Add Route.

C. Give your route a name (e.g., js-page-rewrite) and add a single Route configuration with the following details:

Request Match:

  • HTTP Method: GET
  • Path Match: Prefix with the value /page-rewrite.js (or any unique path you prefer).

Action:

  • Set the action to Direct Response.
  • Response Code: 200
  • Response Body: Paste the full JavaScript code you copied from one of the links above.
  • Toggle "Show Advanced Fields" and find Response Headers to Add. Add a header with the name Content-Type and the value text/javascript.

D. Save the route.

Custom Route Object to serve the text-replacer JavaScript

Now, whenever any LB uses this route, a request to /page-rewrite.js will serve up your script. This script is smart enough to accept search and replace with parameters directly from the URL, which we’ll set up in the next step.

Optionally, you can host the second script in the same way. For example, you could create another custom object route called "js-url-rewrite" that serves the link-rewriter.js code on the /js-rewrite.js path.

My two custom route objects (serving two JavaScripts)

Step 2: Tell the Script What to Do

Now we’ll configure our Load Balancer. This involves adding two routes: one to make our JavaScript available, and another to inject it into the right pages with the right instructions.

  1. Navigate to the Multi-Cloud App Connect tile, select your namespace, and edit the desired Load Balancer.
  2. Go to the Routes configuration section.
  1.  First, add the JavaScript Custom Route Object(s)

         For this, let’s add the route we created in Step 1.

  • Click Add Item.
  • Route Type: Custom Route Object
  • Reference to Custom Route: Select the route you created (e.g., shared/js-page-rewrite).
  • Apply the change. It’s a good idea to drag this route to the top of your route list to ensure it’s evaluated first.
  1. Next, add the Injection Route

       For this, we’ll create a route that targets our web pages and injects the script.

  • Click Add Item again.
  • Route Type: Simple Route
  • HTTP Method: ANY
  • Path Match: Define which pages you want to rewrite. To rewrite everything, use Prefix with /. For a specific section, you might use Prefix such as /2rewrite.
  • Origin Pool: Select your default origin pool for the LB.
  • Scroll down and click Advanced Options.
  • Find the section Bot Defense & Risk Management Javascript Injection and configure Insert JavaScript Tag:
    • Set the drop-down to Enable.
    • Click Configure.
    • Click Add Item to define your script tag.
      • URL: This is where the magic happens. You’ll specify the path to your script and pass it the search/replace parameters. The parameters must be URL-encoded. Example: To replace all instances of “domestic cat” with “happy dog”, the URL would be:

        /page-rewrite.js?search=%2Fdomestic%20cat%2Fgi&replacewith=happy%20dog

        Here, %2Fdomestic%20cat%2Fgi decodes to the regex pattern /domestic cat/gi 

        For a regex, format it like: /pattern/flags (e.g., /domestic cat/gi)

        * > 'g' flag = global (replace all instances, not just the first).

        * > 'i' flag = case-insensitive (match 'Cat', 'CAT', etc.).

      • Tag Attributes: Add an attribute with the name "DEFER" and leave the value empty. This tells the browser to run our script only after the page is fully loaded, which is critical.
      • Pro Tip: Multiple Rewrites: This solution fully supports multiple rewrites on the same page (see screenshots below). If you need to replace several different patterns, simply click "Add Item" again and insert another <script> tag with a new search and replace with parameters. The scripts will run sequentially in the order you add them.
  • Apply and Reorder: Click Apply. Drag your new content rewrite route so it's evaluated before your other routes if needed.

    JavaScript Tags are configured as part of the "Advanced Options" in Route object configuration
    Multiple rewrite JavaScripts can be inserted to perform multiple rewrites
Example of Routes on the LB - including two JavaScripts to rewrite the links and patterns, and the last route to insert the JavaScript tags on the page

Testing Your Rewrite

Now for the fun part. Browse to a page that matches the path you configured.

Before:

Before Rewrite

After:

All instances of "domestic cat" are replaces by "happy dog". Also the links are rewritten from http:// to https://

Success! The text and links have been changed dynamically, with no changes to your backend server.

 

Bonus Section: Serving Interstitial Page & Request Replay

Sometimes, you need the user to replay the request with some modifications. A common use case for this is when traditional server-side redirects (like HTTP 301/302) are difficult or inefficient to manage programmatically in modern environments like serverless platforms or even on XC LB. This is where a client-side JavaScript rewrite becomes an incredibly effective alternative.

Here is the process:

  1. Serve an Interstitial HTML Page: You configure a custom route object to look for the www. prefix in the request's hostname. This is done using a Regex match (e.g., "host: www.*") on the host header. Instead of issuing a redirect status code, the Route simply serves the content of the lightweight HTML page directly. The source HTML for this page can be found here:
    https://github.com/kayvanx/f5xc-page-rewrite-js/blob/main/rewrite-redirect-from-www.html
  2. Client Execution: As soon as that minimal page loads, the embedded JavaScript takes control. It inspects the URL, strips out the www., and then uses window.location.replace() to immediately reload the browser to the correct, clean domain. Crucially, the script ensures that the entire original path, all query parameters, and any hash fragments are perfectly preserved.

This method results in a quick, clean jump for the user, achieving the same result as a standard redirect but powered entirely by the client's browser.

 

Limitations and Considerations

This is a powerful technique, but keep a few things in mind:

  1. Injection Point: F5 XC injects the script tag at one of a few predefined locations (<head>, </title>, or the first <script> tag). Your origin page's HTML must contain one of these tags for the injection to work.

  2. Dynamic Content: The scripts run once on page loads. They won’t affect content that is loaded dynamically later (e.g., from an API call after the page is already visible).

  3. CSP (Content Security Policy): If your origin web server sends a strict CSP header, it might block this injected script from running. To fix this, you can modify the CSP header on the same route where you enabled injection. The simplest policy to allow the script is Content-Security-Policy: script-src 'self';. Note that you can insert this CSP header as a Response Header in the route.

  4. CORS (Cross-Origin Resource Sharing): Because we are hosting and injecting the script on the same domain (our LB's domain), CORS is not an issue. Otherwise, it needs to be modified.

 

Conclusion

The F5 Distributed Cloud platform is full of advanced functionalities that, with a little creativity, can solve tricky requirements in surprisingly simple ways. This client-side rewrite technique is a perfect example of using native tools to avoid adding complexity to your infrastructure.

Stay tuned for the next article in this series, where we’ll explore more creative solutions!

 

Useful Links:

Published Nov 12, 2025
Version 1.0
No CommentsBe the first to comment