yum
upgrades for production use, this is the repository for you.
Active subscription is required.
Adopting NGINX as your web server may be a more challenging task if you come to it after Apache.
One of the primary reasons for that is how different things are in the two webservers. URL redirects are done quite differently in Apache and NGINX.
However, it is quite easy to comprehend how redirects are to be done in NGINX when you know some basics:
- The
rewrite
orlocation
directives in NGINX are matched against the URI without arguments. That is, for a URLhttps://example.com/foo?bar=1`, these directives operate on
/foo` and don’t “see” the query part - The
$request_uri
is the NGINX variable that holds the complete URI, e.g./foo?bar=1
In NGINX, you may end up writing redirects with these directives: rewrite
, location
, return
, if
, and map
. Sounds like too many?
Fear not. There are just a handful of cases to review. Which directives you will use depends on what kind of URLs you are redirecting (whether they use query params), and their number.
Redirecting a single URL irrespective of original arguments
In the simplest case, you want to add a simple redirect from one URL to another, and you don’t bother about the query parameters from the original URL.
The most efficient approach to this would be using the exact matching of the location
directive.
To redirect /foo
to /bar
permanently, you would use:
location = /foo {
return 301 /bar;
}
What we’ve done there is created an exact location
that matches requests for /foo
.
A location NGINX is best to be understood as a request’s context.
Exact matching (note equals sign) means that NGINX will match requests to /foo
only, and not /foomore
.
Throughout request processing, NGINX may “jump” from one context to another, but only a single specific context will be eventually chosen for making up a response.
If a context ends up with a return
statement, no more context switching will take place and NGINX will ultimately serve a redirect when either 301
(permanent) or 302
(temporary) status codes are used as the first argument to return
.
With our configuration, requests to /foo
will be redirected to /bar
with the permanent redirect status 301.
Remember, any kind of location matching in NGINX is done against the URI without/irrespective of its arguments.
So the same location will match the URI /foo?bar=1&...
or /foo?bar=2&...
, etc…
A visitor will be redirected to /bar
.
To preserve original URL arguments in the new URL, you will use the $args
variable in the new URL:
location = /foo {
return 301 /bar$is_args$args;
}
Now /foo?bar=1
will be redirected to /bar?bar=1
, etc.
When to use exact matching for redirects:
- You want to redirect a single or a few URLs
- You want to redirect URLs for any value of request arguments in the original URL
Redirecting many URLs irrespective of their arguments
If you have dozens and dozens of redirects of the previous type, you may want to leverage the map
directive.
It comes in handy when you deal with array-like structures in NGINX.
The map
directive actually defines a new NGINX variable based on the values of other variables.
For the task of redirecting many URLs, we can simply define a $redirect_to
variable based on $uri
, and perform a redirect when it isn’t empty.
Remember, the map
directive should go directly within http {}
context, and not within server {}
.
http {
map $uri $redirect_to {
default "";
/foo /bar;
/lorem /ipsum;
/one /two;
}
# ...
}
Now that we have defined our variable, it can be used in the server
block:
server {
server_name example.com
if ($redirect_to != "") {
return 301 $redirect_to;
}
}
Now, visitors to /foo
are redirected to /bar
.
Requests to /lorem
are redirected to /ipsum
.
Requests to /one
are redirected to /two
.
It’s easy to add many redirects by adding them as new entries under the $redirect_to
map.
Using rewrite
The rewrite
also helps you in batch redirecting many URLs to many URLs.
If you have clear conformity between the old and new URL sets, you will want to use rewrite
for redirects.
Suppose that you had URLs of type /<some.php>
using a bunch of PHP files.
Now you have switched to a front-controller CMS framework, where the index.php
bootstrap file handles SEO URLs.
For /some.php
, you want to redirect to /index.php?page=some
. The rewrite
comes in very handy because it supports regular expressions:
location /
rewrite ^(.*) /index.php?page=$1 permanent;
}
location = /index.php {
fastcgi_pass ...
}
Note how we have to add prefixed location /
and exact located /index.php in order to exclude /index.php itself from the redirect.
When NGINX sees a request for URI /index.php, it will immediately switch to location = /index.php
.
The result is:
/foo.php
redirected to/index.php?page=foo
/bar.php
redirected to/index.php?page=bar
- etc. etc.
The rewrite
directive requires specifying permanent
(permanent redirect) or redirect
(temporary redirect) for specifying the type of the desired redirect.
Redirecting a single URL, accounting for its arguments
When you must match the original URL with its arguments, it is easiest to use if
and evaluate the value of $request_uri
inside it:
if ($request_uri = "/foo?bar=1") {
return 301 /bar;
}
Redirecting many URLs, accounting for their arguments
Say you had a URL structure that heavily relied on URL parameters, and decided to switch to SEO-friendly URLs. If there is no clear way to define which old URLs correspond to the new URLs, you can use the map
approach again.
The only difference to the previous approach is that we are going to use $request_uri
variable which includes URL arguments:
http {
map $request_uri $redirect_to {
default "";
"/foo?arg1=val1" /bar;
/lorem /ipsum;
/one /two;
}
# ...
}
Now that we have defined our variable, it can be used in the server
block:
server {
server_name example.com
if ($redirect_to != "") {
return 301 $redirect_to;
}
}
Note that /foo
will not be redirected, because we now match against the complete URI.
Only visits to /foo?arg1=val1
are redirected to /bar
.
Requests to /lorem
are redirected to /ipsum
.
Requests to /one
are redirected to /two
.
If parameters are added to those URLs, they will not be redirected.
Permanent redirect from subdirectory to the root
Suppose that you had a multistore Magento and hosted your language-specific stores in subdirectories.
Eventually, you decided to have the single international version of your website at the root, and eliminate the subdirectories setup.
To preserve the SEO juice, create redirects from the subdirectory URLs to the root like this:
rewrite ^/(?:en-sa|ar-sa|en-qa|ar-qa|en-kw|ar-kw|ru-ru|en-ru)/(.*)$ /$1 redirect;
This redirects /en-sa/product.html
to /product.html
, etc.
Redirects in NGINX are powerful
Web redirects in NGINX are not complicated and can be done in a very efficient manner when you know which case you’re dealing with.
NGINX has the power to map one variable to another, it has regular expression support, different location-matching types, and many built-in variables.
All this requires some learning curve but the result is the rewarding, fast web server operation.
Atlas
Nice, wish if there were more details, like where do you add these lines, on the example.com.conf file? or Nginx conf file?
which one would it be for this example:
– all pages from
https://example.com/pages
– redirects to
https://example.com
like,
https://example.com/pages/chicken.html
tohttps://example.com/chicken.html
Thanx
Danila Vershinin
Website-specific configuration should be placed to configuration files residing at
/etc/nginx/sites-available/
, which in turn is symlinked to/etc/nginx/sites-enabled/
.E.g., for the domain
example.com
, you would have the/etc/nginx/sites-available/example.com.conf
file which is present as a symlink at/etc/nginx/sites-enabled/example.com.conf
.In
nginx.conf
, include enabled sites withinclude sites-enabled/*.conf;
. Each website specific configuration will likely have a set ofserver
blocks specific to the domain that matches the filename.This is a convention only. Nobody prevents you from putting the entire configuration to
nginx.conf
, but then it will be hard to manage.Whichever way you choose to manage your configuration across the files, redirects configuration must be placed within
server {}
blocks.If such redirects require
map
s, it is worth noting thatmap
directive can only go tohttp {}
section, outside ofserver
blocks.For a permanent redirect you can:
Additionally, you may want to optimize it by nesting within prefixed location:
ijamessaxon
Oh so close…. What about matching on the GET args?
You’ve got
/foo?arg1=val1
but what about/foo?arg1=(.*)
or something like that? Either in location or rewrite, is that doable? It seems to ignore it completely.Greg
You’ll need to append args just like below.
location ~ ^/pages/(.*)$ {
return 301 /$1$is_args$args;
}
<\code>