You appear to be offline. Some site functionality may not work.

Redirects

Your servers often have to handle millions of requests for old and non-canonical URLs. This can cause unneeded load, as well as make logs messier and, if you have recently changed your site's URL scheme, you might be redirecting a lot! Learn how to shift all your static redirects to the edge using an Edge dictionary.

  • LEARN

    Start coding from the instructions below. Make the tests pass!

  • PLAY

    Try out a fully functional example. Just press play.

  • USE

    Add this solution to a service in your Fastly account

Illustration of pattern concept

Instructions

  1. Create a dataset of redirects as a VCL table

    Redirects can be based on complex patterns or exact URL path matches. The latter allows us to use a VCL table key-value store, for a fast lookup and minimal code. Start by creating a VCL table:

    INIT
    table solution_redirects {
      "/source1": "/dest1",
      "/source2": "/dest2"
    }

    It is possible to update these values via an HTTP API call, using an Edge dictionary, which is exposed in VCL in the same way as the table above.

  2. Match inbound requests against redirect table

    Now you have created a data structure containing the source and destination URLs, the next step is to identify inbound requests that match one of your redirection patterns. The req.url variable exposes the portion of the requested URL following the hostname, which may include a query string. For redirection purposes the query string usually doesn't matter, so we'll use req.url.path, which extracts just the path portion. If you want to match the query as well, strip off the .path suffix.

    RECV
    if (table.lookup(solution_redirects, req.url.path)) {
      error 818 "redirect";
    }

    Now, when a request matches one of your source paths, it will trigger an error. The error statement moves the control flow from the RECV event to the ERROR event, and creates a synthetic object that we can manipulate. To allow us to distinguish this special kind of error from any other that might end up triggering the ERROR event, we pass a unique HTTP status code and response status text. HTTP status codes below 600 are reserved by the specification, so we recommend using something in the 8XX or 9XX range. All solution patterns in opur library use 818 and distinguish themselves with a unique status text (in this case, 'redirect')

  3. Generate the redirection response

    The request moves to the ERROR event, where we can now capture it and modify the synthetic object:

    ERROR
    if (obj.status == 818 && obj.response == "redirect") {
      set obj.status = 308;
      set obj.http.Location = "https://" + req.http.host + table.lookup(solution_redirects, req.url.path) + if (req.url.qs, "?" req.url.qs, "");
      return (deliver);
    }

    We convert the synthetic object from an 818 to a 308 response code, and construct an appropriate Location header for the redirect. Let's break down what we include in this:

    • "https://" hard codes the protocol - why not use the opportunity to normalise the request to HTTPS? But if you do want to match the inbound protocol, check out req.proto.
    • req.http.host matches the inbound host. Fastly services can have many domains associated with them, so you probably want to redirect within the same domain. If you want to normalise, feel free to hard code here.
    • table.lookup retrieves the destination path. Since no scope is maintained between the RECV and ERROR events (in fact we may execute them on different physical machines) we need to perform the lookup again. Don't worry, it's very fast.
    • req.url.qs appends the querystring from the inbound request. You may want to consider leaving this out if you don't want to preserve query strings through the redirect.
  4. Setup a test request

    Before we test this by running the fiddle, you will want to set the request path for the test request to something that is in your dictionary of redirects:

    /source1

    Now run the fiddle. You should get a 301 response.

Next steps

This solution can only match entire paths (with or without querystring). If you want to match URL patterns using regular expressions, you will need to write your redirect conditions as a series of if statements. You could also achieve a middle ground by using a table (as in the solution described on this page) but treat each of the source paths as a prefix rather than a full URL (check out the std.strstr function for that).

This solution contains a VCL table. If you prefer, you can define the table using an Edge dictionary, which enables you to manage the table via HTTP API calls, without having to clone and activate new versions of your service.

See also

Reference docs:

Blog posts:

Quick install

This solution can be added directly to an existing service in a Fastly account as a set of VCL snippets. The embedded fiddle below shows the complete solution. Feel free to run it, and click the 'INSTALL' tab to customise and upload it to your service:

Click to view the fiddle code

Once you have the code in your service, you can further customise it to your needs, but if you keep it unmodified, it will be eligible for automatic upgrades if this recommended solution is improved in future.

All code provided through Build on Fastly is provided under both the BSD and MIT open source licenses.

Get in touch

Help us make this resource more useful for the entire Fastly community. Email your questions, requests, and big ideas to developers@fastly.com — or reach out and let us know what you’re working on.