I'm using Nginx 1.6.2. I read that if () is evil and it's not good using it so I need a bit help, because I can't do what I want without using if(). I will post the rules I have with if and would ask if somebody could help me and tell me how to not use if () and use something else and get the same result.
# REDIRECT NON-WWW TO WWW.
if ($http_host != "www.site.eu") {
rewrite ^ http://www.site.eu$request_uri permanent;
}
# REMOVE INDEX FILES FROM URL FOR SEO PURPOSE.
if ($request_uri ~ "/index.php") {
rewrite ^ /$1 permanent;
}
# REMOVE ANY MULTIPLE SLASHES IN THE URL.
if ($request_uri ~* "\/\/") {
rewrite ^/(.*) $scheme://$host/$1 permanent;
}
First rule should be replaced with separate server blocks
server {
listen 80 default_server;
return 301 http://www.example.com$request_uri;
}
server {
listen 80;
server_name www.example.com;
# normal config
}
Other ifs usually are not necessary. Just don't generate links with index.php and you will not need to strip it.
In the official wiki introduction it says that there are some cases which are ok. Have a look at this quote:
The only 100% safe things which may be done inside if in location
context are:
return ...; rewrite ... last;
At the end of the introduction there is an example which also features a rewrite command. So your code looks ok, too.
EDIT: You should also have a look at how the if works.
You can replace this block
# REMOVE INDEX FILES FROM URL FOR SEO PURPOSE.
if ($request_uri ~ "/index.php") {
rewrite ^ /$1 permanent;
}
with this
location ~ ^/index.php/(.*[^/])$ { return 301 $scheme://$host/$1/$is_args$args; }
location ~ ^/index.php/(.*)/$ { return 301 $scheme://$host/$1/$is_args$args; }
I also don't think you need to worry about the last rule for double // because nginx by default automatically takes care of that before it even gets to the point of matching location blocks
Related
I'm trying to create an nginx rewrite that will rewrite /pagename to /pagename/
I've tried using:
location ~ "^/test$" {
rewrite /test /test/ break;
}
but that doesn't seem to work...
any help would be appreciated.
The first parameter of a rewrite statement is a regular expression, and the flag you should use is probably permanent (see this document for details), for example:
location ~ "^/test$" {
rewrite ^(/test)$ $1/ permanent;
}
But you do not need to match the regular expression twice, once in the location and again in the rewrite, so a return would be more efficient, for example:
location ~ "^(/test)$" {
return 301 $1/$is_args$args;
}
Also, the location matches a single URI, to the = operator would be better than a regular expression (see this document for details). So the preferred solution is:
location = /test {
return 301 $uri/$is_args$args;
}
I ended up using return:
return 301 /test/;
I would like to rewrite legacy links using a query parameter type of URL to a new style of URL.
Ex.
example.com/page?id=1 -> example.com/page/1
example.com/otherpage?id=1 -> example.com/otherpage/1
Currently I have the following configuration using the evil if.
if ($args ~* "id=(.*)") {
set $w1 $1;
rewrite .* $scheme://$host/page/$w1? permanent;
}
Note: I am using CloudFront, and relying on the host header above.
If the above is in a server block, with no other location block - would this qualify as a non-evil use of if in NGINX config? Also, the above only supported /page/. Any better ideas for making that portion work for otherpage and other pages?
I have seen a few other ideas discussing using a map, but I'm not quite sure how to bring it all together? I was thinking something along the lines of:
map $args_id ?? {
default ?
??
}
...
server {
...
???
}
UPDATE:
Based on the Answer from #Ivan, this was my final solution:
server {
listen 80;
root /usr/share/nginx/html;
index index.html index.htm;
# Handle legacy requests
if ($args ~* "id=(.*)") {
set $w1 $1;
rewrite ^ $scheme://$host$uri/$w1? permanent;
}
}
Your if construction isn't evil. You can use something like
rewrite ^ $scheme://$host$uri/$w1? permanent;
for any page. More complex example if you want to process both example.com/page?id=1 and example.com/page/?id=1:
map $uri $maybe_slash {
~/$ "";
default "/";
}
...
server {
...
rewrite ^ $scheme://$host$uri$maybe_slash$w1? permanent;
...
}
I would like to have a lighter code for one of my NGINX configurations. I need to write the following four lines in only one (if possible!):
location /en/contact {
rewrite ^/.* https://$server_name/contact permanent;
}
location /en/quality {
rewrite ^/.* https://$server_name/quality permanent;
location /de/contact {
rewrite ^/.* https://$server_name/contact permanent;
}
location /de/quality {
rewrite ^/.* https://$server_name/quality permanent;
}
Thanks!
Using minimal typing, you could use a rewrite statement outside of any location block:
rewrite ^/(en|de)/(contact|quality) https://$server_name/$2 permanent;
If the scheme and server name does not change, the second parameter can be replaced with just /$2. See this document for more.
Alternatively, you could use a regular expression location block:
location ~ ^/(en|de)/(contact|quality) {
return 301 https://$server_name/$2;
}
Same as above, regarding the scheme and server name. Note that the evaluation order for regular expression location blocks is significant - the first rule that matches wins. See this document for more.
I'm on the process of migrating the same app but to a different domain.
For the old domain, I've the routes as:
http://app.example.com/app/users/sign_in?query=hello
I want it to be redirected to another domain omitting the app part as:
http://app.newexample.com/users/sign_in?query=hello
I tried with:
server {
...
location /app {
rewrite ^$scheme://app.sparkon.com/app(/.*)$ $1 last;
}
...
}
I doesn't work. How to achieve this?
I had this issue about a year ago and spent a long time looking for solutions. I found and use this:
server {
listen 80;
server_name example.com app.example.com;
rewrite ^/app(.*)$ http://app.newexample.com$1 permanent;
}
server {
listen 80;
server_name app.newexample.com;
# config for primary domain here
}
From this link. Credit to them.
Don't put scheme in the rewrite pattern:
server {
server_name app.example.com;
location /app/ {
rewrite ^/app/(.*)$ http://app.newexample.com/$1;
}
}
Brg.
I prefer this method as it doesn't need to use rewrite, one of the things that i read are good to avoid too much, cause it needs more processing by the nginx engine.
location ~ /app/(.*) {
return 301 $scheme://app.sparkon.com/$1;
}
I currently have the following (hacky) re-write rule in my nginx.conf to allow dynamic sub-domains to be re-directed to one Django instance.
set $subdomain "";
set $subdomain_root "";
set $doit "";
if ($host ~* "^(.+)\.domain\.com$") {
set $subdomain $1;
set $subdomain_root "/profile/$subdomain";
set $doit TR;
}
if (!-f $request_filename) {
set $doit "${doit}UE";
}
if ($doit = TRUE) {
rewrite ^(.*)$ $subdomain_root$1;
break;
}
I'm sure there is a more efficient way to do this but I need to change this rule so that any requests to *.domain.com/media/* or *.domain.com/downloads/* go to domain.com/media/* and domain.com/downloads/*.
You can use regular expression server names (see http://nginx.org/en/docs/http/server_names.html#regex_names) and assign a matching group to a variable $subdomain directly:
server {
listen 80;
listen 443;
server_name ~^(?<subdomain>.+)\.domain\.com$
location / {
rewrite ^ /profile/$subdomain$request_uri;
}
}
Actually I think it is much easier to change the nginx re-write rules than to write middleware for django to do this. After reading up on how nginx processes it's location matching (most exact -> least exact) I created locations for /media and /download as well as a catch all location for / I then moved the rewrite rule to under the / location and simplified it - as I'm no longer worried about checking for files because this entire location is passed to django - the rule becomes :
set $subdomain "";
set $subdomain_root "";
if ($host ~* "^(.+)\.domain\.com$") {
set $subdomain $1;
set $subdomain_root "/profile/$subdomain";
rewrite ^(.*)$ $subdomain_root$1;
break;
}
and would probably be even simpler if my nginx\regex scripting was better :)
Perhaps a better idea would be to configure django to handle subdomains instead of adding a rewrite in your webserver. Here's how I did it: http://sharjeel.2scomplement.com/2008/07/24/django-subdomains/