Now that we have our AWS infrastructure configured to support a sample WordPress workload (see Part 1 and Part 2 of this series) we can get into installing and configuring WordPress, AWS ElastiCache, and S3 / Glacier backups.
Setup NFS Server for WordPress Media Library
Our WordPress EC2 instances will be transient – we’ll be using AWS Auto Scaling to spin up and down web server instances as needed. In a single server setup, WordPress expects a local (ext4) directory (/wp-content) within the web server root directory for storing WordPress content (themes, plugins, media library, images). The problem with this in an auto-scale setup is that the local directory stays local to one WordPress server, not distributed on all instances. New scale-up instances would be based on the AMI template and wouldn’t have the latest content. On scale-down operations, those local wp-content stores would be lost.
To work around this I decided to set up a NFS server on an EC2 instance. I deployed an Amazon Linux AMI on EC2. An AMI is a template image that can be used to deploy new instances, just like a vSphere VM template. I used ami-05355a6c – a 64-bit instance with a persistent Elastic Block Storage (EBS) volume. Amazon Linux AMI’s are based on RHEL. I chose to deploy a t1.micro instance as this first instance will not be used for production. It also helps that t1.micro instances are included in the AWS Free Tier. I chose to place the new instance in the WordPress Security Group I created earlier.
There are better ways to manage this – like clustering or using rsync between multiple NFS servers in different AWS availability zones. Some WordPress plugins that are designed to copy all local content to an AWS S3 store show promise, but none that I tested were 100% when I enabled Auto Scaling. But a guy can only throw so many resources at a demo, so let’s move on. I’ll hit the NFS config in the next section.
Installing WordPress Server on Amazon Web Services (AWS)
When it comes to deploying web apps to an AWS environment we’ve got options. The simplest is to run WordPress on an EC2 virtual server with Apache or nginx. Another option is using AWS Elastic Beanstalk – a platform as a service (PaaS) offering that allows you to deploy apps directly to a cloud application container with built in scalability. Apps running directly on the cloud – no OS or infrastructure to manage. For this demo, I’m going to go with the first (EC2) option as it’s a bit simpler for an infrastructure guy dipping his toes into the public cloud. We need a template EC2 instance before we create an auto-scale group. Let’s build that out now.
To kick off the WordPress install, I followed the basic instructions on the WordPress site. There’s ample information on the internet on how to do this, so here’s a high-level of my process:
- Create new AWS EC2 instance (a t1.micro instance should be good enough). Add the instance to your EC2 WordPress security group (created in previous post). Save your access key.
- Add new EC2 instance to Elastic Load Balancer (created in previous post).
- SSH to the new server by using the public DNS provided on the AWS Management Console.
- Apply any available security updates.
- Mount the previously created NFS share to my web content directory (DocumentRoot in Apache) I created a new directory for my DocumentRoot at /var/nfs/ on my server, and mounted the NFS export there. I added the mount command to the fstab file so it would be mounted at boot time automatically. Because this is included in the to-be template image, every auto-scale EC2 instance will auto-mount this NFS export.
- Install Apache and supporting PHP modules.
- wget the latest WordPress tar file and unpack /var/www/ (and verify that the files were written to the NFS server).
- Edit wp-config.php and add connection details for WordPress database on AWS RDS (as discussed in my last post). Configure secret keys in wp-config.php file.
- Browse to the WordPress install script page (e.g. https://wordpress.myawsdemo.com/wp-admin/install.php) and complete the setup of WordPress.
- Verify site loads by browsing to your root URL (https://wordpress.myawsdemo.com/).
Congratulations, you now have a running WordPress server; now let’s make it better. It’s been said that appearance is everything, so let’s put a theme on our site. I use the Genesis Framework for many of my sites, so I’ll grab that plus the Associate Child Theme. Configure the theme to your liking. Remember that our DocumentRoot is on a shared NFS server, so every auto-scale instance will have access to the theme assets.
This is also the time to install your WordPress Plugins. While this article is supposed to be more about Amazon Web Services than WordPress, I am going to spend a bit of time on my plugins and their configuration so you can see how I leverage a few other AWS services within plugins to improve scalability, performance, and recoverability of my site.
The first plugin I installed was Google XML Sitemaps (I usually use WordPress SEO by Yoast for SEO optimization and sitemap generation, but it was too much functionality for my demo). I don’t care about SEO or search engine submissions for my demo site, but the sitemap will come in handy for the next plugin: W3 Total Cache.
Caching to AWS ElastiCache
W3 Total Cache (W3TC) is a ‘WordPress Performance Optimization Framework’ that provides browser, page, object, and database caching, minify and content delivery network (CDN) support. After installing and activating W3TC, go to the Install page of the plugin’s settings. Follow the instructions to configure .htaccess and install caching modules. We’ll make use of memcache/memcached shortly. Switch to the General Settings page of W3TC once you complete the installation of the memcache modules. Enable Page Cache and Database Cache and choose the Memcached method for both. Also enable Browser Cache. Save all settings.
Rather than using a local memcache daemon, we’ll use AWS ElastiCache – Amazon’s version of Memcached. ElastiCache is a distributed in-memory caching system that is easily scalable. To use ElastiCache, navigate to the ElastiCache section of the AWS Console and launch a new cache cluster. Give your cache cluster a name and choose your other settings as desired. I am starting with three t1.micro nodes – the nodes will provide 213MB of memcache each. Assign the ElastiCache cluster to your WordPress security group. You can place ElastiCache clusters in specific availability zones. In a production environment, you would want to consider deploying multiple cache clusters to cover the AZs you are running hosts in. This is a beyond my basic demo, so I’ll just stick with one cluster in one AZ. If this AZ or ElastiCache cluster fails, my application will continue, but page and database calls may take longer as the cache would not be available. Once the ElastiCache cluster is instantiated, click the Configuration Endpoint URL in the AWS Console. This will list the addresses of your node endpoints. Copy these node endpoints.s settings. Follow the instructions to configure .htaccess and install caching modules. We’ll make use of memcache/memcached shortly. Switch to the General Settings page of W3TC once you complete the installation of the memcache modules. Enable Page Cache and Database Cache and choose the Memcached method for both. Also enable Browser Cache. Save all settings.
Back in W3TC, click the Page Cache settings page. Check the boxes for Cache front page, Cache feeds, Cache URIs, Cache 404, and Don’t cache pages for logged in users. Under Cache Preload, and check the box for ‘Automatically prime the page cache’. Choose an update interval and number of pages to prime per interval. In the Sitemap URL, use the sitemap.xml file generated by the Google XML Sitemaps plugin. Finally, under the Advanced section, paste the ElastiCache node endpoints into the Memcached hostname:port field as comma separated values. Click Test to verify that the W3TC plugin can communicate with your ElastiCache cluster. If the test passes, Save All Settings.
Switch to the W3TC Database Cache settings page and paste the ElastiCache node endpoints as comma separated values and test. Save all settings after a successful test. ElastiCache is now being used as a page and database cache to improve performance of your site. New EC2 instances that are created through Auto Scaling will be able to use the cache, and will find the cache already warmed.
Content Distribution using AWS CloudFront
I want my site to load quickly for all my visitors, not just those near the AWS US-East datacenters in Northern Virginia. To help with this, I am going to leverage AWS CloudFront as a Content Distribution Network (CDN). W3TC can handle this automatically for us. First, on the W3TC General Settings page, enable CDN and choose Amazon CloudFront (Origin Pull) as the CDN type and save. Now switch to the CDN settings page. Check the boxes for ‘Host Attachements’, ‘Host wp-includes/files’, ‘Host theme files’ and ‘Host custom files’. Now enter your AWS IAM user’s Access Key ID and Secret key and click ‘Create Distribution’. This should create a new distribution in CloudFront.
Now, switch to your Route 53 console and configure a CNAME to point to your CloudFront distribution. The name of the distribution should be presented in the W3TC settings or can be found in the CloudFront console. I used the name static.wordpress.myawsdemo.com.
Next, go to the CloudFront console and edit your distribution’s settings to add the CNAME to the distribution.
Back in the W3TC CDN Settings page, add your CNAME to line #1 under ‘Replace site’s hostname with:’ Test your CloudFront distribution using the test button. If successful, save all settings. You can use the Import buttons on the W3TC CDN Settings page to import your site’s assets into CloudFront immediately. You can now use a tool like CloudBerry Explorer for Amazon S3 to verify that content is being pulled into CloudFront. Finally, load your site and ensure that static assets like pictures are being served from CloudFront via your static CNAME instead of the base URL of your site (right-click and copy image URL to verify).
Now, when someone visits your site, AWS CloudFront will deliver your site’s static assets from the nearest edge location around the world.
Backup to AWS S3 and Glacier
The final WordPress plugin that I want to highlight is BackWPup. This is one of several backup plugins for WordPress. With BackWPup, I can backup my entire WordPress install, as well as any additional files on my server (Apache configuration files, Varnish VCLs, etc.). AWS Simple Storage Service (S3) is supported as a backup target. In the BackWPup settings, add a new job and set it to use Amazon S3. Enter the Access and Secret keys for your IAM WordPress user. Create a new AWS bucket through the plugin (or manually in the S3 Console). You can also choose to place your backups on the S3 Reduced Redundancy storage class to reduce cost.
Once backups are written to S3, you can configure long-term archiving of your backups to AWS Glacier. Glacier is a low cost ($0.01 / GB / Month) storage service designed for 99.999999999% (Eleven Nines) durability. Using a S3 Lifecycle Rule on my BackWPup bucket, I can archive my backups to Glacier for long-term keeping.
With backups in place, I now have a production ready WordPress server with good performance, thanks to flexible EC2 instance sizing (CPU and memory) and ElastiCache caching, and backup and archiving thanks to S3 and Glacier. We’re now ready to configure an auto-scaling group of WordPress servers based on this template that will respond automatically to the load placed on the group. Stay tuned for the next post for a walk-through of how to configure AWS Auto Scaling for WordPress.
Series Links:
Part 1: Introduction to Amazon Web Services (AWS)
Part 2: Preparing Amazon Web Services (AWS) for an Auto-Scaling WordPress Site
Part 3: Installing WordPress on AWS
Part 4: Configuring AWS Auto Scaling for WordPress