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/\ permanent; # } # enforce NO www if ($host ~* ^www\.(.*)) { set $host_without_www $1; rewrite ^/(.*)$ $scheme://$host_without_www/\ 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/?$ /\ permanent; } # removes trailing slashes (prevents SEO duplicate content issues) if (!-d $request_filename) { rewrite ^/(.+)/$ /\ permanent; } # removes access to "system" folder, also allows a "System.php" controller if ($request_uri ~* ^/system) { rewrite ^/(.*)$ /index.php?/\ last; break; } # unless the request is for a valid file (image, js, css, etc.), send to bootstrap if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?/\ 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_ROOT
environment variable is derived from theroot
parameter and settingroot
on theserver
level vs within alocation
block is important. - Using the rewrite rules at the
server
level vs withinlocation
block 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/\ permanent; #} # enforce NO www if ($host ~* ^www\.(.*)) { set $host_without_www $1; rewrite ^/(.*)$ $scheme://$host_without_www/\ 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/?$ /\ permanent; } # removes trailing slashes (prevents SEO duplicate content issues) if (!-d $request_filename) { rewrite ^/(.+)/$ /\ 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?/\ 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?/\ 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_uri
is 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:
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?
since you have the catch all line:
rewrite ^/(.*)$ /index.php?/$1 last;
then later you have the
location ~ \.php$ { }
my question are:
why the question mark in the end of index.php?
why only matching address ended with .php? in that case, /index.php?/controller/method/variable won’t be able to translated to /controller/method/variable
I had to change the lines to the following..
rewrite ^/(.*)$ /index.php?/$1 last;
location ~ \.php { }
ok. I take it back what I said above. it turns out the question mark in “rewrite ^/(.*)$ /index.php?/$1 last;” makes “location ~ \.php$ { }” match. so I was wrong 🙂
Hello,
Thank you for this nice article.
I am looking to redirect robots.txt to robots-off.txt could you tell what is the nginx rule I need for that?
Thank you!
Your Rewrite rule for Nginx is Superb!
Thanks 🙂
Thank you so much. This saved hours of my time! Exactly what i was looking for!
How can we redirect URL with .htaccess file.I want to redirect only 1 URL rest will be the same.Please help me….
You could use ModRewrite or a simple redirect:
also do a search on stackoverflow you will find lots of info
Hi Dimas,Thanks for your reply.I had try this but it is not working.I am using Codeigniter V1.7 & already rewrite most of the URL’s with .htaccess but unable to redirect URL’s with 301.Do you have any solution for this situation?
If you are using apache htaccess and codeigniter, then you should probably have access to modrewrite in which case you can do your redirect with it … what does your htaccess file look like (post to https://gist.github.com/ so that i may have a look)
Hi Dimas,I can’t show it publicly.My client won’t allow to do so because their privacy hope you understand.But,you can check the below code to know how it looks :
RewriteEngine On
RewriteBase /
I had copied first & last line from that file.Hope it would get some solution!
The first & last line automatically removed.Hope it gives you hint for it IfModule.
Thanks!
Without being able to take a look at the structure of the file and commands, I can’t be much help … you can try a redirect using modrewrite …
Hey Thanks Dimas.This Works! I had recreate complete .htaccess file.It has lots of issues the client has used 2 types of rewrite rules.Might that was causing a problem.
Thanks for your help!!!
Thanks for this excellent post Dimas but I’m having problems. I get a message saying that the “server” directive is not allowed here in /etc/nginx/sites-enabled/000-apps.vhost and if I remove the server directive there I get the same error in /etc/nginx/sites-enabled/000-ispconfig.vhost.
Any ideas?
Thanks .. using this with winginx 😉
location ~ \.php$ {
if (!-e $document_root$document_uri){return 404;}
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
After hours of searching and scratching my head.. here you are. Thanks, this worked like a charm. Keep up the good work!
Nginx is very helpful to developer because developer is easy run to his appliafcation by Nginx.That is good information, it is useful to me thanks.
Great article! After scratching my head for an hour your article helped. But there is one issue, as all the requests are passing in this format “/index.php?/$1”
It becomes a problem if i am passing some GET parameters using.
Example if i pass GET param “name” to controller “page” it becomes “/index.php?/page&name=something”
Any way to solve this issue?
Hey Dimas,
Great article – I’m just wondering if you’ve ever got Nginx serving Codeigniter and WordPress together successfully?
I’m trying to do that at the moment we have a folder for Codeigniter files e.g. /ci and one for WordPress /site
Jim
After somehour googling and testing without any luck..
Finally found your article!!
Work like a charm..
But one question, i’m n00b in nginx
where should I put the PHPMyadmin block on these??
Thanks
Hi,
Am I putting this rewrite rule properly? /etc/nginx/sites-available/default?
How come I copy-pasted it on the said file and it does not work?
The URL I am using is : http://ipaddress/proj/index.php?/controller
Where it should just be: http://ipaddress/proj/controller
Old post, but still worth a try.
Using ISPConfig 3 with NGINX, and want to host a Joomla website 1.5, with SEF enabled.
Howto? Afaik, NGINX ignores .htaccess ?
I want it to use the .htaccess provided by Joomla.
Nginx does not support the use of htaccess files, you would have to convert them into something that Joomla would understand .. I found this on the web, hope it’s a step in the right direction …
Seen it too, but seems like it doesn’t wanna play with ISPConfig 3, grr 🙂
“IfIsEvil” is kind of a key to nginx, though. Forcing nginx to evaluate and process many different IF statements is not considered a good practice.
I’d recommend try_files.
http://wiki.nginx.org/Pitfalls
Check “Front Controller Pattern Based Packages”