Nginx rewrite rule to convert URL segments to query string parameters

nginxrewrite

I'm setting up an nginx server for the first time, and having some trouble getting the rewrite rules right for nginx.

The Apache rules we used were:

See if it's a real file or directory, if so, serve it, then send all requests for / to Director.php

DirectoryIndex Director.php

If the URL has one segment, pass it as rt

 RewriteRule ^/([a-zA-Z0-9\-\_]+)/$ /Director.php?rt=$1 [L,QSA]

If the URL has two segments, pass it as rt and action

RewriteRule ^/([a-zA-Z0-9\-\_]+)/([a-zA-Z0-9\-\_]+)/$ /Director.php?rt=$1&action=$2 [L,QSA]

My nginx config file looks like:

server {
...

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

location ~ \.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;
   }
}

How do I get the URL segments into Query String Parameters like in the Apache rules above?

UPDATE 1

Trying Pothi's approach:

# serve static files directly
location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|html)$ {
   access_log off;
   expires 30d;
}


location / {
   try_files $uri $uri/ /Director.php;
   rewrite "^/([a-zA-Z0-9\-\_]+)/$" "/Director.php?rt=$1" last;
   rewrite "^/([a-zA-Z0-9\-\_]+)/([a-zA-Z0-9\-\_]+)/$" "/Director.php?rt=$1&action=$2" last;
}


location ~ \.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;
}

This produces the output No input file specified. on every request. I'm not clear on if the .php location gets triggered (and subsequently passed to php) when a rewrite in any block indicates a .php file or not.

UPDATE 2

I'm still confused on how to setup these location blocks and pass the parameters.

location /([a-zA-Z0-9\-\_]+)/ {
   fastcgi_pass unix:/var/run/php5-fpm.sock;
   fastcgi_index  index.php;
   fastcgi_param  SCRIPT_FILENAME  ${document_root}Director.php?rt=$1{$args};
   include        fastcgi_params;
}

UPDATE 3

It looks like the root directive was missing, which caused the No input file specified. message. Now that this is fixed, I get the index file as if the URL were / on every request regardless of the number of URL segments.

It appears that my location regular expression is being ignored.

My current config is:

# This location is ignored:
location /([a-zA-Z0-9\-\_]+)/ {
   fastcgi_pass unix:/var/run/php5-fpm.sock;
   fastcgi_index  Director.php;
   set $args $query_string&rt=$1;
   fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
   include        fastcgi_params;
}

location / {
   try_files $uri $uri/ /Director.php;
}

location ~ \.php$ {
   fastcgi_pass unix:/var/run/php5-fpm.sock;
   fastcgi_index  Director.php;
   fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
   include        fastcgi_params;
}

Best Answer

Disclaimer: None of the following are tested. Please use it with caution. If anything goes wrong, please turn on debugging as mentioned at http://nginx.org/en/docs/debugging_log.html .

See if it's a real file or directory, if so, serve it,
then send all requests for / to Director.php

This may be achieved with...

server {
  index Directory.php;
  location / {
    try_files $uri $uri/ /Directory.php;
  }
}

The index directive is enough for directory index. To send all requests to Director.php, then location block is needed.

If the URL has one segment, pass it as rt

You may try the following...

rewrite "^/([a-zA-Z0-9\-\_]+)/$" "/Director.php?rt=$1" last;

Please remember the quotes around the rewrites. It is preferable to use quotes, and is needed on certain conditions (that is mentioned in the link provided earlier by @jerm).

If the URL has two segments, pass it as rt and action

You may try the following...

rewrite "^/([a-zA-Z0-9\-\_]+)/([a-zA-Z0-9\-\_]+)/$" "/Director.php?rt=$1&action=$2" last;

Please note that I haven't done anything for QSA in the above examples. You may try $args variable in Nginx to pass the existing query string to the new query string. Ref: http://nginx.org/en/docs/http/ngx_http_core_module.html#variables

I hope that helps to arrive at the full working solution!