Nginx – Convert apache rewrite rules to nginx

apache-2.2nginxrewrite

I want to migrate an Apache setup to Nginx, but I can't get the rewrite rules working in Nginx. I had a look on the official nginx documentation, but still some trouble converting it. http://nginx.org/en/docs/http/converting_rewrite_rules.html

I've used http://winginx.com/en/htaccess to convert my rules, but this just works partly. The / part looks okay, the /library part as well, but the /public part doesn't work at all.

Apache part:



    ServerAdmin webmaster@localhost
    DocumentRoot /srv/www/Web
        
          Order allow,deny
          Allow from all
          RewriteEngine On
          RewriteRule  ^$    public/      [L]
          RewriteRule  (.*)  public/$1    [L]
        

        
          Order Deny,Allow
          Deny from all
        

        
          RewriteEngine On
          RewriteCond %{QUERY_STRING} ^pid=([0-9]*)$
          RewriteRule ^places(.*)$ index.php?url=places/view/%1 [PT,L]
          # Extract search query in /search?q={query}&l={location}
          RewriteCond %{QUERY_STRING} ^q=(.*)&l=(.*)$
          RewriteRule ^(.*)$ index.php?url=search/index/%1/%2 [PT,L]
          # Extract search query in /search?q={query}
          RewriteCond %{QUERY_STRING} ^q=(.*)$
          RewriteRule ^(.*)$ index.php?url=search/index/%1 [PT,L]
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteCond %{REQUEST_FILENAME} !-d
          # Rewrite all other URLs to index.php/URL
          RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
        

        
          Order deny,allow
          deny from all
        
    ErrorLog ${APACHE_LOG_DIR}/error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
        
          AddHandler php5-fcgi .php
          Action php5-fcgi /php5-fcgi
          Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
          FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php5-fpm.sock -pass-header Authorization
        
    CustomLog ${APACHE_LOG_DIR}/access.log combined

Nginx config:


server {
  #listen   80; ## listen for ipv4; this line is default and implied
  root /srv/www/Web;
  index index.html index.php;
  server_name localhost;
  location / {
    rewrite ^/$ /public/ break;
    rewrite ^(.*)$ /public/$1 break;
  }

  location /library {
    deny all;
  }

  location /public {
    if ($query_string ~ "^pid=([0-9]*)$"){
      rewrite ^/places(.*)$ /index.php?url=places/view/%1 break;
    }
    if ($query_string ~ "^q=(.*)&l=(.*)$"){
      rewrite ^(.*)$ /index.php?url=search/index/%1/%2 break;
    }
    if ($query_string ~ "^q=(.*)$"){
      rewrite ^(.*)$ /index.php?url=search/index/%1 break;
    }
    if (!-e $request_filename){
      rewrite ^(.*)$ /index.php?url=$1 break;
    }
  }

  location ~ \.php$ {
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
  }
}

I haven't written the original ruleset, so I've a hard time converting it. Would you mind giving me a hint how to do it easily or can you help me to convert it, please?

I really want to switch over to php5-fpm and nginx 🙂

Thanks

Best Answer

Try this block for the public location:

location /public {
    if ($args ~ "^pid=(?<placepid>[0-9]+)$") {
        rewrite ^/places /index.php?url=places/view/$placepid last;
    }
    if ($args ~ "^q=(?<getq>.+)&l=(?<getl>.+)$") {
        rewrite ^ /index.php?url=search/index/$getq/$getl last;
    }
    if ($args ~ "^q=(?<getq>.+)$") {
        rewrite ^ /index.php?url=search/index/$getq last;
    }
    if (!-e $request_filename) {
        rewrite ^(.*)$ /index.php?url=$1 last;
    }
}

In nginx, references to regex captures in query parts don't work the same way as in Apache. Here we use named captures ?<variablename> in the parts matching the query string $args. Then we use the variables in rewrite parts.

The configuration could be optimized further, as this version has unnecessary complexities (rewriting / to /public in the start).