WordPress on Amazon EC2

It only seems appropriate that the first post on this blog is about how I managed to get it up and running. I had been thinking about starting a blog for a while and now that work is a bit slower than usual because of the summer, I decided to bite the bullet and spend some time to install WordPress on a server and get familiar with the software.

I selected WordPress as my blogging platform of choice for the obvious reasons. It seems to be the de-facto standard these days and as far as I can see it is mature, feature rich and well-supported.

Now the first step when installing WordPress, is to choose between the WordPress.com hosted service, a regular web hosting account, or some form of virtual private server. I discarded the first option quickly, because I prefer to have full flexibility and the  WordPress.com service has limited support when it comes to theming and plugins. So the choice came down to installing WordPress on my current web host or running it “in the cloud”. Because of my networking and data center background I have been curious about  the Amazon EC2 cloud computing platform, but never really had a good case for it. So this seemed like n excellent opportunity. I decide to turn up an EC2 micro instance and install WordPress on it.

Although I have dabbled in Linux and Unix administration, I am not a sysadmin by trade. So clearly this would have been a bit of a daunting task if I would have had to come up with the entire procedure myself. Luckily, I found a couple of good blog posts to get me started. The information contained in this post is loosely based on the information in the following blogs:

To help me understand and supplement some of the material in these posts I spent some time leafing through the “WordPress 3 Complete” book, which was available in my Safari Books Online account.

Launching the Amazon EC2 Instance

I had already been using Amazon S3 for online backups for a while, so all I had to do was add the EC2 service to my existing Amazon S3 account. Once the registration was complete I fired up my first EC2 micro instance from the EC2 console.

Launch EC2 Instance

The first step in the creation of the instance is to select the operating system that you would like to run on your machine. Although I tend to prefer Ubuntu as a Linux distribution, I decide to go with the Amazon Linux AMI. This seems to be a nice stripped down Linux distribution and should offer the best integration with the Amazon EC2 service, as it is built and maintained by Amazon. The tradeoff seems to be that the available repositories are more limited than Ubuntu’s, but for this particular purpose I think that this shouldn’t matter.

Amazon Linux AMI

I select a micro instance, which should be sufficient for now. One of the big advantages of using this type of cloud computing solution, is that it should be pretty painless to scale my installation later if needed.

EC2 Micro Instance

I accept the default 8 GB EBS volume size, figuring that it will probably be enough for the foreseeable future and that I can always increase its size later if required. I leave any other advanced instance details to their default settings.

As part of the configuration process you are also required to create a key pair. Make sure that you store the generated “.pem” file associated with your key in a safe place. You will need this key when you first connect to your instance through SSH. The next step in the process is to configure a security group. By default only SSH is enabled, so be sure to add HTTP and HTTPS to allow access to your WordPress installation later.

Security Group Creation

And off we go… The instance is launching.

Instance Launching

It will take a couple of minutes for the instance to be fully operational and accessible through SSH. However, before jumping onto the freshly installed Linux server I decide to create an elastic IP address for use with this instance. Some of the tutorials perform this step at a later point, but according to comments in the referenced blog posts, this can cause problems with the WordPress installation further down the line. Therefore, I think this is the appropriate point in time to set up the elastic IP address. Elastic IP addresses are created under the “Network & Security” section in the AWS EC2 console.

Note: An interesting thing about elastic IP addresses is that they are free to use, as long as they are associated with an active EC2 instance. If you do not actively use an elastic IP address that you have allocated, you will be charged for it. Essentially, this discourages you from hogging public IP addresses that you are not actively using. As a consequence, you should associate an elastic IP with an instance as soon as you allocate it, in order to avoid being charged for it.

When you allocate an elastic IP address, Amazon also generates an associated public DNS record for this IP address. However, this generated DNS record is not very user friendly.

Elastic IP Address

In order to have a user-friendly URL to point to my blog I create a DNS “CNAME” record in the DNS for my domain, which points to the Amazon public DNS record associated with the elastic IP address:

CNAME palpatine.layerzero.nl ec2-46-51-176-68.eu-west-1.compute.amazonaws.com

Alternatively, you could also create a DNS “A” record pointing to the elastic IP address itself. As long as you only have a single EC2 instance, there is not much difference between these methods. However, when you run multiple instances on EC2, the CNAME method will allow for more efficient communication within the Amazon EC2 cloud, because the DNS names can be resolved to different IP addresses inside the cloud.

Tweaking the EC2 Linux Install

Now that we have the EC2 instance up and running, it is time to connect to it. This is where the key that was created earlier comes into play. I placed this key in the .ssh directory in my home directory on my Mac. I also changed the file permissions on the .pem file to 600, because my ssh client will complain if the permissions on the file are too lax. So now it is time to connect using SSH:

ssh ec2-user@palpatine.layerzero.nl -i ~/.ssh/layerzero.pem

At this point you could simply start the WordPress installation procedure. However, before doing that, I personally like to perform a couple of tweaks for reasons of security and ease of use. Nothing in this section is required to complete the WordPress installation, so if you don’t see any value in the tweaks that I perform in this section, you can simply skip ahead to the WordPress installation part of this post.

The first thing that I am going to do is create a new user and get rid of the default “ec2-user” that was created by Amazon. This is not strictly necessary, but I feel that it is good practice. I switch to the root account using the sudo su command, create a new user, and set a password for the user.

[ec2-user@ip-10-229-65-170 ~]$ sudo su
[root@ip-10-229-65-170 ec2-user]# useradd tom
[root@ip-10-229-65-170 ec2-user]# passwd tom
Changing password for user tom.
New password: ********
Retype new password: ********
passwd: all authentication tokens updated successfully.

Next, I want to make sure that this user can login to the system using the key generated by Amazon. When the instance was created, Amazon added this key as an authorized key to the .ssh directory of the ec2-user. So the easiest way to make sure that the new user can log in using the same credentials, is to copy over the .ssh directory of the ec2-user to the home directory of the new user:

[root@ip-10-229-65-170 ec2-user]# cp -R .ssh ../tom/
[root@ip-10-229-65-170 ec2-user]# chown -R tom:tom ../tom/.ssh

At this point I want to test that I can connect as the new user. Clearly, this can be done using the same command as before replacing the user “ec2-user” in the command with the newly created user. However, because I am lazy, I decide to set up my Mac in such a way that I do not need to specify the user and key file every time I connect to my new host. So I fire up vi and create a file named config in the .ssh directory. In this file I add the following lines:

Host palpatine.layerzero.nl
        IdentityFile "~/.ssh/layerzero.pem"
        User tom

Now I can simply connect using the ssh palpatine.layerzero.nl command without having to specify the user or key file specifically. After having tested that I can connect as my new user, I am going to set up administrative rights for this account. First of all I change the root password:

[root@ip-10-229-65-170 ec2-user]# passwd
Changing password for user root.
New password: ********
Retype new password: ********
passwd: all authentication tokens updated successfully.

Next, I add my new user to the sudoers file by issuing the visudo command as root. In the file I add the following line:


Now it is time to verify that I can switch to root using my new account. So I SSH to my server as the new user and issue the sudo su - command to verify proper operation of the sudo command:

[tom@ip-10-229-65-170 ~]$ sudo su -
[root@ip-10-229-65-170 ~]#

Yay, it works! So now I can safely get rid of the ec2-user. Rather than actually deleting the user, I will simply lock the account and take away its sudo rights. I also remove the authorized key from its .ssh directory to prevent the user from logging in through SSH. To achieve this, I issue the following commands:

[root@ip-10-229-65-170 ~]# passwd -l ec2-user
Locking password for user ec2-user.
passwd: Success
[root@ip-10-229-65-170 ~]# rm /home/ec2-user/.ssh/authorized_keys 
rm: remove regular file `/home/ec2-user/.ssh/authorized_keys'? y

Next I remove the line “ec2-user ALL = NOPASSWD: ALL” from the sudoers file by issuing the visudo command as root. Effectively, I have now transferred the control that was given to the ec2-user by Amazon to a self-defined user account.

As a final tweak, I change the hostname for my server to its proper DNS name, because I don’t like the default hostname that is based on the Amazon internal IP address. The simplest way to change the host name is through the hostname command, but that will not be persistent across reboots. To make the change permanent you should add a proper FQDN in the /etc/sysconfig/network file. So I added the following line to that file:


At this point I am done with the tweaks that I wanted to make to the system. Just to make sure that everything is okay before I start installing the WordPress software, I decide to reboot the system now in order to verify that the hostname and all other changes persist across reboots. So I cross my fingers, reboot, and SSH back into the system as soon as it is up:

chewbacca:~ tom$ ssh palpatine.layerzero.nl
Last login: Fri Aug 24 11:45:29 2012 from a85081.upc-a.chello.nl

       __|  __|_  )
       _|  (     /   Amazon Linux AMI

There are 21 security update(s) out of 28 total update(s) available
Run "sudo yum update" to apply all updates.
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8)
[tom@palpatine ~]$

So there we go, I am ready to install the WordPress software.

Installing WordPress

Before installing the WordPress software itself, I have to install the required packages that WordPress builds on: Apache, PHP, and MySQL. Because pretty much all of the installation work has to be performed as root, I decide to switch to the root account, rather than prepending every command with the sudo command. So I start with the obligatory update of all the packages using yum.

[tom@palpatine ~]$ sudo su -
[root@palpatine ~]# yum update

Next, I install Apache, start it, and set it to always start when the system boots:

[root@palpatine ~]# yum install httpd
[root@palpatine ~]# service httpd start
[root@palpatine ~]# chkconfig httpd on

Now let’s install PHP and restart Apache:

[root@palpatine ~]# yum install php php-mysql
[root@palpatine ~]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

And finally, I install MySQL, start it, and set it to always start at boot:

[root@palpatine ~]# yum install mysql-server
[root@palpatine ~]# service mysqld start
Initializing MySQL database:  Installing MySQL system tables...
Filling help tables...

To start mysqld at boot time you have to copy
support-files/mysql.server to the right place for your system

To do so, start the server, then issue the following commands:

/usr/bin/mysqladmin -u root password 'new-password'
/usr/bin/mysqladmin -u root -h palpatine.layerzero.nl password 'new-password'

Alternatively you can run:

which will also give you the option of removing the test
databases and anonymous user created by default.  This is
strongly recommended for production servers.

See the manual for more instructions.

You can start the MySQL daemon with:
cd /usr ; /usr/bin/mysqld_safe &

You can test the MySQL daemon with mysql-test-run.pl
cd /usr/mysql-test ; perl mysql-test-run.pl

Please report any problems with the /usr/bin/mysqlbug script!

                                                           [  OK  ]
Starting mysqld:                                           [  OK  ]
[root@palpatine ~]# chkconfig mysqld on

With SQL running, I create the WordPress database:

[root@palpatine ~]# mysqladmin -u root create wordpress

Also, I secure the MySQL installation using the /usr/bin/mysql_secure_installation script:

[root@palpatine ~]# mysql_secure_installation


In order to log into MySQL to secure it, we'll need the current
password for the root user.  If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none): 
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] y
New password: 
Re-enter new password: 
Password updated successfully!
Reloading privilege tables..
 ... Success!

By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
 ... Success!

By default, MySQL comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!

One final tweak that I want to make, is to enable the Apache module mod_rewrite in order to allow the use of pretty permalinks in WordPress. This is accomplished by editing the following line in /etc/httpd/conf/httpd.conf:

# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
#   Options FileInfo AuthConfig Limit
    AllowOverride All

While I am editing the file anyway, I also set the server admin email address:

ServerAdmin admin@layerzero.nl

And of course I restart Apache to make the changes to the configuration file take effect:

[root@palpatine ~]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

Now it is time to install the actual WordPress software. I download the latest version of the software into the /var/www/html Apache root directory and untar it:

[root@palpatine ~]# cd /var/www/html/
[root@palpatine html]# wget http://wordpress.org/latest.tar.gz
[root@palpatine html]# tar -xzvf latest.tar.gz
[root@palpatine html]# rm latest.tar.gz

By default all the files are placed in a directory named “wordpress”. I rename the “wordpress” directory to “blog”, because I prefer to have the word “blog” in the blog URL, rather than “wordpress”.

[root@palpatine html]# mv wordpress blog
[root@palpatine html]# cd blog

Now we have to create a WordPress configuration file, which is most easily done by copying the wp-config-sample.php file to wp-config.php and editing it:

[root@palpatine blog]# mv wp-config-sample.php wp-config.php

So I open the file with vi and fill in the appropriate fields:

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */

/** MySQL hostname */
define('DB_HOST', 'localhost');

For security purposes I also generate the required salts through use of https://api.wordpress.org/secret-key/1.1/salt/ and insert these in the file.

At this point we’re almost done. As a final step I change ownership of all the wordpress files to the apache user. This will allow Apache to write files in the blog directory, which is necessary to install themes, upload files, etc. through the WordPress interface. As an alternative, it is also possible to enable FTP on the server and allow WordPress to upload the files through FTP, but personally I think it is cleaner to transfer files directly using HTTP instead of enabling another service just for this purpose.

[root@palpatine blog]# cd ../..
[root@palpatine www]# chown -R apache:apache html

So now we’re all set! To finalize the install, I point my browser to the install link “http://palpatine.layerzero.nl/blog/wp-admin/install.php” and fill in the basic parameters to create an admin account:

Install WordPress

And at last, I am ready to start blogging!

2 thoughts on “WordPress on Amazon EC2

Leave a Reply

Your email address will not be published. Required fields are marked *