1

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;
}
Nick
  • 4,433
  • 29
  • 67
  • 95

2 Answers2

1

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!

Pothi Kalimuthu
  • 5,734
  • 2
  • 24
  • 37
  • Thanks for the sample code. I tried using it as a model (please see Update #1 above), but I get `No input file specified` on every request. – Nick Sep 30 '13 at 12:42
0

This is a good primer on capturing regexes as variables in nginx locations

http://nginx.org/en/docs/http/server_names.html#regex_names

jerm
  • 637
  • 3
  • 5
  • I get the basics of it, but do I need a location block for one segment and another location block for 2 segments? And do I need `fastcgi_pass` in each of those blocks? – Nick Sep 29 '13 at 18:44
  • yes and yes.... You might be tempted to use an "if" statement to do this in once location block, but be sure to read why if is evil: http://wiki.nginx.org/IfIsEvil – jerm Sep 29 '13 at 19:30
  • Please see my update #2 above- I'm still not sure how to pass the captured value of the regex as a Query String parameter. And also how to append any existing Query string, like Apache's `QSA` option. – Nick Sep 30 '13 at 12:41