Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx redirect all requests from subdirectory to another subdirectory root

I'm quite new to Nginx so please bear with me.

I'm trying to redirect all requests from one subdirectory (store) to the root of another subdirectory (trade). See my progress below. The site in the target subdirectory (trade) is a magento site so that is what most of the current rules are for.

server {
    server_name example.com *.example.com;
    root /usr/share/nginx/html/example.com/public_html;
    index index.php index.html index.htm;

    access_log /var/log/nginx/example.access.log;
    error_log /var/log/nginx/example.error.log;

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

    location /trade/ {
            index index.html index.php;
            try_files $uri $uri/ @handler;
            expires 30d;
    }

    location ~ /store {
            rewrite /trade permanent;
    }

    location ~ ^/trade/(app|includes|lib|media/downloadable|pkginfo|report/config.xml|var)/ { internal; }
    location /trade/var/export/ { internal; }
    location /. { return 404; }
    location @handler { rewrite / /trade/index.php; }

    error_page 404 /404.html;

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
          root /usr/share/nginx/html;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
            try_files $uri =404;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;

    }


}

The section I am using to redirect is the following:

location ~ /store {
        rewrite /trade permanent;
}

This works for example.com/store but not example/store/index.php or any other uri with args. I have a feeling that the php file section at the bottom is overriding the processing. That is why I have put the ~ in front of the store location as the documentation here states this will be processed first. Does the processing stop or continue on?

I have read about nesting a php rule but I have tried this to no avail.

I would greatly appreciate any help.

like image 768
user1214769 Avatar asked Mar 06 '14 12:03

user1214769


3 Answers

ok try something like this

location ^~ /store(.*) {
  return 301 $scheme://$http_host/trade$1$is_args$query_string;
}

Trying to avoid hardcoded stuff as much as possible and using return because it's prefered over permanent rewrites

like image 152
Mohammad AbuShady Avatar answered Nov 15 '22 13:11

Mohammad AbuShady


Ok,

Coming back to this I can see the issue.

In Nginx when you prepend a location directive with ~ this means that you want to process regular expressions in your directive (case sensitive, ~* for case insensitive). I believe that all regex directives will process before any others but I stand to be corrected.

So when I am using:

location ~/store {
       rewrite /trade permanent;
}

There is no regex there. Its is simply matching /store and redirecting to trade.

After some investigation (and polishing up on my regex, which is rubbish), I came back to it and have come up with a working solution.

location ~ ^/store/(.*) {
            rewrite ^/store(.*) /trade permanent;
    }

Here I am asking the directive to process the regex by entering ~ then match any url with /store/ in it.

Then, according to the docs, the rewrite syntax is:

rewrite regex replacement [ flag ]

so I am matching all urls with store in it and permanently redirecting them to the new subfolder.

Pretty easy really, embarrassingly so actually but hey, every day is a school day. I'm open to correction on all of this and hope it helps someone.

like image 30
user1214769 Avatar answered Nov 15 '22 14:11

user1214769


You need to ensure that your location ~ \.php$ handler does not take any URLs below the old folder. Indeed, precedence rules are clearly documented within http://nginx.org/r/location, and you can either use regular expressions, or, better yet, use prefix-based matching with the ^~ modifier to instruct that the search must stop without trying to see if that regex-based \.php$ location would match:

    location ^~ /old/long/path/ { # will match /old/long/path/index.php, too
        rewrite  ^/old/long/path/(.*)$  /new/$1  permanent;
    }

The above snippet is likely the most efficient way of doing this, but here is another way of doing the same:

    location ~ /old/long/path/(.*) {
        return  301  /new/$1$is_args$args;
    }

Why does one example has $is_args$args and the other one doesn't? Good question! Note that location directive as well as the first parameter of the rewrite directive both operate based on the contents of the $uri variable, as opposed to $request_uri. Long story short, but $uri does not contain $args, so, in both cases, $1 will not contain any args; however, in the case of rewrite, the case is deemed so common that $args are automatically added back by nginx, unless the new string ends with a ? character, see http://nginx.org/r/rewrite.

like image 1
cnst Avatar answered Nov 15 '22 13:11

cnst