Thursday, February 10, 2011

CodeIgniter NGINX Rewrite Rules

CodeIgniter NGINX
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).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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 "Syst
em.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_ROOT environment variable is derived from the root parameter and setting root on the server level vs within a location block is important.
  • Using the rewrite rules at the server level vs within location 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.
11
12
13
14
15
16
17
18
19
20
21
22
# 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:
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# canonicalize codeigniter url end points
# if your default controller is something other than "welcom
e" 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.
43
44
45
46
47
48
# removes access to "system" folder, also allows a "System.ph
p" 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.
50
51
52
53
54
55
# 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

No comments:

Post a Comment