A good[ish] website
Web development blog, loads of UI and JavaScript topics
The Nginx location directive sets configuration depending on a request URI, on which, for example, redirects can be performed.
Here's a really simple, but working, Nginx server configuration with one location block, that block performs a redirect to a different domain:
server {
server_name staging.clubmate.fi;
root /var/www/staging.clubmate.fi/public_html;
location /foo {
return 301 http://clubmate.fi;
}
}
The location syntax is as follows:
location [ = | ~ | ~* | ^~ ] uri { ... }
You can use a modifier or not, here's what each of the modifiers do:
=
~
~*
^~
Modifier act kind of like flags in JavaScript regex.
Below is a more detailed look into each one of these.
Just a string without any modifiers:
location / {
# Will match anything that starts with forward slash, that's literally every
# single page
}
location /foo {
# Will match /foo and /foooooo and /fooxxxx and so on... The matching starts
# from the beginning of the string, So it doesn't match /bar/foo.
}
The match is case sensitive, the above example won't match /FOO
.
Use the equal sign =
to tell Nginx that this is a literal match:
location = / {
# Will match forward slash "/" and nothing more
}
location = /foo {
# Will match /foo and nothing more
}
This is where it gets interesting.
ℹ️ Nginx uses the PCRE engine to parse the Regular Expressions and the following characters needs to be escaped:
.^$*+?()[{\|
. And inside in character classes:^-]\
.
Tilde ~
enables Regex on the following string. So whenever you want to use Regular Expressions to match the path, use the tilde or the case insensitive tilde followed by asterisk ~*
:
Here's some basic example of redirecting to a new path structure:
location ~ ^/tag/(.+) {
return 301 /tags/$1;
}
Here's what's happening in it:
~
^
/tag/
(.+)
$1
But see, it doesn't keep the query parameter around:
$ curl -I -s 'http://staging.clubmate.fi/tag/foo?baz=quix' | grep Location:
Location: http://staging.clubmate.fi/tags/foo
This might be bad for many reasons (if you're doing tracking or "campaigns" or if it's just a part of your URL structure). But it can be added using the built-in $query_string
variable:
location ~ ^/tag/(.+) {
if ($query_string) {
return 301 /tags/$1?$query_string;
}
return 301 /tags/$1;
}
Nginx has a ton of built-in variables that can be used.
Very common thing to do is to set far expiring headers for static file types, so they'll stay cached longer in your browser:
# Set expires to year on static file types
location ~* ^.+\.(css|js|jpg|jpeg|gif|webp|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|mp4)$ {
expires 365d;
access_log off;
}
ℹ️ The literal mention of the dot needs to be escaped.
Favicons often make logs unnecessarily loud and usually they don't serve much purpose. In this topsy-turvy proprietary technology world that we live in, where every provider wants to have their own favicon format, the matching isn't so straightforward. But there's almost nothing a good old regex pattern can't do:
location ~ (?:apple-touch-.*|favicon.*)\.(?:png|ico) {
log_not_found off;
access_log off;
}
You get the idea what location
can do for you.
I should add that, never test redirects in a browser, because the browser "lies", they cache redirects heavily so you can never be sure what's going on. Better use curl
for that:
$ curl -I 'http://staging.clubmate.fi'
Using the above mentioned server block, that will give you the following output:
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sun, 28 Oct 2018 05:26:05 GMT
Content-Type: text/html
Content-Length: 178
Location: http://clubmate.fi
Connection: keep-alive
You can grep
that to make it more readable if you want:
$ curl -I -s 'http://staging.clubmate.fi' | grep Location:
Location: http://clubmate.fi
The -I
option tells curl to fetch only the headers. The lower case -s
is for silent, otherwise it shows the progress of the request.
Nginx also has the rewrite directive but that's for a another unforeseeable post.
Please do drop a comment below if you have something to add.
Comments would go here, but the commenting system isn’t ready yet, sorry.