Server Setup

NGINX locations: performance impact and optimizations

by , , revisited on


We have by far the largest RPM repository with dynamic stable NGINX modules and VMODs for Varnish 4.1 and 6.0 LTS. If you want to install NGINX, Varnish, and lots of useful modules for them, this is your one-stop repository to get all performance-related software.
You have to maintain an active subscription in order to be able to use the repository!

The location directive in NGINX can be considered as a core one as it’s the most crucial to have a functional web server.

Without further ado, let’s review on best performance practices in regards to it.

Best practice #1. Speed up regular expressions in location

Using regular expression in location directive means evaluating/compiling them at runtime, by default.
However, you can greatly improve the performance of matching to those locations, by precompiling those regular expressions on NGINX startup.

The magic directive here is pcre_jit on;. Place it in the main context (e.g. atop your nginx.conf file).

From the official documentation:

PCRE JIT can speed up the processing of regular expressions significantly.

Best practice #2. Use exact matching, where applicable

&tldr – replace regular expression matching with exact matching, where possible

Even though you can greatly improve the performance of locations defined by regular expression, they still result in some performance penalty.

Especially so, if there are many of them because NGINX has to evaluate each of them, sequentially.

location ~ ^/foo/bar/?$ {rewrite ^(.*)$ /foo permanent;}
location ~ ^/lorem/ipsum/?$ {rewrite ^(.*)$ /lorem permanent;}

Having a few rules like this is not a big problem. But if you’re rewriting URL structure for many URLs (think thousands),
the best approach would be using exact matching:

location = /foo/bar/ { return 301 /foo; }
location = /foo/bar { return 301 /foo; }
location = /lorem/ipsum/ { return 301 /lorem; }
location = /lorem/ipsum { return 301 /lorem; }

Best practice #3. Isolate regular expressions in a nested location

&tldr; Use nested locations instead of rewrite

The creator of NGINX, Igor Sysoev, at a conference in 2014, had to mention that NGINX evolved over time with nested locations.
The rewrite directive was a predecessor to nested locations, and thus should be avoided.

I haven’t said anything about rewrite‘s because you shouldn’t be using them at all

Using nested locations allows us to isolate the regular expressions.

Isolating regular expression location under prefixed locations helps to avoid regex matching for each request!

Let’s take the following example:

server {
    rewrite ^/img/(.+)$ /index.php?img=$1 last;

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

    location ~ \.php$ {
        fastcgi_pass ...
        include fastcgi_params;
    }
}

Why it’s bad? For any request, the regular expression ^/img/(.+)$ is evaluated. Surely it is fast in our example.
But in case you have anything slightly more complex than that, you absolutely want to avoid evaluating it for any request.

How to make the same rewrite, using nested location:

server {
    location /img/ {
        location ~ ^/img/(?<img>.+)$ {
            fastcgi_pass ...
            fastcgi_param SCRIPT_FILENAME /path/to/index.php;
            fastcgi_param QUERY_STRING img=$img
            include fastcgi_params;
        }
    } 

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

    location ~ \.php$ {
        fastcgi_pass ...
        include fastcgi_params;
    }
}

How is one better than the other? For a request to /foo, NGINX will not do any regular expression evaluation.
It will only do prefix matching, choose the location /, and ultimate land in location ~ \.php via try_files.

As you see from the above, using nested locations often means having to duplicate some NGINX configuration directives.

Fear not. The author of NGINX recommends the principle of copy-pasting/duplication in NGINX configuration.
According to Igor, this actually saves time in the long run, when you have to untangle one mighty regex location or rewrite into smaller pieces, in order to apply a more specific configuration to a set of URIs.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.