Nginx rewrite rules, fastcgi and WordPress – 404 pages due to REQUEST_URI

fastcginginxPHPWordpress

I'm trying to convert a set of rewrite rules which were created for Apache for hosting a WordPress site to use with NginX (fastcgi, PHP).

From what I understand, WordPress has a page ("expo") which then uses code in a theme to check for a request parameter ("p"). It then uses "p" to do some database queries and render content.

So you can access this page by calling /expo?p=name_of_expo.

The requirement is that the URL be structured thus: /expo/name_of_expo

I've stripped it down to the most basic rewrite rule I can:

location ~ ^/expo/.+/?$ {
    rewrite ^/(.+)/(.+)/?$ /$1/?p=$2? last;
    try_files $uri $uri/ /index.php?$args;
}

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

location ~ \.php$ {
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
}

When going to /expo?p=name_of_expo, the correct page is displayed. However, when going to /expo/name_of_expo, the WordPress 404 is triggered.

The rewrite log from nginx suggests that the correct URL is being written:

2012/03/08 16:56:16 [notice] 15995#0: *7698 "^/(.+)/(.+)/?$" matches "/expo/name_of_expo", client: 192.168.60.116 [snip...]

2012/03/08 16:56:16 [notice] 15995#0: *7698 rewritten data: "/expo/", args: "p=name_of_expo", client: 192.168.60.116 [snip...]

Obligatory software version information:

nginx version: nginx/1.0.13

spawn-fcgi v1.6.3 (ipv6) - spawns FastCGI processes
Build-Date: May 25 2010 12:33:48

PHP 5.2.10 (cli) (built: Nov 13 2009 11:44:05)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies

CentOS release 5.7 (Final)

Best Answer

Try this

server {
  error_page   405   = @handler;
  error_page   404   = @handler;

  location / {
    if (-f $request_filename) {
      break;
    }

    if (!-e $request_filename) {
      rewrite . /index.php last;
    }
  }

  location @handler { 
    rewrite / /index.php;
  }

  location ~ \.php/ {
    rewrite ^(.*.php)/ $1 last;
  }

  location ~ \.php$ {
    if (!-e $request_filename) { rewrite / /index.php last; }

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
  }

}

And in your fastcgi_params

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;