Drawing a Blank
by Mike Fulcher

Playing with Nginx & PageSpeed on EC2
Friday, June 07, 2013

Up until recently I’ve been hosting this Jekyll-powered blog on GitHub Pages. I wanted hosting that was cheap or free and I wanted dead simple deployments. For that, GitHub Pages was perfect. But I found that I needed more – for example, on GitHub Pages I have no control over cache expiry headers. Even Heroku fell short, as I want to have my blog served up on my apex domain; not a sub-domain. I also really wanted to try automating performance optimisations using Google’s PageSpeed Nginx module in order to simplify my usual workflow, so I decided to do some experimenting with PageSpeed on an EC2 instance.

Getting started: Provisioning a new EC2 instance

If this is your first time setting up EC2, sign into AWS and go to your AWS Management Console, then click on EC2. At this stage you may wish to change the selected region (being based in New Zealand, I chose the Sydney region). Click the Launch Instance button, and follow the wizard to create your EC2. I chose an Ubuntu 13.04 Server (64 bit) and kept all settings as default (don’t forget to create a Key Pair if you need to – this is how you’ll access your EC2. Alternatively you can select a Key Pair you’ve created previously). Once you’re finished, you should see “1 Running Instance” on your EC2 Dashboard.

Configuring the firewall

Next, the firewall settings need to be configured to allow SSH, HTTP and HTTPS so that we can access and run our web server. Go to the Security Groups page (under Network & Security), select the security group you chose for your EC2, and click the Inbound tab. If you don’t see 22 (SSH) in the list, select SSH from the dropdown and hit Add Rule. Do the same for HTTP and HTTPS. Finally, hit Apply Rule Changes.

Gaining access

If this is your first time accessing an EC2, you’ll need to set up your Key Pair. First, move the .pem file into ~/.ssh/ (or wherever you like to keep your SSH keys) and run ssh-add ~/.ssh/my-key-pair.pem. This tells SSH to try using this key when it makes a new SSH connection.

At this stage you could SSH into your EC2 using the public DNS that is assigned to your instance, but I’m going to go one step further and assign the instance it’s own IP address. We can do this using Amazon Elastic IP addresses, and it means that you can create an A record on your apex domain which points to your EC2 instance – no need for a www subdomains and CNAME records!

Assigning an Elastic IP

Back on your AWS Management Console, go to Elastic IPs (also under Network & Security), click Allocate New Address, and follow the prompts to create an IP address and assign it to your EC2 instance. Once that’s done, you can create an A record to point your domain at this IP address, and you’ll then be able to connect to your EC2 using ssh ubuntu@yourdomain.com. Note that the user is ubuntu – that’s the root user that gets created when you provision Ubuntu instances. If you selected a different OS, the user may have a different name.

Setting up

Since we have a fresh OS installed on our EC2 there are a few packages we should install first. To speed this up, I used a simple script that I found here. This installs some essential packages along with rvm and Ruby 2 (which we’ll need in order to compile our Jekyll blog). The only problem I had with this script is that it installs Apache2, and I wanted Nginx. You could modify the script before you run it, or if like me you’ve already run it, you can run the following commands to remove it cleanly:

# Stop the server, if it's running
sudo service apache2 stop
# Remove all apache2 packages and dependencies
sudo apt-get purge apache2 apache2-utils apache2.2-bin apache2-common
sudo apt-get autoremove --purge
# Remove all trace
sudo rm -Rf /etc/apache2 /usr/lib/apache2 /usr/include/apache2

Important: don’t go installing Nginx using apt just yet. While it’s the easiest way to install Nginx, we’re going to compile it from source, so that we can inject the PageSpeed module during the compile phase.

Installing PageSpeed + Nginx

Installing PageSpeed requires building Nginx from source so that the PageSpeed module can be injected into the final build. Fortunately it’s very straightforward: just follow the instructions in the readme on the PageSpeed GitHub repo.

Configuring Nginx

By default, the Nginx configuration file is located at /usr/local/nginx/conf/nginx.conf. I have my Jekyll source located at ~/static/drawingablank.me/, so I started by replacing the sample server block with the following:

server {
  listen       80;
  server_name  localhost 54.252.195.157 drawingablank.me;

  charset utf-8;

  location / {
    root   /home/ubuntu/static/drawingablank.me/_site;
    index  index.html;
  }
}

Adding PageSpeed

You’ll find instructions for enabling PageSpeed in the readme on the GitHub repo. My new server block looks like this:

server {
  listen       80;
  server_name  localhost 54.252.195.157 drawingablank.me;

  charset utf-8;

  location / {
    root   /home/ubuntu/static/drawingablank.me/_site;
    index  index.html;
  }

  pagespeed on;

  # Needs to exist and be writable by nginx.
  pagespeed FileCachePath /var/ngx_pagespeed_cache;

  # Ensure requests for pagespeed optimized resources go to the pagespeed handler
  # and no extraneous headers get set.
  location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
    add_header "" "";
  }
  location ~ "^/ngx_pagespeed_static/" { }
  location ~ "^/ngx_pagespeed_beacon$" { }
  location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
  location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }
}

This will enable the default set of PageSpeed optimisations, but you can also turn on/off just the features you want. Also, note the FileCachePath which needs to be a directory which is writable by Nginx. First create the directory with sudo mkdir /var/ngx_pagespeed_cache then set the permissions with sudo chmod 777 /var/ngx_pagespeed_cache.

One extra step I’d like to mention: installing Nginx from source doesn’t install an init script. On Ubuntu, I recommend this init script – installation instructions are on the readme. This lets you run sudo service nginx start|stop|restart. At this point, you should be able to start Nginx, hit your domain and see your website! And if you view source, you should – if things are running correctly – see that your CSS and javascript assets have been rewritten (you’ll see .pagespeed. in the file paths).