Tech Blog

NginX Add Trailing Slash With 301 Redirect Without If Statements

We had a situation where a client using Joomla wanted to have trailing slashes added to URLs, not just processed behind the scenes as the ‘correct’...

Published
July 28, 2015
Author
Adam Strohl
Reading time
1 minute

NginX Add Trailing Slash With 301 Redirect Without If Statements

We had a situation where a client using Joomla wanted to have trailing slashes added to URLs, not just processed behind the scenes as the ‘correct’ URL but 301ed to the resulting URL with the trailing slash.

This makes sense from a SEO standpoint as you don’t want two URLs with the same content. Joomla was expecting trailing slashes as well and wasn’t properly processing URLs without them.

We also wanted to avoid “If” statements inside our NginX configurations as they are processed in a difficult to predict manner, are inefficient and are generally considered to be evil.

As some background with Joomla we use a configuration like this so that files that exist are served, but anything else is re-mapped (with no redirect) to Joomla’s index.php. This is commonly referred to as “SEO friendly URLs”:

location / {
           try_files                 $uri $uri/ /index.php$is_args$args;
        }

Adding the 301 redirects with trailing slashes is actually quite simple: We catch candidate URLs in their own location block, see if the file really exists, and if not jump to a custom @location destination which does the 301:

location ~ ^([^.\?]*[^/])$ {
           try_files                 $uri @addslash;
        }
        
        location @addslash {
           return                    301 $uri/;
        }
        
        location / {
           try_files                 $uri $uri/ /index.php$is_args$args;
        }

To recap: We define a “location ~ ^([^.\?]*[^/])$” at the top that matches all URLs that don’t have a period in them and that don’t end in a slash (so http://www.site.com/file.php will not match – even if it doesn’t exist). This first location block’s “try_files” statement checks to see if the URL maps to a file that exists, and if not @addslashes is triggered.

Then we define the @addslashes location to return a 301 using the URI with a slash at the end as the new destination.

Lastly we keep the original “location /” block to preserve the re-mapping functionality for any URLs not like this (or, for example, have already been redirected previously).

Need help with Linux or FreeBSD infrastructure?

A-Team Systems provides engineer-led support for production Linux and FreeBSD environments, including troubleshooting, operational oversight, and ongoing infrastructure management.

Contact A-Team Systems