Nginx Caching for WordPress

I was searching for a way to enable caching for WordPress and I stumbled across this great article.

In the example that was given, there was an Apache server working the backend while an nginx server was working as a front-end cache.  Those are too many services for me, so I wanted to use just one system.  Nginx.   Here is how I did it (much of this information was taken verbatim from the link above).

First, install the WordPress Nginx proxy cache integrator into WordPress. You can download it from here:
Activate it after it is downloaded.

Then create this file:

proxy_cache_path  /var/lib/nginx/cache0  levels=1:2   keys_zone=staticfilecache:180m  max_size=250m;

proxy_temp_path /var/lib/nginx/proxy;
proxy_connect_timeout 30;
proxy_read_timeout 120;
proxy_send_timeout 120;

upstream wordpressapache {
        #The upstream apache server. You can have many of these and weight them accordingly,
        #allowing nginx to function as a caching load balancer (oh my. Awesomeness abounds.)
        server weight=1 max_fails=3 fail_timeout=30s;

First, copy /etc/nginx/sites-enabled/default to /etc/nginx/sites-enabled/default.proxy

cp /etc/nginx/sites-enabled/default /etc/nginx/sites-enabled/default.proxy

Then, I changed this line in /etc/nginx/sites-enabled/default from

server {
	listen   *:80; ## listen for ipv4

to this

server {
	listen   *:81; ## listen for ipv4

This basically tells nginx to listen on port 81 instead of 80, which we will find out why soon enough.

Now, edit /etc/nginx/sites-enabled/default.proxy and add the following under the server section.

# Set the hostname
proxy_set_header Host $host;

#Set the forwarded-for header.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

location / {
     index  index.php index.htm tracker.php;
     # If logged in, don't cache.
     if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
            set $do_not_cache 1;
     proxy_cache_key "$scheme://$host$request_uri $do_not_cache";
     proxy_cache staticfilecache;
     proxy_pass http://wordpressapache;

location ~* wp\-.*\.php|wp\-admin {
     # Don't static file cache admin-looking things.
     proxy_pass http://wordpressapache;

location ~* \.(jpg|png|gif|jpeg|css|js|mp3|wav|swf|mov|doc|pdf|xls|ppt|docx|pptx|xlsx)$ {
     # Cache static-looking files for 120 minutes, setting a 10 day expiry time in the HTTP header,
     # whether logged in or not (may be too heavy-handed).
     proxy_cache_valid 200 120m;
     expires 864000;
     proxy_pass http://wordpressapache;
     proxy_cache staticfilecache;

location ~* \/[^\/]+\/(feed|\.xml)\/? {
     # Cache RSS looking feeds for 45 minutes unless logged in.
     if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
            set $do_not_cache 1;
     proxy_cache_key "$scheme://$host$request_uri $do_not_cache";
     proxy_cache_valid 200 45m;
     proxy_cache staticfilecache;
     proxy_pass http://wordpressapache;

location = /50x.html {
     root   /var/www/nginx-default;

location ~ /\.ht {
     deny  all;

Now run the following to get your site back online.

service nginx reload


For any doubters of evolution, look closely the next time you drive down a highway. Look to the side of the road at all of the debris. Look in between the lanes at debris. Is there more in those places than in the center of the lanes? Of course there is. That’s because as cars hit the debris, it moves around. And it keeps moving around until it rests in a place where nobody hits it anymore. In an abstract sense, the debris evolves. What makes anyone think that our bodies cannot do the same thing?

Crisis Management

Successfully navigating through an IT crisis requires both successful problem solving AND successful communication.

When it comes to a crisis, it is absolutely imperative to communicate effectively. People tend to fill in the details of what they do not know with their imaginations. Most often, those ad-lib details are inaccurate. Without good communication, you could experience the best, most ingenious solutions in the world, and you would not be the wiser. Seeing the ashes of a house that once stood might make you condemn a fire department. But knowing that the firemen saved everyone single living being in that house might allow you to focus on and appreciate the heroism, rather than to kindle any condemnation.  The facts do not change, but your perspective does.  Good communication yields more accurate perspectives and that is exactly what you want during a crisis.

Should the NSA have data monitoring capabilities?

Personal freedom is what is at stake here, or at least that is the concern of many. How can someone feel free to speak their mind on government matters if their anonymity is nothing but a transparent cloak in the eyes of the government? The ability for any person or organization to indiscriminately and discretely collect personal data about others is power, no matter how you look at it. As they say in the movies, “With great power comes great responsibility.”

Trust is the real issue for most people. Do we trust our government to use good judgment and sufficient discretion with a tool as powerful as the one that they have in front of them?

But this debate really goes even deeper than the previous questions. Without context, idealists on the right and the left will draw hard lines about this. But the challenges that our country faces are quite complicated. Working in the IT field, I have been presented with many real-world security challenges. Usually it boils down to the many vs. few predicament. Should we let the few rotten apples spoil the bunch? How do you save the good apples? If only a few people at a company present most of the risk to the entire company due to their abuse of policies, do you take away everyone’s rights by imposing restrictions on everyone? Or do you develop a comprehensive system for holding people accountable so that you can allow more freedoms? What if the same system of accountability that protects personal rights requires access that encroaches on personal freedoms? Now you have to choose between the lesser of two evils. When you throw in “trust”, it further complicates the decision. Maybe now, you too understand the predicament that we, as a country, face.

Leaving VirtualBox

After testing a virtual machine in VirtualBox, I decided to move to a different hypervisor. I removed the VirtualBox tools and after rebooting, I could no longer use my mouse. The following devices showed up with yellow exclamation marks in Windows XP.

HID-compliant mouse
PS/2 Compatible Mouse

After much research, I could not find a solution online. In the end, I managed to fix the issue on my own. Here is what I did to resolve this issue.

  1. Open regedit as an administrator.
  2. Expand HKEY_LOCAL_MACHINE and then SYSTEM.
  3. Click on CurrentControlSet.
  4. Search for “mouse”. The first entry returned should have a string for “UpperFilters”. If it is not there, repeat the search until you see an entry for “UpperFilters”.
  5. Double-click UpperFilters and remove the reference to the VBox driver. It should only say “mouclass” at this point.
  6. Click ok to complete the changes.
  7. Reboot.

At this time, your mouse should be working again.

How to get Nginx Working With PHP Fastcgi in Debian Squeeze

First, you need to install the following.

sudo apt-get install php5-cgi nginx

Next, you need to edit the file /etc/nginx/fastcgi_params. It should look like this:

fastcgi_index  index.php;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_FILENAME        $document_root$fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

Now, you need to create a new site. Here is an example site that should work:

server {
	listen   *:80; ## listen for ipv4

	server_name; # This is where you define your host headers.
        root   /var/www/html/;

	access_log  /var/log/nginx/localhost.access.log;
	location / {
		index  index.php index.html index.htm;
	error_page  404  /index.php;
	location ~ \.php$ {
	  # Filter out arbitrary code execution
	  location ~ \..*/.*\.php$ {return 404;}
	  include fastcgi_params;

Take notice to the “root /var/www/html/;” line and how it is not inside the location tag. This is on purpose so that it is inherited by the other configuration blocks.

Now you just need to create a /etc/init.d/php-fastcgi file with the following content:

# Provides:          php-fcgi
# Required-Start:    $nginx $network
# Required-Stop:     $nginx
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php over fcgi
# Description:       starts php over fcgi
(( EUID )) && echo ‘You need to have root priviliges.’ && exit 1
PHP_CGI_NAME=`basename $PHP_CGI`
start() {
      echo -n "Starting PHP FastCGI: "
      start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
      echo "$PHP_CGI_NAME."
stop() {
      echo -n "Stopping PHP FastCGI: "
      killall -q -w -u $USER $PHP_CGI
      echo "$PHP_CGI_NAME."
case "$1" in
      echo "Usage: php-fastcgi {start|stop|restart}"
      exit 1
exit $RETVAL

Now, let’s make sure that the php-fastcgi script starts with the server:

sudo update-rc.d php-fastcgi defaults

And lastly, let’s start everything.

sudo service php-fastcgi start
sudo service nginx start

That’s it! Your site should work at this point.

How To Fix Widgets After Changing Your WordPress SiteURL

So you finally get around to buying that domain name for your WordPress site. You export a backup of your database and do a search and replace on the database file.   But when you import the database back in, your widgets are not there.  How do you fix it?

This plugin is a lifesaver! Enough said.
Widget Fixer

A Quick Way to Remove /index.php From WordPress Permalinks

This assumes that you are using Lighttpd as your web server.  But this trick should work with all web servers.

If you are using Lighttpd, add the following line to your site settings in lighttpd.conf.

server.error-handler-404 = "/index.php"

You now need to restart Lighttpd.

sudo service lighttpd restart

Now login to your wp-admin console and change the permalink URL to resemble the following.

That’s it!   You’re done.   The simple, easy, elegant way to get WordPress to work without showing the index.php.

Update: If you do not wish to use the 404 trick, there is another way to accomplish the same thing by using a mod_rewrite rule. The following example illustrates how to use mod_rewrite to accomplish the same thing as we did above with the 404 error handler.

url.rewrite-once = (
	"^/(wp-content|wp-includes|wp-admin|.*\.php\??).*$" => "$0" ,
	"^/((?!(index.php)).*$)" => "/index.php/$1"

How to Switch WordPress from Apache to Lighttpd

If you are using Ubunutu, there are a couple of packages that you need first.  This command should get you what you need.

sudo apt-get install lighttpd php5-cgi

Now, let’s edit the /etc/lighttpd/lighttpd.conf file.  You need to add mod_fastcgi to your server.modules line.  It should look something like this when you’re done.

server.modules = ( "mod_access", "mod_rewrite", "mod_fastcgi", "mod_accesslog", "mod_redirect" )

Now let’s add the fastcgi.server settings so that it knows what to do with a .php page.

fastcgi.server = (
    ".php" =>
       ( "localhost" =>
              "socket" => "/tmp/php-fastcgi.socket",
              "bin-path" => "/usr/bin/php-cgi"

Now we need to make index.php pages part of the normal start pages.

server.indexfiles = ( "index.html", "index.php" )

Lastly, we simply need to change the document-root to point to our wordpress installation.   It should look something like this.

server.document-root = "/var/www/wordpress"

Now run these few commands to stop Apache, make sure it doesn’t start again, start Lighttpd, and make sure it automatically starts for you.

sudo service stop apache2
sudo service start lighttpd
update-rc.d apache2 remove
update-rc.d lighttpd defaults

That’s it!    Enjoy WordPress running on Lighttpd!