
If you are a CodeIgniter enthusiast, you know that finding rewrite rules for Apache (htaccess file) is relatively easy, but doing the same for Nginx rewrite rules is not all that simple. Use these Nginx rewrite rules to get your next CodeIgniter project up and running.
So I had a little fun with Nginx this weekend, I setup a rackspace server, installed Nginx (with PHP and MySQL), and installed CodeIgniter.
If you are a CodeIgniter enthusiast, you know that finding rewrite rules for Apache (htaccess file) is relatively easy, but doing the same for Nginx rewrite rules is not all that simple. The rules that follow are from my original article: CodeIgniter htaccess (for Apache) and are an exact translation into Nginx rewrite rules.
CodeIgniter Nginx Config
Here is the entire config file that I use. Remember that some of these rules are commented out, you will have to explicitly enabled them by removing the comments (removing the “#” from in front of the rule).
server
{
server_name .example.com;
access_log /var/log/nginx/example.com.access.log;
root /var/www/example.com/html;
index index.php index.html index.htm;
# enforce www (exclude certain subdomains)
# if ($host !~* ^(www|subdomain))
# {
# rewrite ^/(.*)$ $scheme://www.$host/$1 permanent;
# }
# enforce NO www
if ($host ~* ^www\.(.*))
{
set $host_without_www $1;
rewrite ^/(.*)$ $scheme://$host_without_www/$1 permanent;
}
# canonicalize codeigniter url end points
# if your default controller is something other than "welcome" you should change the following
if ($request_uri ~* ^(/welcome(/index)?|/index(.php)?)/?$)
{
rewrite ^(.*)$ / permanent;
}
# removes trailing "index" from all controllers
if ($request_uri ~* index/?$)
{
rewrite ^/(.*)/index/?$ /$1 permanent;
}
# removes trailing slashes (prevents SEO duplicate content issues)
if (!-d $request_filename)
{
rewrite ^/(.+)/$ /$1 permanent;
}
# removes access to "system" folder, also allows a "System.php" controller
if ($request_uri ~* ^/system)
{
rewrite ^/(.*)$ /index.php?/$1 last;
break;
}
# unless the request is for a valid file (image, js, css, etc.), send to bootstrap
if (!-e $request_filename)
{
rewrite ^/(.*)$ /index.php?/$1 last;
break;
}
# catch all
error_page 404 /index.php;
# use fastcgi for all php files
location ~ \.php$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/example.com/html$fastcgi_script_name;
include fastcgi_params;
}
# deny access to apache .htaccess files
location ~ /\.ht
{
deny all;
}
}
Some Very Important Notes
I spent nearly half a day testing out these rules, so here are some important things I noticed:
- The PHP
DOCUMENT_ROOTenvironment variable is derived from therootparameter and settingrooton theserverlevel vs within alocationblock is important. - Using the rewrite rules at the
serverlevel vs withinlocationblock is also key in their proper functionality, certain rules will not work properly otherwise.
Nginx Rewrite Rule Breakdown
The first set of rules allow you to enforce “www” or enforce NO “www”, you will have to pick which you prefer and enable one or the other. Additionally, for those who may have subdomains, adding the subdomains to the list (if enforcing www) will safely exclude those subdomains from being redirected.
# enforce www (exclude certain subdomains)
#if ($host !~* ^(www|subdomain))
#{
# rewrite ^/(.*)$ $scheme://www.$host/$1 permanent;
#}
# enforce NO www
if ($host ~* ^www\.(.*))
{
set $host_without_www $1;
rewrite ^/(.*)$ $scheme://$host_without_www/$1 permanent;
}
I’ve also made some additions in an attempt to Canonicalize some of the CodeIgniter URL end points. The key benefit of a Canonicalized URL is that your search engine page ranking (page juice) is not spread across several pages, but instead, targeted to a single page.
In your CodeIgniter project you will typically have a default controller and you will be able to access this controller at the following URLs:
/ /welcome /welcome/ /welcome/index /welcome/index/ /index.php
That’s a total of 6 URL end points pointing to the front controller. Additionally other controllers you’ve created will also have a default “index” method, consider the following:
/category /category/index /category/index/
Again, a total of 3 URL end points where there should only be one. These next set of rewrite rules prevent this:
# canonicalize codeigniter url end points
# if your default controller is something other than "welcome" you should change the following
if ($request_uri ~* ^(/welcome(/index)?|/index(.php)?)/?$)
{
rewrite ^(.*)$ / permanent;
}
# removes trailing "index" from all controllers
if ($request_uri ~* index/?$)
{
rewrite ^/(.*)/index/?$ /$1 permanent;
}
# removes trailing slashes (prevents SEO duplicate content issues)
if (!-d $request_filename)
{
rewrite ^/(.+)/$ /$1 permanent;
}
With these rules the front controller will always be accessed at “/” and any other URLs pointing to a controller’s “index” method will be accessed at “/controller”. Notice that I also use a 301 redirect, this aids in maintaining or passing any existing search engine ranking (page juice) to the final redirected page.
So these:
/welcome /welcome/ /welcome/index /welcome/index/ /index.php
… would simple become:
/
… and:
/category /category/index /category/index/
… would become:
/category
Another important thing to note: for controllers with an “index” method which take any sort of parameter, these URLs will still work as such:
/welcome/index/123 /category/index/123
To be able to remove the “index” (or “welcome/index”) and still have parameters passed in, you will need to configure your routes file.
The next rule prevents access to the system directory and additionally allows you to have a System.php controller file.
# removes access to "system" folder, also allows a "System.php" controller
if ($request_uri ~* ^/system)
{
rewrite ^/(.*)$ /index.php?/$1 last;
break;
}
And the final rule is the catch all to route all requests to the bootstrap file.
# unless the request is for a valid file (image, js, css, etc.), send to bootstrap
if (!-e $request_filename)
{
rewrite ^/(.*)$ /index.php?/$1 last;
break;
}
Apply These Final Touches to Clean Up the URL
Remember, once you have your CodeIgniter Nginx config setup, you will want to go into your “/system/application/config/config.php”, find the following:
$config['index_page'] = "index.php";
and change it to:
$config['index_page'] = "";
Because you are using Nginx rewrites, the above will set your config file so that “index.php” will NOT show up as part of the URL as such:
http://www.example.com/index.php/controller/method/variable
instead your URLs will be cleaner:
http://www.example.com/controller/method/variable
If you have comments or improvement suggestions please let me know.

http://www.example.com/controller/method/variable
instead your URLs will be cleaner:
Can you make an htaccess that will remove the controller/method/
and the result will be this.
http://www.example.com/how to build house /id here
Richard, Take a look at CodeIgniters URI Routing. You may be able to route all requests to one controller, then handle them accordingly there. Also look at the URI Class for details on getting the segments of the URI.
Hi,
Trying this now and getting
Invalid condition: "request_uri" on line 14…which is the first conditional after the enforce no www block.
nginx 0.8.52
php 5.3.3 / suhosin
That’s weird cause
$request_uriis part of the HttpCoreModule, I’ll search around, if I find anything I’ll post it here.These rules helped me a lot.
Thanks man
Hi,
unfortunately I’m having persiting problems getting my ISP- site statistics area working with Nginx…
For Apache I was using following .htaccess snippet:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/(stats|failed_auth\.html).*$ [NC]
RewriteRule . – [L]
But now, being on Nginx, I don’t can find any rewrite rule for…
Any help would be real great.
Thanks lot in advance!
Erik
Erik, I am no expert on Nginx, so the code I provide is definitely a work in progress and should be tested:
if ($request_uri ~* ^/(stats|failed_auth\.html).*$) { break; }The rule should be somewhere before other statements. Start there and see if that works…
I added your rule and reloaded Nginx today. There was no site blocking AND the site statistics is opening with the old content before I moved to Nginx – that looks great at first.
Will take a look at my ISP- site statistics area tomorrow for updated stats – I’ll report here if the rule is working.
THANKS!
@ Dimas
Hi,
now I got acces to the ISP- site statistics area at http://domain.com/stats/, but unfortunately the the stats aren’t updating (last daily report from 2010-12-16 at http://domain.com/stats/daily/2010-12-16/index.html)…
In regards to the stats, I wouldn’t be able to tell you whether its a nginx rule or an ISP issue. Log stats are always nice, you’ll have to look more into nginx and it’s log/format.
Additionally you may consider using Google Analytics or something like Mint, the downside of these offerings is that you have to include code in each page which needs tracking.
Also, I am using the “peekaboo_collapse_all” feature, you can find a note about it in the admin page for Peekaboo.
Hi, why my output always 404 Page Not Found with your tutorial? Let me now to solve it
Hi,
thanks for the rules… I have one problem, this doesn’t seem to work with multiple codeigniter applications
I have a frontend and backend (application/frontend & application/backend). I use a index.php and a admin.php in the root. The index.php works fine, but for the admin.php (www.test.com/admin.php/controller/method) this doesn’t work… Any fix for this?
Thanks!
And you should use: try_files (instead of: if (!-e $request_filename))
http://wiki.nginx.org/HttpCoreModule#try_files
@tuurtnt, you will need to route proper requests to
admin.php, how you differentiate a proper request is up to you. One suggestion is to prefix admin requests with “admin” … example.com/admin/admin.php/controller/method and route everything from “/admin” to admin.php … or you could route on the specific controller name.Hi,
ok I will try to figure it out… I have one question, what does the $ mean in (location ~ \.php$)
Also take a look at this:http://wiki.nginx.org/Pitfalls#Pass_Non-PHP_Requests_to_PHP
Hello. Thanks for posting this, worked like a charm.
However I got a problem with $_POST returning always an empty array.
The same code in apache works fine. Ever run into it ?
@VangelisB, I have run into this before, you will notice that if your post request is being redirected (per the rules) the POST data is lost (confirm in firebug). Make sure the POST data is going to the final end-point.
thank you for ur amazing article.
i’ve tried ur article but it doesn’t work. I always got 403
can u translate this to me ? i really have no idea about this
my default controller is home
RewriteEngine On
RewriteCond %{REQUEST_URI} ^system.*
RewriteRule ^(.*)$ index.php?/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
Hi Dimas does above config also apply in new version of codeigniter? I have currently using version 2.0.2
You sir, are a scholar and a gentleman. I recently made the transition to nginx and you eliminated the last hitch!
Hi Dimas,
I am new in Nginx and I must convert .htaccess rule to work with Nginx.
What’s the file name of this config and where’s the place? is it on the folder like .htaccess?
Thank you very much,
Winoto
Nice job. It’s very helpful article. I fixed my problem with this article. I love codeigniter with nginx!
hi, i just download fresh codeigniter and upload it to my server with nginx. i applied your configuration for my nginx server, then i open the website and i got the welcome page.
but when i try access it like http://server/index.php/welcome i got “500 Internal Server Error”, what should i do next?
Thanks,
But what is the filename of this config?
Where should I place this file?