Ssey Ssey - 2 months ago 20
Apache Configuration Question

Configure nginx language subdirectories

I'm moving a site from apache to nginx and stuck with the following configuration.

I have site http://example.com/ which shows the main (English) version.
Also, I have a few more languages which could be opened using correspondent subdirectories.
http://example.com/de http://example.com/fr, http://example.com/es or http://example.com/es/ (with a trailing slash).

These subdirectories are virtual (non-existing), but should open the same pages from the root directory. A php script handles the language representation.

Now English site works fine, however, other languages don't work.
I can open http://example.com/es/ (only with a trailing char) and it opens the main page, however, all other pages could not be accessed (e.g. http://example.com/es/test.html which is a seo friend url). I already reviewed lots of similar questions and answers on SO but non of them are helpful.
Here is my configuration:

server {
....
root /var/www;
index index.php index.html index.htm;

location / {
rewrite ^/(de|fr|it|es)\/(.*)$ /$2;
try_files $uri $uri/ @fallback;
}

location @fallback {
rewrite ^(.*)$ /seo.php?$args last;
}

location ~* \.(jpeg|ico|jpg|gif|png|css|js|pdf|txt|tar|gz|wof|csv|zip|xml|yml) {
access_log off;
try_files $uri @static;
expires 14d;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control public;
root /var/www;
}

location @static {
rewrite ^/(\w+)/(.*)$ /$2 break;
access_log off;
rewrite_log off;
expires 14d;
add_header Cache-Control public;
add_header Access-Control-Allow-Origin *;
root /var/www;
}

location /backend/ {

rewrite ^(.*)$ /backend/index.php last;
}

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}


It previously worked on apache as follows:

RewriteRule ^(de|fr|it|es)\/(.*)$ $2
RewriteCond %{REQUEST_URI} !^/(backend|template)/
RewriteCond %{REQUEST_FILENAME} !\.(gif|jpeg|png|js|css|swf|php|ico)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ seo.php [L]


Please advise. Thanks.

Answer

Obviously Apache is transforming /es to /es/ before applying the rewrite. nginx will not do that unless the directory actually exists.

However, it is easily remedied by tweaking the regular expression, and making the trailing slash optional.

Try this:

rewrite ^/(?:de|fr|it|es)(?:/(.*))?$ /$1;

The (:? ) construct is a non capturing group.

EDIT:

If you want the trailing slash to be added "visibly", then you will need a redirect. For example:

rewrite ^/(de|fr|it|es)$ /$1/ permanent;
rewrite ^/(?:de|fr|it|es)/(.*)$ /$1 last;