Faster WordPress: Multisite, nginx, and Batcache

A couple weeks ago I decided to move this site to a new server. With the help of Pete Mall and Mark Jaquith I settled on the following setup:

  • Linode 512 MB
  • Debian 6 32-bit
  • PHP-FPM
  • APC (for opcode and object cache)
  • nginx
  • WordPress Multisite
  • Batcache

I documented my setup and after testing it with another friend (it worked!) and mentioning it to a couple others, decided to post it here. I’m going to assume you’re familiar with the basics of administering a VPS, especially SSH.

Linode

I did this on Linode, but it will probably work fine on pretty much any VPS (or dedicated server). It won’t work on a shared host because it depends on installing specific software that requires root access. My server needs are not very extravagant so I chose Linode’s cheapest plan, a 512 MB VPS. You’ll need to choose a location for your server, and since I have no idea what the practical differences are, I went with Dallas based on a recommendation. For the purposes of this tutorial, it doesn’t matter which one you choose.

Go through the Linode setup, choose the Debian 6 32-bit distribution, get your ssh information, and login to your new server. If you use a larger VPS you might want the 64-bit distribution, but on a 512 MB server that’s going to cause problems.

Linux

Linode has a very good tutorial on the first few things you’ll want to setup with your new Linux install. Once you’re logged in you can skip to the security section in Linode’s “Getting Started” tutorial. That will walk you through:

  • Updating your package installer
  • Setting your server’s hostname
  • Setting the timezone

Your settings here can be unique to you. In my case I like to name computing devices after Yankees players (see my external hard drive named Mattingly) so I called my Linode server dimaggio. I like to use my local time, which is America/Los_Angeles in the Linux world. Some people like to use UTC, which we do at Automattic. Pick your poison.

Before you go any further, you should install sudo because you’ll need it soon and your server won’t have it by default. You can do it with this one liner:

apt-get install sudo

Now that you have the basics setup, it’s time to move onto the real stuff — users, permissions, firewalls, and software. Slicehost has two great tutorials on this: Debian part 1, and Debian part 2. We’ll go through these now.

You don’t want to be logged in as root any longer than you absolutely have to. The first thing Slicehost will walk you through doing is creating a new user account. They use the username demo but you’ll probably want to use your first name. In my case I skipped the additional group management steps; I don’t plan on managing a large number of users and it’s easier to have fewer moving parts. If you don’t assign your user to a group, it will be automatically put in a group with its own name — my user is in a group called evan. Slicehost will walk you through the details, but I’ll add one suggestion: do not log out of your root SSH session until you’ve successfully logged into your user account and confirmed that your sudo access works. Otherwise you’ll need to reset your whole server and start from the beginning. Once you’re setup, move onto part 2.

Part 2 mainly covers Bash and the Aptitude package installer. I am pretty particular about my bash prompt. You can grab the key parts of mine here. This does a few things:

  • Shorten long directory names by replacing the middle with an ellipse
  • Add the git branch name to the prompt (if you’re in a git repo)
  • Use up and down arrows to search your bash history using whatever you’ve already entered as a search prefix
  • Make tab cycle through available commands instead of listing them
  • Add tab-completion for git commands

The git pieces rely on this git auto-complete script.

Once you’ve got your .bashrc setup and your package repositories updated, it’s time to move onto the the next step: PHP-FPM.

The stack: PHP-FPM

Debian’s default package repository has an outdated version of PHP-FPM, so first we’re going to add a new repository to our list. Aptitude’s repository list is kept in /etc/apt/sources.list and we want to add a new line with this repo: deb http://packages.dotdeb.org stable all. You’ll need to use sudo to edit this file and save it. When you’re finished, it should look something like this. Now go back to your home directory and setup your new repository.

cd ~
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -
rm dotdeb.gpg
sudo apt-get update
sudo apt-get upgrade

Now we can install PHP and its siblings:

sudo apt-get install php5 php5-fpm php-pear php5-common php5-mcrypt php5-mysql php5-cli php5-gd php5-apc

We’ll be using PHP-FPM to handle all of the PHP requests that come in through nginx. To do that, we’ll need to update the PHP-FPM config at /etc/php5/fpm/pool.d/www.conf. We will set PHP-FPM to decide how many processes it will run and how it will listen for requests from nginx. My config file is here. It will set PHP-FPM to spawn a reasonable number of children and servers for 512 MB VPS and configure it to listen over a Unix socket instead of a TCP port. These settings may not be perfect for you, but they should get you started.

Restart PHP to make sure your new settings are in effect.

sudo /etc/init.d/php5-fpm restart

The stack: nginx

We’re going to use nginx as our web server, so first we’ll install it.

sudo apt-get install nginx

Now we’ll setup our nginx config at /etc/nginx/nginx.conf to tell nginx how to serve our data. This file is pretty straightforward, but it does assume you’re using the 512 Linode server (or another one like it). You can grab mine here.

Once you have your config in place, restart nginx to use the new settings.

sudo /etc/init.d/nginx restart

The stack: MySQL

The last part of your stack is MySQL, which we will install now:

sudo apt-get install mysql-server php5-mysql

Once you complete the MySQL installer you can head over to Linode’s low memory settings tutorial to configure some settings for MySQL geared toward low memory servers (which a 512 MB VPS is). I followed their guidelines in my config, so I won’t copy it here. The last two items won’t be in your default my.cnf file, so you can add them at the bottom.

Email

One last thing you’ll want to install here, even though it’s not a part of the traditional L(A|E)MP stack, is an email server. Again, Linode has a great send-only mail server tutorial. If you want to configure a mail server to actually receive email, that’s outside the scope of this post. In my case my server’s only interaction with mail is to send it — for example, when you need to reset your WordPress password.

WordPress

There are lots of ways to get WordPress installed. In my case, I had a few requirements that guided my choices:

  • I’m using WordPress multisite
  • I’m using the multisite domain mapping plugin
  • WordPress will manage my whole site
  • My site will be version controlled with git

After experimenting with lots of different options, I decided on this setup:

  • My public directory will just be a copy of my git repository
  • WordPress will be installed in my git repository as an svn export
  • Local development will use Mark Jaquith’s local config setup

At this point, you’ll want to install git on your server so that you can pull in your repository. Again, a one-liner will do it for you:

sudo apt-get install git-core

I setup my git repository and exported WordPress trunk, then setup my local-config.php per Mark’s instructions. Next I setup my .gitignore file to make sure I didn’t accidentally commit any of the local-specific data.

.DS_Store
/local-config.php
/.htaccess
/wp-content/uploads/
/wp-content/blogs.dir/
/wp-content/plugins/hello.php

I won’t walk through the WordPress multisite installation. If you need help with that, there’s a great Codex article that covers it. The only part specific to this tutorial is that you won’t want to use the .htaccess file (notice how I .gitignore‘d it?) because we aren’t using Apache. Instead, you’ll use a nginx config file to handle this. In my case, I put a file called .nginx-config into the root of my git repo and symlink it to nginx’s sites-enabled directory. You can grab my config file here — obviously you’ll want to replace domain.com with your actual domain. I have a couple other rewrite rules specific to my site, but this should cover the basics.

Again, that config goes into your git repo, which means nginx has no idea it exists yet. Once you’ve pulled your git repo onto your server, you can symlink it to the place nginx will look (/etc/nginx/sites-enabled). In my case my web sites are being served from /srv/www/domain.com/public, so that’s where my git repo will be pulled. This directory won’t exist by default, so you’ll need to create it as well as /srv/www/domain.com/log, which is where nginx will store your access and error logs. You can put your website content in another directory if you want, but you’ll need to change the nginx config file to make it work. Now you can symlink your config by running:

sudo ln -s /srv/www/domain.com/public/.nginx-conf /etc/nginx/sites-enabled/domain.com

This will take care of copying your rules to nginx, and it will also block nginx from serving that file publicly because it starts with a dot.

Restart nginx to make sure it uses your new virtual host.

sudo /etc/init.d/nginx restart

Batcache

Last, you’ll want to setup caching for WordPress. I’m using Batcache, which uses the WordPress object cache for all of its page caching. We use it on WordPress.com and it’s super-configurable, but I’m using it with the out-of-the-box settings for now. Batcache requires a persistent object cache backend, which Mark Jaquith’s APC plugin is perfect for on a one-server setup. If you’re running multiple servers you should use Ryan’s Memcached plugin (and you should also have stopped reading this a while ago). We already installed php5-apc (along with the rest of PHP) so there’s no server config needed here.

The Batcache installation is pretty straightforward. You will put Batcache’s batcache.php into /wp-content/mu-plugins (which you’ll probably need to create). Then you’ll put Batcache’s advanced-cache.php into /wp-content. Finally, you’ll put APC’s object-cache.php into /wp-content (the same place as advanced-cache.php). You’re almost there, you just need one line in your wp-config.php to tell WordPress to use the cache:

define( 'WP_CACHE', true );

Finale

That’s it. You should be good to go with a very fast and easy (relatively speaking) WordPress setup. There is some other house keeping you might want to do, like hardening WordPress, but I’ll skip that for now because there is plenty of good information about it on the Codex. You’ll also need to setup your DNS, both within Linode and in your domain registrar. This is no different than any other setup so I’ll skip that as well. Finally, you may want to configure other server-specific settings, like rotating logs. You should check out Linode’s tutorials on those.

For a bit of fun, you can run Apache’s benchmark test to see how many requests your server can (in theory) serve per second. First you’ll want to install Apache’s dev tools. Once you do that, from your server, we can throw a bunch of traffic at WordPress:

sudo apt-get install apache2-dev
ab -n 10000 -c 1000 -H 'Host: domain.com' http://127.0.0.1/

The output will include a “Requests per second” line, and in my experience you should be able to hit the mid-6000′s.

Edit: I really do want to clarify this is mostly for fun, and not a useful metric of how much traffic you’ll be able to handle. The one place this is actually useful is comparing your new server to an old server, purely on a relative basis. For example, my old site running Apache with mod_php came in around 200-300 requests per second. So I can get a sense of how much faster the new server is, but it does not mean I’ll be able to serve 500m page views per day from one VPS.

Again, I owe many thanks to Pete Mall and Mark Jaquith for helping me figure this out.

64 thoughts on “Faster WordPress: Multisite, nginx, and Batcache

  1. maryon mayor

    wait i got confused. i thought you only use linode? but in the post you refer to slicehost? or you just referred to it as an tutorial only but you only used linode. thanks…. anyway will try to do simulate this setup… nice post btw

    Reply
    1. evan Post author

      The Slicehost references are just for their tutorials, as you said. They have very good tutorials that are relevant for pretty much any Linux/VPS setup, including Linode. You could replicate this whole process on Slicehost if you wanted, but I did use Linode.

      Reply
  2. Pingback: Dreamhost to Linode - Web Hosting 201 | SSKTN.COM

  3. Nathaniel Schweinberg

    I’ve been doing research on a very similar build, and I’m curious why you chose Debian over Ubuntu? I know they are similar, but any apparent advantage of one over the other for this case?

    Reply
    1. evan Post author

      As you say, they’re very similar (Ubuntu is based on Debian). You could almost follow this exact method (except the dotdeb parts) on Ubuntu, so the differences are really minor. The biggest differences are in how each handles updates and security patches, but even in that regard they’re pretty similar. I think Debian comes with very slightly less configured by default (for example, *I think* Ubuntu has sudo installed out of the box).

      Honestly, if you’re more familiar with one than the other, that’s probably enough reason to use it. If you’re not familiar with either and you want to use this post as guidance, I guess going with Debian would be a little easier.

      Reply
  4. Scott Kingsley Clark

    I setup my VPS on Linode this past monday with the help of your tutorial. I’ll be using W3 Total Cache instead of BatCache for my needs though.

    Do you have any opinions on Varnish, would bringing that into the mix add any additional gains/benefits that you’re aware of?

    Reply
    1. evan Post author

      Cool, I hope it helped with the setup.

      I skipped Varnish for a couple reasons. I have a couple ideas I want to play with that require user-specific events on certain pages, and Varnish would be an annoyance to deal with. I also have other (non-WordPress) sites running on the same server that I don’t want to cache, and I didn’t want to juggle different servers on the same port for different sites. Finally, I didn’t really need it, so those reasons were enough for me to just skip it.

      It definitely has performance benefits though, so if it makes sense for you, you should check it out.

      Reply
      1. Scott Kingsley Clark

        Awesome, I’m going to install/config it since I’ve got some big sites I want to make sure are rock solid, and I don’t have any issues with running Varnish VPS-wide. Thanks again for the tutorial, I love coding but all this server stuff can get complicated quickly :)

        Reply
      2. Scott Kingsley Clark

        After a few weeks, I finally got around to finishing up the setup of my server and moving my sites over to it. I ended up having to switch my PHP-FPM implementation in Nginx slightly to accomodate Varnish.

        I also switched from APC to Memcached, and instead of using Batcache I used W3 Total Cache.

        My sites are lightning fast now, I’ve ditched my old hosting and am definitely not looking back!

        Reply
      3. evan Post author

        Scott, that’s awesome. Thanks for letting me know.

        Why did you end up going with Memcached? Are you using multiple servers? If not, APC would probably be faster for you.

        You should do a post on your nginx/Varnish setup.

        Reply
      4. WP Ho

        I also got interested in Varnish thanks to this article. But then I realized that Varnish is made mainly with 64-bit system in mind. 32-bit system is not recommended, according to this article (http://kristianlyng.wordpress.com/2010/01/26/varnish-best-practices/).

        Evan: BTW, I’m not sure whether you’re aware. I’m subscribed to follow-up comments for this post. But whenever I click on the link in the new comment notification email, it brings me to your homepage because the link in the email points to http://evansolomon.me/2012/04/01/faster-wordpress-multisite-nginx-batcache instead of http://evansolomon.me/notes/faster-wordpress-multisite-nginx-batcache/. You may want to look into this when you’ve time.

        Reply
  5. Pingback: I Have a Website | tollmanz.com

  6. Christopher

    How are you liking Linode now? It’s been on my todo list for a long time now to try them out and I just set one up last night, so far I really like it. Haven’t done performance testing yet, but feels quick.

    Going the same route you went with Nginx/FPM. I’ve always used Apache, so this is currently a test bed for switching to Nginx. This was an awesome well timed guide.

    I have a lot of sites I run spread across many VPS environments. I was considering running two linodes, one for a dedicated mySQL and another for nginx/fpm.

    Reply
  7. WP Ho

    Thanks for the excellent write-up. I’m using shared hosting now and is thinking of moving to VPS in the future, so this guide is a god-send.

    One Nginx noob question: You said you use MU Domain Mapping plugin. What changes do you have to make to Nginx’s config files to get MU domain mapping to work properly?

    Thanks for your time!

    Reply
    1. WP Ho

      Just like to add that the multisites I’m referring to are not just sub domains, but also different domain names like domain1.com domain2.com etc. Thanks.

      Reply
    2. evan Post author

      You don’t need any special rewrites or config to use the domain mapping plugin. If you check out my nginx virtual host config you’ll see: listen 80 default_server;

      That tells nginx to use these rules as a fallback, meaning that any site that doesn’t have its own virtual host file will use these rules. So domain mapped sites just run the same nginx config as all the others, and WordPress handles the request/blog matching internally.

      Reply
  8. john

    the only problem i am running into is when i’m install wordpress, i’m getting “Sorry, but I can’t write the wp-config.php file.”

    Reply
    1. evan Post author

      WordPress is running as a user that doesn’t have permission to write to that file. For security reasons, that’s a good thing. I’d recommend making the changes to your wp-config.php file elsewhere, saving them (hopefully to a version control repository), and then letting WordPress use the rules you setup.

      Reply
  9. john

    i was able to find a solution to what I was trying to do,

    in the domain conf file of the sites-available dir, instead of fastcgi_pass unix:/var/run/php5-fpm.sock;. I put, fastcgi_pass 127.0.0.1:9001;

    and in the /etc/php5/fpm/pool.d dir, i made a domain.conf defining it [domain]
    listen = 127.0.0.1:9001
    ; Unix user/group of processes
    user = yourusernamethatownsthedomaindir
    group = thegroupnamethatownsthedomaindir

    i hope that made sense.

    Reply
  10. Scott Kingsley Clark

    I went to go run a larger WP site and ran into a PHP memory issue. After digging and digging, I finally revealed overrides that had been placed in the /etc/php5/fpm/pool.d/www.conf file that override core settings in php.ini

    So I was actually changing them in php.ini and wasn’t seeing them change, which led me to finding it there. I removed those overrides and am just planning on using php.ini itself for the primary location of editing these.

    Just put this here in case it helped anyone else.

    Reply
  11. Julian Fernandes

    Hello Evan,

    First of all, excelent tutorial! It helped me to clear some doubts i had. But i have one question left and i would be happy if you could answer it :)

    Why use Batcache instead of W3 Total Cache? On my setup i have Nginx, PHP-FPM, APC, Varnish and W3 Total Cache for a single WordPress blog… i will setup a new WP site, on a new VPS, i i’m wondering… does Batcache gives more performance than W3 Total Cache?

    I believe W3 Total Cache would give me more performance, since page cache can be configured to run on disk, but i haven’t done any benchmark… mostly because i don’t wanna mess up with this WP setup, since it’s kinda big.

    Thanks in advance!

    Reply
    1. evan Post author

      I dislike the way W3 Total Cache works. I think it does far too much and is far too agressive in the way it does it. Upon activation, W3 Total Cache rewrites your wp-config.php file and some of the object cache files. And to make matters worse, deactivating it doesn’t undo those changes. So if you try to use W3 Total Cache without version control (which you shouldn’t do) you better have a backup if you ever want to uninstall it. In short, I don’t want to use all of W3 Total Cache’s features and I dislike its approach.

      I believe W3 Total Cache would give me more performance, since page cache can be configured to run on disk

      Batcache uses a persistent object cache for its page caching, which is stored in memory. Memory-based caching is always going to be faster than reading from disk, so this reasoning should be reversed. I assume W3 Total Cache can be setup to use a memory-based cache, but since I don’t use it I have no idea how to do it.

      In general I prefer plugins (or tools in general) that do a specific thing rather than a mix of things. The more features a plugin adds, the less likely it will be that I like every feature, and I want to minimize the code I’m running that I don’t use or like.

      Reply
      1. Julian Fernandes

        Thanks for the quick answer Evan :)

        I like W3 Total Cache because it have DB cache too, instead of just Page and Object cache. Does Batcache offer that too?

        Also, if i use a plugin like WP Minify, would Batcache cache the output file too?

        Reply
      2. evan Post author

        I like W3 Total Cache because it have DB cache too, instead of just Page and Object cache. Does Batcache offer that too?

        I don’t know what W3TC’s database cache is, or exactly what that means. MySQL has an internal cache, which as far as I know W3TC doesn’t change. It sounds like an object cache, and the plugin description only talks about database caching with regard to the object cache. If it does something different, could you expand on what that is?

        Also, if i use a plugin like WP Minify, would Batcache cache the output file too?

        Batcache will serve anything that WordPress gives it, including minified files. If you’re using WordPress to alter your JS or CSS, you should probably configure that to be cached by nginx because there’s no reason WordPress needs to be involved in that request once the data minified.

        Reply
      3. evan Post author

        To expand a bit on why I dislike W3 Total Cache, here is a short summary of my experience installing it.

        First, because I know what’s coming, I made a new branch in my git repository.

        Then I installed and activated W3 Total Cache. Let’s see what it did.

        Oh, that’s interesting. That’s not the worst part though, the worst part is that because I am running Batcache it’s already broken my site. Here’s what the page you’re reading this on would look like if I activated W3 Total Cache on it.

        Because of WordPress’ modular design, I’d hope to be able to fix this by deactivating the plugin. Not so much.

        That’s what my repository looks like after the plugin is deactivated. Notably (though really, the whole thing is notable), it’s actually changed one file that wasn’t changed before, wp-config.php. What change did it make, you ask. Good question, I was curious too.

        So after I deactivated W3 Total cache it decided to simply wipeout part of Batcache’s configuration. This sort of had the opportunity to be a good thing, because it had already broken Batcache to start with. Unfortunately they missed that parlay because they also edited wp-content/advanced-cache.php and destroyed the $batcache global, which means Batcache now throws a PHP notice because of an undefined variable.

        That sucks. And if I were less responsible about versioning my code, I’d have a hell of a time getting my site back to a working state. I know a lot of people who love W3 Total Cache and I believe it does a lot of good things, but this is just a design I am not interested in working with.

        Reply
      4. Julian Fernandes

        Hello Evan,

        I don’t know if W3 Total Cache offer some kind of different database caching to be honest.

        About the minify, right now i use W3 Total Cache to minify, compress and cache it. I believe all it does is set Nginx to do it then.

        Thanks for clearing my doubts :)
        I also read this: https://sivel.net/2011/12/wordpress-caching-comparisons-part-2/
        Seems i will give Batcache a try instead of W3 Total Cache for this next project. I can always benchmark it anyway :)

        Reply
    1. evan Post author

      Yup. The listen line in my nginx virtual host config tells nginx to direct all requests here (via the default_server setting) unless the request matches a specific server name in another config. DNS just directs the request to my site, which nginx grabs here for arbitrary domains and sends to WordPress. WordPress is where the actual logic of which site has which content lives.

      Reply
  12. Urko Masse

    I’m having problems using the APC object cache. Our multisite installation uses subdirectories, and not subdomains.
    As soon as I put the object-cache.php file in there, things start acting up. It looks like the key for the cached objects is not unique for each of our users’ blogs.
    Has anyone had this problem? I tried to tweak the key() function to include the blog_id during generation of the keys, but it didn’t help.

    Reply
    1. Mark Jaquith

      Hey, I’m the author of the APC object cache. It would be very strange for keys to not be unique per blog. It uses the blog_id to prefix keys. See line 338 in version 2.0.4. Could you send me any additional information you have? mark at wordpress dot org.

      Reply
      1. Urko Masse

        Never mind, I found the problem…
        The previous system administrator had commented out two of the Multisite config lines in wp-config.php: PATH_CURRENT_SITE, BLOG_ID_CURRENT_SITE…

        I guess the miracle is how the system had been running all this time…

        Reply
  13. Teodor Boev

    Thanks for the great article, everything works as described…. is there any way to see if the page has been cached? In advanced-cache.php there is variable $debug that supposed to print something in the header but it doesn’t work for me, any ideas? Or am I doing something wrong :)

    Reply
    1. evan Post author

      By default $debug will insert an HTML comment into the cached page. It looks something like this.

      <!--
      	generated 3410 seconds ago
      	generated in 0.232 seconds
      	served from batcache in 0.000 seconds
      	expires in 190 seconds
      -->

      If you don’t see that, the page is not being served from Batcache. There are two likely reasons. One, Batcache isn’t working. Two, you’re logged in, which by default means you won’t get a Batcached page. There is a third possible reason, which is that the threshold for serving a page from Batcache (which I think is 4 requests in less than 60 seconds by default) hasn’t been hit, in which case you’ll just get the regular page even when Batcache is working fine.

      An easy way to test is to visit your site logged out and refresh it a bunch of times in a row, then check the page source for that comment.

      Reply
  14. Pingback: Best of Twitter 2012-11-16 | Codex Atlanticus

  15. Brian

    @evan – wanted to take a minute to thank you for this article. I learned more in the comments, actually and appreciate your back-and-forth with @Julian. I’ve been tinkering with Multi-site and have (ironically) only installed W3 Total Cache on live servers (smaller projects mind you, not the scale of the multisite I’m working on now). I had no idea the extent of the core changes or that they were not reversed via deletion, I’m with you all the way and I’ll probably use batcache / APC / minification rather than letting W3 Total Cache hijack my filesystem ;-)

    Opinion question: any thoughts on best practice re: dev -> prod for a larger scaled multisite? You think doing a LEMP setup like this as a virtualbox VM is the best way to be prepared for production concerns in local sandboxing?

    Reply
    1. evan Post author

      Brian, thanks for the kind words. I like Virtual Box for testing the “real” environment. You could setup a remote staging server, but that obviously costs a bit of money.

      For deployment, I’m a fan of Mark Jaquith’s WP Stack project. I also wrote a command line tool called Scatter that provides some helper functionality for deployment. I’d recommend checking out those projects, and feel free to let me know if you have any questions.

      Reply
      1. Brian

        Ah! I think you’re my new best friend. This is just what I was looking for… I know enough about automation to know that we’re trying to make machines do things so humans don’t have to – I figured someone must have done this but this is my first sighting of these tools. I think my only other question (I’ve come up with my own answers from research, but feeling like I’m talking to someone who *really* knows right now) is how these might integrate with http://wp-cli.org/ in a typical deployment routine? I guess there’s no standard for that just because every organization’s policy re: deployment / versioning / backup / updates is going to be different…

        Reply
        1. evan Post author

          Great, I’ve been looking for a new best friend.

          I don’t know of anyone using WP-CLI in deployment, but that doesn’t mean it couldn’t be done. I’d imagine you’d want to have it running on the remote server and have some kind of post-deploy action (using Scatter, Capistrano, etc) that manipulates whatever you need. As you said, it might end up being be highly specific to each use case, but that doesn’t make it a bad idea.

          I’ll see if the guys involved in the WP-CLI project have anything else to add.

          Reply
          1. Mike Schroder

            Yeah, there isn’t anything standardized at the moment (that I know of) beyond what’s already within WP-CLI to make deployments easier.

            I’d imagine that whatever is standard practice (or could be considered such) and consists of more than one WP-CLI command would be considered for core WP-CLI itself.

            The rest (how you call WP-CLI) is likely to be very dependent on your environment.

            That said, as noted above, if you do find you’re performing significant steps within WP-CLI that you’d consider to be standard practice, or gaps in what you think it should be able to do, feel free to sound off in a ticket or pull request on the WP-CLI project, so we can reduce steps for everyone!

            http://github.com/wp-cli/wp-cli/

            Reply
          2. Brian

            Thanks to you both @Evan and @Mike! Any thoughts on how the new option of having wp core live in it’s own directory as of WP 3.5 will impact any of this? I’m sure I can figure it all out, but just throwing that out there since I’ll be waiting for the 3.5 release before pushing my project to production, given that there’s significant benefit from being able to correctly structure the filesystem for an optimal versioning schema (thanks to the WP team for this update to multisite, I came in at just the right time! :)

            Reply
            1. evan Post author

              I think the only impact on deploys is that you can install WordPress as a Git submodule or SVN external, instead of versioning it as a part of your project. It will also require some updates to your rewrite rules. If you’re using Apache WordPress will give them to you, if you’re using nginx you’re on your own (for now). Also, just to clarify, it’s not a new feature to be able to put WordPress in its own subdirectory, just Multisite (single site already worked fine).

              On a personal note, I worked on the Multisite-in-a-subdirectory patch with Mark Jaquith and a few others, so I’m happy to hear you’re excited for it.

              Reply
              1. Brian

                Yeah, should have said “the new option of having WP *multisite* live in it’s own directory… I’ve been handling singular instances via separate subdir’s for years. I’m definitely planning to run LEMP with the new subdir schema so I’m super stoked. If you get around to figuring out the correct NGNIX rewrites for that setup, just let me know here, if I get to it first, I’ll do the same :-)

  16. Chris

    Wow! This has been my goto resource for setting up nginx for a while. Thanks so much for writing this. Everything was well documented and not vague and I’ve successfully set up nginx.

    Do you think you will make a similar tutorial on setting up Mark Jaquith’s wp-skeleton/wp-stack with Capistrano, the process of setting up vagrant with puppet, and tying it all back your workflow when pushing to your server? I’ve looked high and low for something similar to this article, but there doesn’t seem to be one when it comes to putting it all together nor in terms of clarity. Thanks again.

    Reply
    1. evan Post author

      I use Capistrano to deploy this site (I didn’t at the time I wrote the post) so I’d like to write an update to include that and a few other changes I’ve made since then. I don’t currently use WP Stack because I haven’t updated the site to use WordPress multisite’s new-ish subdirectory features, which is somewhat ironic since I worked on #19796. If I do that, I’ll probably do it with WP Stack, but I’m not sure when I’ll get around to it since it’s not a super high priority for me (doesn’t mean it won’t happen, just that I can’t commit to when).

      I haven’t automated this setup in Puppet or Chef — though I’d like to — so I don’t have a Vagrant config for it either. All of that sounds like fun, just haven’t spent the time to do it yet.

      Reply
      1. Chris

        Yeah. It is fun, but time consuming. I’ve been in the process of learning all this the past few months with nginx. I’m 90% there with capistrano and can see the end in sight ^^

        Reply
  17. Pingback: Wordpress Multisite, Multiserver, W3 Total Cache, Nginx configuration |

  18. Pingback: Nginx + Wordpress Multisite 3.4.2 + subdirectories + static pages and permalinks | Life with Linux

  19. Pingback: nginx + php-fpm cycle redirection error on linode new vps | Life with Linux

  20. Pingback: Moving WordPress sites from Dreamhost to Linode | Nicholas Muldoon

  21. Jack

    Hi Evan

    Really appreciate this post, helped me a lot today. I have spent my professional life working with Windows and am just starting to venture out and learn more on the Linux side of things. Today I migrated my blog onto a Digital Ocean VPS with nginx/php-fpm stack and batcache. I have to say Digital Ocean really are great I love the ability to instantly create snapshots along the way, helps for when I made a mistake and wanted to jump back 30 minutes in time. After reading through the comments I’m now worried that there may still be parts of w3tc lurking somewhere, I’ll have to take a look tomorrow. Anyhow I have run a blitz test on my new setup and am more than happy with the results :)

    https://www.blitz.io/report/6466cf6729c8f636cb8e1af92c6aa05b

    Reply
  22. Pingback: Faster WordPress: Multisite, nginx, and Batcache | Evan Solomon (Linktipp) | BheimseinBlog

Leave a Reply