rewrite don't work in a multilanguage MVC site

Francis Daly francis at
Tue Oct 25 20:22:52 UTC 2011

On Tue, Oct 25, 2011 at 06:56:05PM +0200, Fernando García Torres wrote:

Hi there,

>     RewriteEngine On
>     RewriteCond %{HTTP:Accept-Language} ^en [NC]    RewriteRule ^$ /en/ [L,R=301]
>     RewriteCond %{HTTP:Accept-Language} ^es [NC]    RewriteRule ^$ /es/ [L,R=301]
>     RewriteCond %{REQUEST_FILENAME} !-f    RewriteCond %{REQUEST_FILENAME} !-d    RewriteRule (.*) index.php?ctr=$1 [QSA,L]

If I read this right, it only redirects the request for "/" to "/en/" or
"/es/" if the Accept-Language header begins with one of those strings;
otherwise, if the file-or-directory exists, serve it; otherwise, redirect
to index.php?ctr=(the original request).

Note that nginx and apache differ in the leading / of the url, so you'll
want to make sure that you allow for that. I'm going to assume that you
want to redirect to /index.php for all otherwise-404s.

Also note that you'll want to check whether apache writes
index.php?ctr=request or index.php?ctr=/request. The check what you
configure nginx to write, and see if it works too.

And as a final note -- checking the first two characters of
Accept-Language is not the right way to process that header. But it's
your site, and you get to do what you want on it.

> And this my translation to nginx:
>     location / {            if (-f $request_filename) {                      expires 30d;                      break;              }
>             if ($http_accept_language ~* "^es") {                    rewrite ^/$ /es/ permanent;                    break;            }
>             if ($http_accept_language ~* "^en") {                    rewrite ^/$ /en/ permanent;                    break;            }
>             if (!-e $request_filename) {                      rewrite (.*) /index.php?ctr=$1 last;              }      }

I suggest writing this as two locations:

        location = / {
          if ($http_accept_language ~* "^en") {
             return 301 /en/;
          if ($http_accept_language ~* "^es") {
             return 301 /es/;

        location / {
          try_files $uri $uri/ /index.php?ctr=$uri;

> location ~ \.php$ {            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;            ...

I would be more explicit, unless you have more php scripts:

        location = /index.php {
          fastcgi_pass unix:php.sock;


        include fastcgi.conf;

at server level. But however you want to handle php is probably fine.

> With this, when I type I'm being redirected to, great, but I get a 404 error, and in the error.log I have this line:
>     "/bla/bla/html/en/index.php" is not found 

I get a 403 Forbidden, not a 404, so I must have some other configuration
difference from you.

> So, why is not nginx looking for the URI /index.php?ctr=/en/? 		 	   		  
Per the config, if the directory exists, it is served.

In my tests /en/ exists and returns 403, /ex/ doesn't and returns the
same content as /index.php?ctr=/ex/ does, apart from REQUEST_URI being

Good luck with it,

Francis Daly        francis at

More information about the nginx mailing list