I've been playing around with the Rackspace Cloud hosting offerings, and as of right now I've got this very blog running load balanced on a set of servers. And while it's a little more complicated than just setting up a single server, it really isn't that hard. In fact, I'll walk you through the process.
So why exactly would you need a load balanced website? Well, a single server can only handle so many connections. After a certain point it just can't handle any more users, and the website starts to slow down or even become unreachable. A load balancer is a device that can spread those visitors over a bunch of different servers, allowing the "load" of those visitors and their requests to be "balanced" over a number of different devices. Especially with the Rackspace Cloud, creating more servers to handle increased load is remarkably simple. Even if you don't have that much traffic to worry about, in the event that your server crashes a load balancer will let you spin up new servers and immediately start sending traffic their way instead of having to wait for the DNS records to update (which could take 24 hours to 48 hours).
Simple analogy: a single server is like a single twig and will easily break, but a load balancer allows you to tie a whole bunch of twigs together to make a stronger solution.
Before we get started, here’s a quick overview of the steps we’re going to take:
1. Spin up and configure a complete WordPress server.
2. Duplicate the WordPress server and set up as SQL server.
3. Force WordPress server to use remote SQL server.
4. Configure cloud storage solution for images and uploaded files.
5. Configure Load Balancer and DNS records.
OK, here we go!
1. Spin up and configure a complete WordPress server
The easiest way to configure the load balanced system is to start with a complete and functioning server with everything running just the way you like it, and then slice it up from there. So the first step is to spin up a new server. Windows, Linux, whatever — it doesn’t really matter. But for the purposes of this walk-through we’re going to be using Fedora Linux 16. Rackspace already has a great article about how to set up a cloud server instance, so I’m not going to go over that again.
Once you have your server set up you need to have the following things running:
- Webserver (IIS / Apache)
- SQL Server (Microsoft SQL / MySQL)
Personally, I'm an Apache/MySQL/PHP kind of guy as they're much easier to configure for me, but pick your own poison. Again, Rackspace has some good articles on how to do it or you can scour Google. I also like to slap PHPMyAdmin on there because it makes administrating MySQL a whole lot easier.
At this point you should have everything squared away on your server — MySQL up and running, WordPress installed and properly configured, firewall allowing HTTP access and the operating system fully updated. If you have a domain name for the WordPress site you should point it to the server now and make sure everything is working using the domain instead of the IPs — this will save you some trouble down the road. Go ahead and take a quick image of this server (another Rackspace article there) so that if everything goes sideways you still have something to work with.
2. Duplicate the WordPress server and set up as SQL server
Now we need to slice out the MySQL server and set it running on a standalone system.
"Wait, WHAT?!" I hear you cry, and there's a good reason for it. Putting the SQL server on a different system makes the traffic susceptible to sniffing and requires you to open up the SQL port in the firewall, but it needs to be done. But first, the reason it needs to be done.
WordPress uses the SQL database to store just about everything, including the text of your posts and the comments. When you have a single server it makes sense to have the SQL server on the same box, but when you have multiple servers running the same website the only way to have them all running and showing the exact same content simultaneously is to have a single central SQL server with the "master" copy of the database. You'll still need to replicate the uploaded files (pictures and so forth) across the different web servers, though.
So, now that everything is running you will need to spin up a new server to act as the central SQL server. Take an image of the running server that you have and spin up a new one from that image (see article here).
Now that you have an identical server running we need to slice some things out to slim it down and improve performance, as well as allow other servers to use it.
1. Set the permissions on the MySQL Database for your WordPress installation to allow connections from anywhere and not just the local system. This is best accomplished using the "Permissions" tab in PHPMyAdmin.
2. Disable Apache on the system. Don’t uninstall it (as you’ll need it for the PHPMyAdmin system), simply disable it. Use this command: sudo service httpd stop
We also need to open the firewall to allow MySQL connections (port 3306). This traffic should never leave the Rackspace network, but since it is still technically a public connection you should still pick a good username / password combination to protect the server. Open the iptables config file in a text editor (sudo vi /etc/sysconfig/iptables) and pop the following line at the top of the config:
- -A INPUT -p tcp –dport mysql -j ACCEPT
Save the file and reboot the server for good measure.
3. Force WordPress server to use remote SQL server
You now have one working COMPLETE server, and one working SQL-only server. The next step is to tie the two together.
WordPress uses a file called "wp-config.php" to keep track of the MySQL connection information. The file is stored in the root directory of the WordPress installation. Since we created the SQL server based off the existing running complete server, we can assume that the username and password combination in this file is correct and the rest of the database is compatible. The only thing we need to change is the address of the server.
When we're picking the IP address we want to connect to, we have a choice. We can either use the public IP of the server (listed on the Rackspace Cloud control panel page for the server) or we can find the private IP of the server and use that instead. The private IP address will force the connection to route over Rackspace's internal network instead of going over the public Internet and so makes the connection less likely to be sniffed (especially if the servers are in the same datacenter). You can find the private IP address of the SQL server by SSHing into the computer and running "ifconfig." The private IP will usually be a 10.x.x.x address on eth1.
Here’s the corrected line you need to update in wp-config.php using either the public or private IP:
- define(‘DB_HOST’, ’10.179.98.192′);
Where 10.179.98.192 is the IP address of your SQL server. If you have a DNS record for the SQL server you can slap that in there instead and pop some single quotes around it. Like so:
- define(‘DB_HOST’, ‘sql20.notaserver.net’);
There are a couple errors that could arise once you make the change to the WordPress configuration, and thanks to my own idiotic stumblings I've experienced most of them. Thankfully I also have a solution. So, if you get the following errors on your WordPress site when trying to load it after making the switch, this is what's going on:
- Unable to establish a connection… : The WordPress installation is trying to connect to the newly designated MySQL server, but can’t get it to work. This specific error is indicative of the network connection itself being unable to make it between the servers. Ensure that the IP address or domain name of the server that you specified in the wp-config.php file is correct and responding to pings from the web server itself. Also ensure that the firewall on the SQL server is allowing the traffic.
- HTTP 500 Error: Also known as the “internal server error,” this indicates that the connection to the SQL server is up and working, but something else is amiss. Make sure that the account (username and password combination) you’re using in the wp-config.php file is granted the right permissions on the SQL server for the database for the WordPress tables, and also that the account is allowed to be accessed from any IP address and not just the local host.
- The site isn’t the latest version: If you spun up the SQL server instance using an older image of your single complete server (for example, if you’ve published new stuff since then) you might not have all of the articles in the SQL server’s database. You can either type them in on the new system or spin up and configure a new SQL server from an image of the current server being sure to tell your writers to hold their horses for a bit.
At this point you should be looking at one server running Apache and PHP with the WordPress files on it, and one server with MySQL and the WordPress content on it, and they should be working together to serve the website.
4. Configure cloud storage solution for images and uploaded files
The next issue is with the images and other files associated with your WordPress site. In a normal configuration all of the media files are stored on the webserver itself, but because we now have multiple webservers running it’s very hard to duplicate the files across both servers efficiently. Thankfully Rackspace’s Cloud Files solution offers a great alternative storage method for all the images you want to post on your blog, and a WordPress plugin is available to do all of the hard work for you. CDN Tools is a third party plugin that will automatically upload all of your files to the Rackspace Cloud Files service and do the magic to make them appear in your posts. An added benefit is that because the images are being served from a content delivery network — instead of the server itself — it reduces the load on your webservers and makes the site load faster.
5. Configure Load Balancer and DNS records
Now we just need to set up the load balancer.
Think of your server configuration as a straight line. On one end you have the Internet, where your readers will come from to visit the site. The first thing they should hit on their way into your network is the load balancer, which will direct their traffic to the appropriate server based on some parameters we'll set up. Next in line are the web servers, the dumb systems that simply serve static HTML or PHP pages and respond on port 80. Those systems talk to the "brains" of the operation, which is last in line, the SQL server that listens on port 3306. The SQL server sends the webservers whatever content the reader wants to see; the webservers spice it up and make a presentable web page based on the WordPress files; and the load balancer remembers where the traffic came from and sends it right back to them. Now that we have the infrastructure spun up to handle a load balancer, we need to spin up the load balancer itself.
Rackspace has a great article on how to spin up a load balancer, and you should follow it to configure the LB. Set the webserver we’ve spun up (the one with Apache still running) as the only node behind the LB for now.
With the load balancer up and running you now have a complete solution. Using the public IP address of the load balancer you can change your DNS records to point your various domains to that LB. Remember to setup Apache with a virtual server in the configuration files of the SERVERS (nodes) for each domain name you want to point towards your load balancer, as the LB will blindly pass the traffic along without altering it and allow you to run as many sites off that one configuration as your heart desires.
At this point you should take an image of the webserver (the node) that is running behind the load balancer. If you see your server starting to slow down, all you have to do is spin up a new instance of that server and designate it as a node in the load balancer's configuration. Traffic should be balanced between the servers automatically and your site will remain up and responding.
And that's how you set up WordPress in a load balanced environment with Rackspace Cloud. Well, at least that's how I did it. And I think I did a damn fine job.