Porting standard Apache’s mod_rewrite rules to Nginx

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, December 11, 2011

Follow me on Twitter as @mattiasgeniar

Most webframeworks will provide you with a .htaccess file that contains RewriteRule’s to be used in Apache to create “clean URLs”, or “routes” as it’s called in Zend Framework. The problems is that it doesn’t work for Nginx as it doesn’t read .htaccess file and wouldn’t understand the syntax anyway.

So, here’s a basic example of how to rewrite some rules.

This is usually what you find in the .htaccess file.

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [NC,L,QSA]

The above simply says: if what you are trying to access isn’t a file or a directory, pass it to my index.php script where you attach the page you’re trying to access ($1) to the query string “q=”.

In nginx, it would become something like this.

if (!-e $request_filename) {
    rewrite  ^(.*)$  /index.php?q=$1  last;
    break;
}

The above does the same thing as the RewriteRule in Apache: if the file you’re trying to access doesn’t exist locally (!-e $request_filename), rewrite it to the index.php page with the actual page as a parameter.

So, what about those additional Apache flags you pass along with the RewriteRule?

  • NC: no-case, to perform a case insensitive regex. Since we’re not matching [a-z] that doesn’t matter here. We match everything within (.*).
  • L: the Last rewrite, don’t process any more rules when this one gets executed. That’s solved by adding the last keyword after the rewrite-line in Nginx.
  • QSA: Query-String-Append is automatic in Nginx. You don’t need to specify that any other parameters need to be appended automatically. If you don’t want that, you can add a question mark after your rewrite (rewrite  ^(.*)$  /index.php?q=$1**?**)

In fact, the nginx config above is not that performant. Every request on the server needs to be evaluated in that if-statement, which is something nginx strives to avoid. Therefore, the if() statement above, can also be rewritten as follows.

location / {
    try_files $uri $uri/ /index.php?q=$1;
}

The try_files config will attempt to access the files in order. In this case, it will check if “$uri” is a file being accessed directly. If that’s not the case, it will check if “$uri/” is a directory (note the trailing slash). IF that’s also not the case, it will pass to the index.php script with the given query-string.

That should/could help you get started with rewriting Apache RewriteRules to Nginx! For other examples, have a look at Converting rewrite rules by Nginx.org.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.