Adventures with EC2 micro instances: Content Delivery Network

by 9 May 2014, last updated 14 May 2014

Serving content through a CDN is often regarded as a costly operation, which requires heavy traffic to justify. Nowadays it's cheap, and benefits micro instances too.

This article follows the steps done in the previous article, where a t1.micro instance was set up with Nginx, PHP-FPM and MySQL server. You can also easily apply them to your own Nginx configuration if you didn't go through the previous article.

The focus here is CloudFront, a part of Amazon Web Services, and uses the same pricing model as the other services. You pay for the requests and bandwidth, so your cost might be anything from a few cents to a couple of dollars for the average site running on a micro instance. Realistically, if you're paying more than a few dollars a month on CloudFront, chances are that you've already had to upgrade from a single micro instance to bigger instances, more load balanced instances and/or RDS.

Basic strategy

We could go all-out by hosting the whole domain through a CDN, but in this article we'll just lighten the load on the instance by serving static content through one. The idea is that dynamic content is served directly from the server so the visitor will always have up-to-date information, and you'll have direct control on the way that content is served.

Images, stylesheets, JavaScript and miscellaneous binary downloads will be served through static.domain.com, which points to CloudFront's servers. Internally CloudFront will use another domain, static-origin.domain.com, to fetch files to its caches. This origin domain exposes a static directory under our regular domain.com root.

So effectively, static-origin.domain.com/image.jpg = domain.com/static/image.jpg.

Why all this? This model fits around the way CMSs usually work, with a single subdirectory for static file uploads. Also, in some cases you can't move a CMS' upload directory outside its root (to use /www/domain.com for CMS and /www/static.domain.com for its content). It also keeps things simple, since all of a site's resources are under a single directory.

Step 1: CloudFront distribution

All of these steps are pretty simple and creating a CF distribution isn't an exception. Even if the distribution creation wizard (and AWS Console in general) seems complex at first.

Sign in to AWS Console, open the CloudFront section, and click Create Distribution to get started.

  1. Select Web as your delivery method.
  2. Origin Settings
    • Origin Domain Name: static-origin.domain.com
    • Origin ID gets filled automatically
  3. Default Cache Behavior Settings
    • This section has sensible defaults, but you should definitely click the question mark icons to learn more about each option you might be interested in.
  4. Distribution Settings
    • Alternate Domain Names (CNAMEs): static.domain.com
  5. Click Create Distribution. It takes a while before it's active, so move on to the next step while you wait.

Step 2: DNS changes

This is as simple as adding two new records to your domain's DNS zone. So open Route 53, log in to Namecheap, or access whatever it is that you're using.

Step 3: Web server changes

The static directory should be available, so add it with this:

sudo mkdir /www/domain.com/static

If you use something else, like uploads, change the command above and configuration below accordingly.

Add the following to /etc/nginx/conf.d/web.conf which was created in the previous article:

server {
  listen 80;
  server_name static-origin.domain.com;
  root /www/domain.com/static;

  access_log /var/log/nginx/static-origin.domain.com_access.log;
  error_log /var/log/nginx/static-origin.domain.com_error.log;

  location ~* \.(css|js|jpg|png|gif|pdf|zip)$ {
    expires 1w;
  }
}

Looking quite the same as before. The location block was revised from the previous article's configuration to include some more common extensions of static files you might be serving. Remember to check through this list to make sure it holds everything you need. You could also increase the expiration time to a month (1M), a year (1y) or even max for 10 years. CloudFront then uses this information to store your static files. Be aware that CloudFront might purge your files from their cache early and fetch them again on the next request if their algorithms don't deem them popular enough to hold until expiration.

Finally, reload Nginx with:

sudo service nginx reload

Let's test it

Assuming the CloudFront distribution is up and running at this point, you can test everything by uploading a file (image.jpg in this example) to the static directory, and access the following URLs:

http://static.domain.com/image.jpg
http://static-origin.domain.com/image.jpg
http://domain.com/static/image.jpg

All three should show up and look identical. If the first one fails, make sure the CloudFront distribution has a state of Enabled, and that the second and third ones work. If the second one doesn't work, check the new Nginx configuration, make sure Nginx is reloaded, and that the third one works. If the third one doesn't work, check that the file exists and Nginx is running.

Now start linking to your content using the first type of URL and the CDN will handle your files to your site's visitors.