Skip to content

Wordpress on Nginx on Dreamhost

By the time this is done being written I’ll have been running Wordpress on Nginx on a Dreamhost VPS. Better yet, I’ll be doing it with a smaller more well defined resource foot print, with better response times, and faster page loads than I had with Apache. The tradeoff, some more upfront configuration.

I’ve covered the broad strokes about my motivation here, here, and here. In short, Nginx offers a more consistent dependable level resource usage while still having the capability of scaling to serve may users, reducing the possibility of crashing the VPS while under moment of heavy load.

This is long, and may end up being multiple parts, so if you’re interested follow the jump and keep reading.


Let me make a couple of things clear. I’m not your technical support. If you run into a particularly challenging problem translating your sites to Nginx feel free to leave a comment, maybe I can help, maybe I can’t. On top of that, I have no idea how helpful Dreamhost’s support is going to be for Nginx related issues if you run into them. I’m not e

If you run software other than Wordpress on your Dreamhost VPS, that’s outside the scope of this article or any follow on articles. If that’s the case you may be able to get by simply by adding the code I list under Wordpress Itself, and seeing if it works. If not, you’ll need to consult the Nginx wiki to see if they have a solution or simply work it out for yourself.

In terms of switching things over… I maintain a development and test server in my office, that I can do these kinds of changes on. Unfortunately almost any test domain, other than on another Dreamhost VPS isn’t going to mirror Dreamhost’s config, so it’s possible to run into some unexpected issues in the process.

One alternative if you don’t have a test server or second VPS is to spin up your Nginx instance on a non-standard port like 8080 and test it while Apache is still running on 80. Unfortunately, I’m not going to cover how to do that.

Also, I’m not covering every step in detail, rather I’ll be pointing out the major issues I ran into and the fixes for them.

Understanding Dreamhost’s Nginx Config

Before you begin trying to transition to Nginx on a Dreamhost VPS, it’s helpful to understand how they have it configured by default.

Under normal conditions, i.e. you simply flip the switch in the web panel to change the server from Apache to Nginx, Dreamhost will generate a default Nginx config. This is located in /dh/nginx/servers/httpd-$HOSTNAME/.

This config file contains the basic configuration for all of the domains hosted by the virtual host. This include the CGI proxy settings to be able to process PHP files, as well as remapping certain URIs and turning on auto indexes.

It’s good enough to get some basic sites up and running, but it needs some tweaking to get anything else working correctly. Dreamhost accomplishes the extended tweaking by having each virtual hosts’ server section load and parse any files in the /home/$user/nginx/$domain/ directory.

For example, extra config directive for “example.com” run by user bob, would be stored in /home/bob/nginx/example.com/.

There is no limit in the Nginx config as to how many files can be included in that directory to configure the server. As such I find it’s useful to break my configurations into a couple of files. One is a “standardized” config file that enables Wordpress pretty permalinks and proper handling of WP Super Cache. The second is a site specific file that covers custom redirects that I’ve configured and anything else I may have to rewrite or deal with.

The name of the game for a seamless transition is to have the ~/nginx/ directory structure in place with the correct config files in them and read to go before you flip the switch in the control panel to jump to Nginx.

Wordpress

Wordpress’ design is still heavily slanted to running on Apache. It uses Apache’s .htaccess files to handle rewrite rules for pretty permalinks. Moreover, most caching caching plugins will attempt to detect if Apache’s mod_rewrite is enabled and adjust their behavior accordingly.

Nginx, however, is not Apache. It doesn’t read .htaccess files nor does it use mod_rewrite, even though it’s more than capable of doing those things.

First, to have functional pretty permalinks you’ll need to include the following in your ~/nginx/site.com/wordpress-nginx.conf file.

location / {
    try_files $uri $uri/ /index.php;
}

Second, Wordpress will likely whine about not being able to find mod_rewrite and may disable pretty permalinks from the Permalinks setting page. This plugin, Nginx Compatibility, gets Wordpress to happily believe, among other things, that mod_rewrite is running. As a result, Wordpress doesn’t disable things like pretty permalinks and the caching plugins don’t complain about mod_rewrite being unavailable.

Wordpress MU/Wordpress Network

The worst part of when things break is when it’s not obvious that they did. Wordpress MU will need an additional rewrite rule to handle serving files from the various additionally sites. The following covers that.

rewrite files/(.+) /wp-includes/ms-files.php?file=$1 last;

Wordpress Plugins

Most plugins will run just fine without ever caring what the server is. This is because the operate entirely inside the environment that Wordpress provides. I either run or have at least cursorily tested the following plugins and haven’t found any issues when running under Nginx.

  • All in one Favicon
  • All in One SEO Pack
  • Askmet
  • Block Bad Queries
  • Breadcrumb NavXT
  • Contact Form 7
  • Cookies for Comments
  • Custom Upload Directory
  • Dashboard:Pending Review
  • Dashboard: Scheduled Posts
  • External Links
  • FlickRSS
  • FV TopLevel Categories
  • Google Analiticator
  • Greg’s High Performance SEO
  • Multi-page Toolkit
  • Redirection*
  • Revision Control
  • Role Manager
  • Sexybookmarks
  • Simple Twitter Status Updates
  • Slimbox 2
  • Table of Contents Generator
  • TimesToCome Stop Bot Registration
  • TinyMCE advanced
  • Wordpress Mobile Edition
  • WP LaTeX
  • WP-PageNavi
  • WP Super Cache*
  • Yet Another Related Posts Plugin

That said, however, there are some plugins that depend on Apache’s functionality to improve their performance (*ed in the list above). These generally are caching plugins like WP Super Cache or W3 Total Cache. For these plugins it will be necessary to add rewrite rules to the ~/nginx/site.com/ config.

WP Super Cache Rules

There are a number of WP Super Cache rules I’ve found floating around the internet. I’m using these rules, though I can’t recall who to attribute them to.

This one in particular detects mobile browsers and passes them on to Wordpress. It’s a little less efficient, but it allows mobile theme plugins to operate properly. Also not, WP Super Cache will still cache and serve the mobile pages as WP Cache pages.

# WP Super Cache rules.
# Designed to be included from a 'wordpress-ms-...' configuration file.

# Enable detection of the .gz extension for statically compressed content.
# Comment out this line if static gzip support is not compiled into nginx.
gzip_static on;

set $supercacheuri "";
set $supercachefile "$document_root/wp-content/cache/supercache/${http_host}${uri}index.html";
if (-e $supercachefile) {
        set $supercacheuri "/wp-content/cache/supercache/${http_host}${uri}index.html";
}

# If this is a POST request, pass the request onto WordPress.
if ($request_method = POST) {
        set $supercacheuri "";
}

# If there is a query string, serve the uncached version.
if ($query_string) {
        set $supercacheuri "";
}

# Logged in users and those who have posted a comment get the non-cached version.
if ($http_cookie ~* comment_author_|wordpress_logged_in|wp-postpass_) {
        set $supercacheuri "";
}

# Mobile browsers get the non-cached version.
# Wastes CPU cycles if there isn't a mobile browser WP theme for the site.
if ($http_x_wap_profile) {
        set $supercacheuri "";
}

if ($http_profile) {
        set $supercacheuri "";
}

if ($http_user_agent ~* (2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800)) {
        set $supercacheuri "";
}

if ($http_user_agent ~* (w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-)) {
        set $supercacheuri "";
}

# Stop processing if the supercache file is valid.
if ($supercacheuri) {
        rewrite ^ $supercacheuri break;
}

Mind the long lines when copying and pasting.

If you don’t use a mobile theme plugin, you’ll get back a few CPU cycles by commenting out the code from “#Mobile browsers get the non-cached version” to just above “Stop processing if supercache file is valid”.

I include the above code and the snippet under Wordpress further up in a wordpress-with-supercache.conf file that I can copy or symlink to any domain I’m running Wordpress on.

One additional note. The Nginx rewrite rules aren’t intelligent enough to handle serving up the pre-gziped Super Cache files. I’m sure that could be added, but Nginx’s native gzip capabilities are fast enough that you’re not likely to see any performance gain from using them. At this time, I’d recommend disabling the “Compress pages so they’re served more quickly to visitors. (Recommended)” option in WP Super Cache.

As an aside, I suspect there may be a way to simplify the WP Super Cache rules into the try_files command noted previously.

W3 Total Cache

According to a post on Wordpress.org, W3 Total cache fully supports Nginx. I don’t know what that means with respect to external rewrite rules, as I don’t use W3 Total Cache and I haven’t had an opportunity to test it.

Custom Redirection Rules

I mention this because if you use a plugin like Redirection, and then use the mod_rewrite bit to accelerate that, you’ll need to translate your Redirection rules to something Nginx can use.

Nginx’s rewrite syntax is slightly different from Apache’s, though it is regex based so it’s not too hard to follow. Rewrite rules follow the format of rewrite src/url/ dst/url action;.

For example, if you want to redirct the page http://example.com/2011/some_old_post to http://example.com/2011/some_new_post you would use the following.

 rewrite /2011/some_old_post /2011/some_new_post permanent;

You can also use parenthesis—()—to capture patterns and the positional markers( $1, $2, etc.) will place them in the new URIs.

For example, if  I want to redirect the tag http://example.com/tag/some_old_tag to http://example.com/tag/some_new_tag, you would use something like this.

rewrite /tag/some_new_tag/(.*) /tag/some_old_tag/$1 permanent;

The complete documentation on Nginx’s rewrite rules is given on their rewrite wiki page. I suggest reading though it until you understand it if you have to do any custom redirection.

I’ve elected to save my custom redirection rules in a separate file from my stock wordpress config, however, if you’re not running multiple separate Wordpress installs, you could just as easily stick them in the same file as the rest of the site’s config.

Backout Plan

Before flipping the switch, I really strongly suggest a back out plan. If you’re doing it manually and editing config files from a root terminal session you should definitely back up your changes. If you’re just flipping the drop down in the Dreamhost panel, things are considerably easier. In short, it boils down to basically one thing.

Don’t delete the .htaccess files in your Wordpress directories.

If you find something horribly broken you can back out the change simply by going back into the Dreamhost web panel and setting the VPS’s server back to Apache. If you’re using one of the cache plugins, depending on what went wrong, you’ll also want to manually clear the cache after the transition back to Apache.

Flipping the Switch

Almost all the work involved in this is preparatory. Once you’ve created the ~/nginx directory structure and populated it with the relevant config files, it’s a simple matter of going into the Dreamhost web panel and flipping the VPS’s configured server over to Nginx.

If everything was done right, sometime in the next minutes you’ll be rewarded by a site that looks exactly the same, but reports (at least if you look at the headers) that it’s being serviced by Nginx.

What to do if something goes wrong

If suddenly everything disappears, including your home page, then there probably was a problem with a config file that prevented Nginx from starting. To start with, check your config files. Make sure lines are terminated by semicolons, directives are spelled correctly, etc. etc. If you’re concerned about this taking a long time, flip the virtual host back to Apache while you double check your configs.

If something specific stops working, like you can’t get to blog posts or something to that effect, Nginx will add it’s errors to the access.log and error.log found in ~/logs/site.com/.

If all else fails, switch back to Apache, and start Googling. I’d also recommend read though the offical Nginx wiki and Dreamhost’s Wiki page on Nginx.

Published inComputersLinuxWordpress

9 Comments

  1. Have you tried setting up nginx to run php as php-fpm instead of fcgi? I made the nginx switch on dreamhost but keep finding that php service hangs and chokes.

  2. Jason

    To be perfectly honest, I’d much rather be running PHP-FPM than the plane CGI backend. The only problem is, so far as I can tell, Dreamhost doesn’t have php-fpm available on their VPSes or in their package library, which means building PHP5.3 from source, and that’s just way more effort to manage and deal with than I’d like.

    Perhaps we should start a suggestion for Dreamhost to include an updated Nginx + PHP5.3 + PHP-FPM + APC stack.

  3. Nice write up! Too bad I didn’t find it BEFORE I got my nginx/WordPress site converted from Apache. It might be too late for you as this is a old post. But to get nginx to serve already compressed static files, you simply need to add: gzip on;

    to the “http” section of your config like the snippet below.

    #Gzip
    gzip on;
    gzip_static on;

    “gzip on” tells nginx to serve a already compressed copy if it’s available and of the same file name. You can do this with all your static text files (.js .css .xml and such).

    Hope it helps you and others 🙂

    PS… I strongly suggest adding php-APC to your setup. Out of the box I felt the surge in speed. My page generation speed went from .250 or so to .065! Even the WP backend was screaming fast!

  4. Jason

    @ Lee H
    Actually, I do have gzip enabled globally not on a per server basis, which is why “gzip on;” isn’t in the per site configs.

    As for PHP-APC, I’m currently running that on my development box, and yes, I’ve been looking at moving from xCache to APC, however, it’s quite low on my priority list at the moment. I’d also like to move from php-cgi to php-fpm as well, but that too is somewhat low on the priority list.

  5. […] an excellent Dreamhost guide on how to complete the transition, and several other Dreamhost users (here and here, for example), have successfully neogtiated the […]

  6. Have you upgraded to nginx 1.4, and have you figured out new rewrite rules for supercache? The if() statement was finally removed apparently. (Unless I’m just missing something really easy).

  7. Oh wow. Nginx’s statement parser can’t deal with “if(…)” but only “if (…)”
    Works now.

  8. Jason

    My understanding of Nginx has always been that a space was required between the if and the open paren. That’s certainly been the case since at least as long as I’ve been using it. Ignoring the space fails on 1.1.19 on my dev machine.

    Nginx without having if for rewriting would be highly problematic. Using if may be less than ideal–it’s certainly bad, and being using incorrectly, if your using it for something other than rewriting–but not having it would make things problematic at best.

Comments are closed.