How to Set Up a Load Balanced and Redundant LAMP Web Application on GoGrid

From GoGrid



Contents

Overview

This how-to document is a step-by-step guide to setting up an HA (Highly Available) LAMP (Linux/Apache/MySQL/PHP) environment within GoGrid. The setup consists of a load-balanced web front end with content being stored on Cloud Storage. The backend database configuration employs MySQL Master-Master replication. Failover for both the web front end and the database backend are seamless. In addition to providing additional resources to handle higher loads, the web site(s) being run on this configuration will stay online even when one web server and/or one database server(s) go offline.


The example architecture used in this document can be applied to any Linux environment available on GoGrid. The resources used in this how-to consist of the following:

  • 2+ web/app servers using CentOS 5.1 64-bit with LAMP software
  • 2 database serverw using CentOS 5.1 64-bit with MySQL 5.0
  • GoGrid's Cloud Storage service
  • GoGrid's (F5) Load Balancer service


This setup will allow you to easy manage a high availability PHP/MySQL application such as Drupal, PHPBB, osCommerce, Wordpress, Joomla, Mambo, ZenCart, or your own application. The same general principals can be applied to Windows environment that run on ASP.NET, however the setup will certainly vary.

NOTE: Security topics are not covered here. For example, securing your servers by running SSH on a non-standard port and restricting SSH root login are some best practices which are highly recommended. Since we won’t be specifying a MySQL bind-address, it is especially important to restrict access to MySQL with iptables or to remove the public IPs from the database servers and to set a strong MySQL root password. However, these things are outside of the scope of this document.


The above infrastructure will allow you to host all of your web files on Cloud Storage with your web/app servers simply acting as TCP/IP processors for hosting your site. The database server will act as your private database with no public connection to the outside world while the F5 load balancer will balance the traffic among your public web/app servers. To scale your infrastructure, simply add more web/app servers and follow the same configuration guidelines mentioned below.


This setup is secure, redundant and maximizes the resources available to your GoGrid cloud.


NOTE: This document assumes that you have general Linux systems administration skills. It does not cover everything surrounding basic system configuration and is meant as a general guideline to follow. It is geared towards Wordpress specifically but could easily be adapted for other LAMP web applications as listed above. All the information in this document is provided as-is. GoGrid does not offer support for implementing these instructions nor does it support troubleshooting issues arising from the operation or configuration of this setup.

Getting Started

Overview

In this scenario, we will be using the following objects in our GoGrid cloud. Instructions for instantiating each of the objects are below. You may wish to use different configurations in your own environment.

Servers

Name Type RAM Operating System Image Public IP Private IP
web01 Web Server 1GB CentOS 5.1 (64-bit) LAMP 208.1.1.3 10.1.1.3
web02 Web Server 1GB CentOS 5.1 (64-bit) LAMP 208.1.1.4 10.1.1.4
db01 Database Server 2GB CentOS 5.1 (64-bit) MySQL 5.0 208.1.1.11 10.1.1.11
db02 Database Server 2GB CentOS 5.1 (64-bit) MySQL 5.0 208.1.1.12 10.1.1.12


The amount of RAM used for these servers only an example and is not a suggestion as to how much may be required for your particular setup. It is important to deploy servers with enough RAM so that swap utilization can be avoided as much as possible.


Load Balancers

Name Load Balancer Type Load Balancer Persistence Virtual IP/Port Pair Real IP/Port Pairs
LB01 Round Robin Source Address 208.1.1.2:80 208.1.1.3:80
208.1.1.4:80


Database IP Failover

Hearbeat Floating IP
IP used by web servers to access database servers 10.1.1.10


Certain information used through this document such as the IP addresses, domain names, passwords, etc., will be different than what you will use. Such items are emphasized in red and should be replaced with your own. Make sure you do so consistently.

Web/App Servers

The first thing to setup is our first web server. Simply do the following:

  1. Log into your GoGrid account at My.GoGrid.com.
  2. Click on the "Add" button from the Grid menu
  3. Select "web/app server" to deploy from the add menu.
  4. Select the type of Operating System you want along with the amount of RAM and the Server Image. For this environment, you will want to setup a (CentOS 5.1) LAMP server. For these simple web servers ,you may want to choose 1GB of RAM.
  5. Enter an IP Address from your list of available IP's at the left of your screen. The system will automatically display all unused IP addresses that are currently available to you. In this scenario, we will use 208.1.1.3 as the IP address of the first web server.
  6. Name your server and add a description. In this scenario, we will use web01.
  7. Click on the "Save" button
  8. Your server will be deployed within 2-15 minutes.
  9. To obtain your server’s password, go to the “Support” tab and click on “Passwords” or right-click on the server in the UI and click on "Password". Changing the password here will not change your server password; this interface is only used for you to store passwords and to allow our Support teams access to your passwords to provide technical support, when needed.


Do this again for an additional web server. In this example, the second server's name will be web02 with an IP of 208.1.1.4.

Database Servers

Now that you have a web/app server, you need a database server. To add a database server, do the following:

  1. Log into your GoGrid account at My.GoGrid.com.
  2. Click on the "Add" button from the Grid menu
  3. Select "database server" to deploy from the add menu.
  4. Select the type of Operating System you want along with the amount of RAM and the Server Image. For this environment, you will want to setup a (CentOS 5.1) MySQL 5.0 server. For your db server, it is best to choose at least 2GB of RAM.
  5. Enter an IP Address from your list of available IP's at the left of your screen. The system will automatically display all unused IP addresses that are currently available to you. In this scenario, we will use 208.1.1.11 as the IP address of the first database server.
  6. Name your server and add a description. In this scenario, we will use db01.
  7. Click on the "Save" button.
  8. Your server will be deployed within 2-15 minutes.
  9. To obtain your server’s password, go to the “Support” tab and click on “Passwords” or right-click on the server in the UI and click on "Password". Changing the password here will not change your server password; this interface is only used for you to store passwords and to allow our Support teams access to your passwords to provide technical support, when needed.


Do this again for an additional database server. In this example, the second server's name will be db02 with an IP of 208.1.1.12.

Cloud Storage

Next, you need to add Cloud Storage and set up the routes to each server:

  1. Click on the "+" button on the Grid tab.
  2. Select the "Cloud Storage" option and icon. This will allow you to utilize more than 10GB of Cloud Storage
  3. Each GB of data over the initial 10GB quota will be charged for at a rate of $0.15 per GB.


To set up the connections from your web/app and database servers to Cloud Storage, follow the instructions on the Cloud Storage getting started guide.

F5 Load Balancers

Lastly, you can set up the F5 Load Balancer. Do this once you have set up ALL of your web/app and database servers.

  1. Click on the "add" button from the Grid menu
  2. Select "Load Balancer"
  3. The "Add Load Balancer" window will open
  4. Provide a name and description for the Load Balancer (you can have multiple instances of Load Balancers, all for different purposes)
  5. Add a "Virtual IP" from the list of available IP's at the left of screen. The system will automatically suggest the next available VIP from your IP block for you. In this scenario, we will use set the virtual IP to 208.1.1.2.
  6. Add a "Virtual Port" number for the port you wish to balance. In this example, the port will be set to port 80.
  7. Add "Real IP's" and "Real Ports" to the pool. These are the IP addresses and corresponding ports you wish to Load Balance. The system will automatically suggest the IP addresses you currently have deployed on the grid. For this example, we will add the IP addresses 208.1.1.3 and 208.1.1.4.
  8. You can add additional IP's and ports to the pool by clicking on the "+" button or by tabbing down a line if necessary.
  9. Select the type and persistence for the Load Balancing Algorithm. In this example, we will use Round Robin load balancing with Source Address persistence.
  10. Click "Save" and your Load Balancer should be completely deployed within a few minutes.

Configuring Your Servers

The following configuration should be done on all of your servers.

  1. To begin, enter the following command to edit your network interface configurations:
     vi /etc/sysconfig/network-scripts/ifcfg-eth1

    The entire file should read as below, but change IPADDR=10.1.1.3 to match the IP of the host you are editing. In this example it is for web01. Do this on each server, changing the IP as appropriate.

    DEVICE=eth1
    BOOTPROTO=static
    ONBOOT=yes
    IPADDR=10.1.1.3
    NETMASK=255.255.255.0
    
  2. Set the hostname on all of your servers with the following command:

     vi /etc/sysconfig/network

    The entire file should read as below, but change HOSTNAME=web01.localdomain.com for hostname of the host you are editing. In this example it is for web01. Do this on each server, changing the HOSTNAME as appropriate.

    NETWORKING=yes
    NETWORKING_IPV6=no
    HOSTNAME=web01.localdomain.com
    
  3. Set up your hosts files on each server.
     vi /etc/hosts

    The /etc/hosts file must contain all the cluster nodes hostnames. These names should be identical to the result of uname -n command. The entire file should read as below, but change 127.0.0.1 localhost.localdomain web01 localhost on the first line only (for localhost) to match whatever host you are editing. The remaining lines should be edited to reflect the IP addresses and hostnames of the other servers in your environment.

    127.0.0.1	localhost.localdomain	web01	localhost
    10.1.1.3	web01.localdomain.com 	web01
    10.1.1.4	web02.localdomain.com 	web02
    10.1.1.11	db01.localdomain.com 	db01
    10.1.1.12	db01.localdomain.com	db02
    
  4. Now create a route to access GoGrid's Cloud Storage for each machine. You can easily do this with the following commands:
    echo “any net 10.117.0.0/24 gw 10.1.1.1” >> /etc/sysconfig/static-routes
    
    mkdir /mnt/cloudstorage
    
    vi /etc/fstab
    

    Append the following to the bottom of the fstab file, all on one line. Be sure to replace all occurrences of 12345 with your actual customer number (first part of your Cloud Storage hostname) and the your_cloud_storage_password with your Cloud Storage password which can be found on my.gogrid.com.

    //12345.cloud.storage.gogrid.com/12345 /mnt/cloudstorage cifs file_mode=0660,dir_mode=0770,uid=apache,gid=apache,userid=12345,password=your_cloud_storage_password
    
  5. Now append the following lines to the bottom of the rc.local file:
    vi /etc/rc.local  
    

    So that it looks like this:

    mount /mnt/cloudstorage
    umount /mnt/cloudstorage
    echo 0 > /proc/fs/cifs/LinuxExtensionsEnabled
    mount /mnt/cloudstorage
    
  6. Lastly, you want to ensure all of your servers are up to date. When this has completed, you can reboot them:
    yum -y update


    reboot

Configuring your Web Servers

To configure your web servers, do the items listed below. Remember that this tutorial is geared towards Wordpress, but you can do this with any PHP-MySQL applation for Linux.

  1. Ensure that php-mysql is installed on each web server:
    yum -y install php-mysql
  2. Now install Wordpress. You only have to do this from one web server and it doesn't matter which one you choose as the wordpress source files will actually be installed on your Cloud Storage allotment. Replace wordpress-2.7.1.tar.gz with the filename of whatever version you downloaded if it differs.
    cd /mnt/cloudstorage
    wget http://www.wordpress.org/latest.tar.gz
    tar zxvf wordpress-2.7.1.tar.gz
    mv wordpress myblog_wordpress
    cd myblog_wordpress
    mv wp-config-sample.php wp-config.php
    vi wp-config.php 
    
  3. Now locate the following lines in the conf file edit them as shown below, replacing myblog_wordpress with the name you will assign to your database at a later step, wpadmin with the name you will assign to your database user at a later step, abcd1234 with the password you will assign to your database user at a later step, and 10.1.1.10 with the IP address you will assign to your heartbeat at a later step.
    define('DB_NAME', 'myblog_wordpress');
    define('DB_USER', 'wpadmin');
    define('DB_PASSWORD', 'abcd1234');
    define('DB_HOST', '10.1.1.10');
    
  4. Now configure Apache on each web server. To start, edit the Apache conf file:
    vi /etc/httpd/conf/httpd.conf

    Locate the following lines and remove the # comment so that they look like below:

    EnableMMAP off
    EnableSendfile off
    
  5. Now your vhosts need to be configured so that you can run multiple websites on these servers if you ever need to:
    vi /etc/httpd/conf.d/vhosts.conf

    The entire file should read as below, but change the IP address to match the web server you are editing, in this example it is for web01. Do this on each web server, changing the IP as appropriate. Be sure to change 208.1.1.3 with the appropriate IP address of the machine, yourdomain.com with the appropriate domain name, yourname@youremail.com with your actual email address, and myblog_wordpress with the actual document root of your web server asset up above.

    NameVirtualhost 208.1.1.3:80 
    <VirtualHost 208.1.1.3:80>     
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com     
        ServerAdmin yourname@youremail.com     
        DocumentRoot "/var/www/myblog_wordpress"     
        AccessFileName .htaccess     
        php_admin_flag safe_mode off     
        php_value register_globals "1"     
        php_value upload_max_filesize 8M     
        <Directory "/var/www/myblog_wordpress">       
          Options Indexes FollowSymLinks       
          AllowOverride All       
          Order allow,deny       
          Allow from all     
        </Directory>
    </VirtualHost>
    
  6. On each web server, create a symbolic link to Cloud Storage from the Apache document root with the following command, replacing myblog_wordpress with your actual document root.:
    ln -s /mnt/cloudstorage/myblog_wordpress /var/www/myblog_wordpress
  7. Restart Apache on each web server for the changes to take effect:
    service httpd restart

Configuring Your Database Servers

  1. Install heartbeat on both of your db servers. When installing heartbeat, you have to issue the command twice to get it fully installed. Do this on both DB servers:
    yum -y install heartbeat  
    yum -y install heartbeat
    chkconfig heartbeat on
    
  2. Create a heartbeat ha.cf configuration file on each DB server:
    vi /etc/ha.d/ha.cf
  3. Below are the complete contents of ha.cf for db01. This file will be identical on both DB servers except for the line that begins with ucast which should specify the private IP for the other DB server, and the node values with the actual uname -a output from each database server:
    #	File to write debug messages to
    debugfile /var/log/ha-debug
    # 	File to write other messages to
    logfile	/var/log/ha-log
    #	Facility to use for syslog()/logger 
    logfacility	local0
    #logfacility	daemon
    #	keepalive: how long between heartbeats?
    keepalive 2
    #	deadtime: how long-to-declare-host-dead?
    deadtime 5
    #	warntime: how long before issuing "late heartbeat" warning?
    #	See the FAQ for how to use warntime to tune deadtime.
    warntime 3
    #	Very first dead time (initdead)
    initdead 10
    #	What UDP port to use for bcast/ucast communication?
    udpport	694
    #	What interfaces to broadcast heartbeats over?
    #bcast eth1
    ucast eth1 10.1.1.12 #specify a different system if using ucast (unicast)
    auto_failback on
    #	Tell what machines are in the cluster
    #	node	nodename ...	-- must match uname -n
    node	db01.localdomain.com db02.localdomain.com
    #	Less common options...
    #	Treats ip as a psuedo-cluster-member
    #	Used together with ipfail below...
    #	note: don't use a cluster node as ping node	
    #ping 10.10.10.1 # This assumes the network mentioned above is 10.10.10.0/24
    #	Processes started and stopped with heartbeat.  Restarted unless
    #		they exit with rc=100
    #respawn userid /path/name/to/run
    #respawn hacluster /usr/lib/heartbeat/ipfail # 32-bit OS
    respawn hacluster /usr/lib64/heartbeat/ipfail # 64-bit OS
    #	Do we use logging daemon?
    #	If logging daemon is used, logfile/debugfile/logfacility in this file
    #	are not meaningful any longer. You should check the config file for logging
    #	daemon (the default is /etc/logd.cf)
    #	more information can be found in 
    #	http://www.linux-ha.org/ha_2ecf_2fUseLogdDirective
    #	Setting use_logd to "yes" is recommended
    use_logd yes
    
  4. Now you will need to create heartbeat authentication keys on each DB server by entering the authkeys file:
    vi /etc/ha.d/authkeys
  5. This file needs to be exactly the same on both DB servers and should contain the following two lines:
    auth 2
    2 sha1 insert_your_password_here
    

    where insert_your_password_here is replaced with your real password.

  6. Set permissions as follows on the file that was just created:
    chmod 600 /etc/ha.d/authkeys
  7. Create a heartbeat haresources file on each DB server:
    vi /etc/ha.d/haresources 

    This file also needs to be exactly the same on both DB servers and should contain the following single line where db01.localdomain.com is replaced with your actual hostname and 10.1.1.10 is replaced with your hearbeat IP:

    db01.localdomain.com IPaddr::10.1.1.10
  8. Start heartbeat on both DB servers with the following command:
    service heartbeat start

    Check the output of the ifconfig command and look for the floating IP to appear under eth1:0

MySQL Master-Master Replication

  1. Now we will set up MySQL with master-master replication. First, set the MySQL root user password on both machines where YOUR_PASSWORD_HERE is replaced with your MySQL root password:
     mysqladmin -u root password YOUR_PASSWORD_HERE
  2. Create a user replication and grant it privileges on the database. Replace 10.1.1. with the first three octets of your private IP range:
    mysql -u root –p
    mysql> GRANT REPLICATION SLAVE ON *.* TO ‘replicaton’@’10.1.1.%’ IDENTIFIED BY ‘slave’;
    mysql> GRANT REPLICATION CLIENT ON *.* TO ‘replication’@’10.1.1.%’;
    mysql> GRANT SUPER ON *.* TO ‘replication’@’10.1.1.%’;
    mysql> GRANT RELOAD ON *.* TO ‘replication’@’10.1.1.%’;
    
  3. Create the Wordpress database and create a db user and password to access the db other than root, replacing myblog_wordpress, wpadmin,abcd1234 and 10.1.1. with the appropriate values you previously set:
    mysql> CREATE DATABASE myblog_wordpress;
    mysql> USE myblog_wordpress;
    mysql> GRANT ALL ON myblog_wordpress.* TO wpadmin@’10.1.1.%’ IDENTIFIED BY ‘abcd1234’;
    mysql> GRANT ALL ON myblog_wordpress.* TO wpadmin@localhost IDENTIFIED BY ‘abcd1234’;
    mysql> FLUSH PRIVILEGES;
    mysql> quit
    

Configuring db01

  1. Now configure MySQL on db01 by editing my.cnf conf file:
    vi /etc/my.cnf
  2. Modify the file to look like this, replacing myblog_wordpress with the actual name of the database and 10.1.1.12 with the private IP of db02. Pay extra attention to the lines with the #Different comments:
    [mysqld]
    datadir=/var/lib/mysql
    socket=/var/lib/mysql/mysql.sock
    user=mysql
    # Default to using old password format for compatibility with mysql 3.x
    # clients (those using the mysqlclient10 compatibility package).
    old_passwords=1
    
    server-id=1 #Different than db02
    
    log-bin
    log-bin=/var/log/mysqld/db01-bin #Different than db02
    log-bin-index=/var/log/mysqld/db01-bin-log.index #Different than db02
    binlog-do-db=myblog_wordpress
    binlog-ignore-db=mysql
    binlog-ignore-db=test
    
    master-host=10.1.1.12 #Different than db02
    master-user=replication
    master-password=slave
    
    replicate-same-server-id=0
    auto-increment-increment=2
    auto-increment-offset=1
    master-connect-retry=5
    
    relay-log=/var/log/mysqld/db01-relay-bin #Different than db02
    relay-log-index=/var/log/mysqld/db01-relay-log.index #Different than db02
    
    expire_logs_days=10
    max_binlog_size=500M
    
    [mysqld_safe]
    log-error=/var/log/mysqld.log
    pid-file=/var/run/mysqld/mysqld.pid
    
  3. Create the log file directories for the new MySQL logging and then restart the service:
    mkdir /var/log/mysqld
    chown mysql:mysql /var/log/mysqld
    service mysqld restart
    

Configuring db02

  1. Now configure MySQL on db02 by editing my.cnf conf file:
    vi /etc/my.cnf
  2. Modify the file to look like this, replacing myblog_wordpress with the actual name of the database and 10.1.1.11 with the private IP of db01. Pay extra attention to the lines with the #different comments:
    [mysqld]
    datadir=/var/lib/mysql
    socket=/var/lib/mysql/mysql.sock
    user=mysql
    # Default to using old password format for compatibility with mysql 3.x
    # clients (those using the mysqlclient10 compatibility package).
    old_passwords=1
    
    server-id=2
    
    log-bin
    log-bin=/var/log/mysqld/db02-bin #Different than db01
    log-bin-index=/var/log/mysqld/db02-bin-log.index #Different than db01
    binlog-do-db=myblog_wordpress
    binlog-ignore-db=mysql
    binlog-ignore-db=test
    
    master-host=10.1.1.11 #Different than db01
    master-user=replication
    master-password=slave
    
    replicate-same-server-id=0
    auto-increment-increment=2
    auto-increment-offset=2 #Different than db01
    master-connect-retry=5
    
    relay-log=/var/log/mysqld/db02-relay-bin #Different than db01
    relay-log-index=/var/log/mysqld/db02-relay-log.index #Different than db01
    
    expire_logs_days=10
    max_binlog_size=500M
    
    [mysqld_safe]
    log-error=/var/log/mysqld.log
    pid-file=/var/run/mysqld/mysqld.pid
    
  3. Create the log file directories for the new MySQL logging and then restart the service:
    mkdir /var/log/mysqld
    chown mysql:mysql /var/log/mysqld
    service mysqld restart
    

Verify the MySQL Replication Status

  1. To verify the MySQL replication, enter MySQL and run the following commands:
    mysql -u root –p
    mysql> SHOW MASTER STATUS;
    mysql> SHOW SLAVE STATUS\G
    
  2. The most important lines to check are the following, which should read “Yes” on both DB servers:
    Slave_IO_Running:  Yes
    Slave_SQL_Running:  Yes
    
  3. Also important is the following line from SHOW SLAVE STATUS\G which should match the Position value from SHOW MASTER STATUS; on the other server. The number may differ from what you see below:
    Read_Master_Log_Pos:  98
    
  4. MySQL replication usually works well and is extremely useful, but the databases can get out of sync under certain conditions. One thing to try is to issue the following commands on both servers:
    mysql> stop slave;
    mysql> reset master;
    mysql> reset slave;
    mysql> start slave;
    
  5. If that doesn’t work, follow the "Restoring from Backups" section below.

Setting up Backups

This backup configuration is very basic and is only a suggestion of one way you can ensure you have something to fall back on if something goes wrong. It only maintains one copy of backups from the night before. Also, some of this is redundant, but it ensures your backups will continue from more than one source should one server be off for an extended period of time. Note that these operations are all scheduled everyday at 2:00am. This time can be adjusted as desired, but should be kept the same on all servers to ensure the web and DB content in the backups are as synchronized as possible.

Configuring Backups on web01

  1. To configure backups on the first web server, you will need to create a backups directory on the localhost:
    mkdir /mnt/cloudstorage/backups
    mkdir /root/backups
    
  2. Now create a simple bash script to backup your document root:
    vi /root/backups/web01-backup.sh
    

    Enter the following into the file, replacing myblog_wordpress in all instances with the document root on Cloud Storage:

    #!/bin/bash
    tar czf /mnt/cloudstorage/backups/web01-myblog_wordpress.tar.gz /mnt/cloudstorage/myblog_wordpress
    /bin/cp /mnt/cloudstorage/backups/web01-myblog_wordpress.tar.gz /root/backups/web01-myblog_wordpress.tar.gz
    
  3. Modify the script's permissions to be run by root:
    chmod +x /root/backups/web01-backup.sh
  4. Now set up a crontab to execute the backup script nightly at 2am:
    crontab -e
    * 2 * * * /root/backups/web01-backup.sh
    

Configuring Backups on web02

  1. Now configure backups on the second web server. The process is identical to web01 except the name of the server has changed:
    mkdir /root/backups
    
  2. Now create a simple bash script to backup your document root:
    vi /root/backups/web02-backup.sh
    

    Enter the following into the file, replacing myblog_wordpress in all instances with the document root on Cloud Storage:

    #!/bin/bash
    tar czf /mnt/cloudstorage/backups/web02-myblog_wordpress.tar.gz /mnt/cloudstorage/myblog_wordpress
    /bin/cp /mnt/cloudstorage/backups/web02-myblog_wordpress.tar.gz /root/backups/web02-myblog_wordpress.tar.gz
    
  3. Modify the script's permissions to be run by root:
    chmod +x /root/backups/web02-backup.sh
  4. Now set up a crontab to execute the backup script nightly at 2am:
    crontab -e
    * 2 * * * /root/backups/web02-backup.sh
    

Configuring Backups on db01

  1. Configure backups on the first db server. You will need to create a backups directory on the localhost:
    mkdir /root/backups
    
  2. Now create a simple bash script to backup your document root:
    vi /root/backups/db01-backup.sh
    

    Enter the following into the file, replacing wpadmin with your database username, abcd1234 with your database password, and myblog_wordpress with your database name:

    #!/bin/bash
    mysqldump --user=wpadmin --password=abcd1234 myblog_wordpress > /root/backups/db01-myblog_wordpress.sql
    /bin/cp /root/backups/db01-myblog_wordpress.sql /mnt/cloudstorage/backups/db01-myblog_wordpress.sql
    

    where abcd1234 is replaced with your database password.

  3. Modify the script's permissions to be run by root:
    chmod +x /root/backups/db01-backup.sh
  4. Now set up a crontab to execute the backup script nightly at 2am:
    crontab -e
    * 2 * * * /root/backups/db01-backup.sh
    

Configuring Backups on db02

  1. Configure backups on the second db server. This is almost identical to db01 except the hostnames have changed:
    mkdir /root/backups
    
  2. Now create a simple bash script to backup your document root:
    vi /root/backups/db02-backup.sh
    

    Enter the following into the file, replacing wpadmin with your database username, abcd1234 with your database password, and myblog_wordpress with your database name:

    #!/bin/bash
    mysqldump --user=wpadmin --password=abcd1234 myblog_wordpress > /root/backups/db02-myblog_wordpress.sql
    /bin/cp /root/backups/db02-myblog_wordpress.sql /mnt/cloudstorage/backups/db02-myblog_wordpress.sql
    

    where abcd1234 is replaced with your database password.

  3. Modify the script's permissions to be run by root:
    chmod +x /root/backups/db02-backup.sh
  4. Now set up a crontab to execute the backup script nightly at 2am:
    crontab -e
    * 2 * * * /root/backups/db02-backup.sh
    

Restoring From Backups

If something causes the databases to become out of synch or if it is necessary to go back to an earlier state of the Wordpress blog for any other reason, the following procedure can be used to restore the backups that were setup in the previous section. Since Wordpress content is stored as a mixture of web and database content, it is important when performing a restore to restore everything from web and DB backups taken at the same time.

Be certain to check that the backups exist and are in good order before proceeding as the first steps are destructive. It’s always a good idea to be safe and make backup copies of the existing content before proceeding with this restoration.

Restoring Web Servers

You can restore web servers once from either web server since the source files are hosted on Cloud Storage. Since each web server accesses the files on Cloud Storage, you will simply need to run the following commands from one of the web server to restore a backup, replacing myblog_wordpress in all instances with your document root.

rm -rf /mnt/cloudstorage/myblog_wordpress
tar zxvf /mnt/cloudstorage/backups/web01-myblog_wordpress.tar.gz /mnt/cloudstorage

This will restore a single backup to both web servers with minimal downtime.

Restoring Database Servers

Since the MySQL servers are in master-master replication, you will only need to restore one database server and the other will pick up the changes. Enter the following commands on a single db server to restore them both, replacing myblog_wordpress in all instances with your database name, wpadmin in all instances with your database password, 10.1.1 in all instances with the first 3 octets of your private IP range, and abcd1234 in all instances with your database password:

mysql -u root -p 

mysql> DROP DATABASE myblog_wordpress;
mysql> CREATE DATABASE myblog_wordpress;
mysql> USE myblog_wordpress;
mysql> source /mnt/cloudstorage/backups/db01-myblog_wordpress.sql
mysql> GRANT ALL ON myblog_wordpress.* TO wpadmin@'10.1.1.%' IDENTIFIED BY 'abcd1234';
mysql> GRANT ALL ON myblog_wordpress.* TO wpadmin@localhost IDENTIFIED BY 'abcd1234';
mysql> quit


This will restore both databases and no further action is necessary.

Testing

Test the setup to ensure everything is working as expected. It should be possible to take down 1 web server and 1 database server and the blog will continue to be online. The blog can still be updated when a web or database server is offline. When the database server comes back online, it should “catch up” with the other thanks to the replication services. Try different combinations of shutting down servers, accessing the blog, and posting content. At worst, there may be an interrupted connection during a failover, but refreshing the browser after a few seconds should then show the site.

Personal tools