Tuesday, January 22, 2013

Setting up Nginx on EC2 Ubuntu

Nginx is a high performance Web server and a reverse proxy. It is one of the top servers that can counter the C10K problem. It can be used to load balancer application servers and serve static assets.

There are many ways to set up your load balancers in AWS. Here are some examples:
  1. Elastic Loader Balancer -> Application and Nginx on each server
  2. Three layers: Elastic Load Balancer -> Nginx Servers(cache, load balancers) -> Application Servers
  3. Elastic Loader Blancer -> Application servers; using ElasticFront to server assets
  4. Nginx -> Application servers
Instagram uses the 2nd approach above.

This tutorial will focus on setting up Nginx on a single EC2 instance, while load balancing the application servers.

Creating a EC2 Instance

In the AWS Management Console, begin by creating a t1.micro Ubuntu Server 12.04.1 LTS 64-bit. (If you don't know how to create an instance, read Amazon EC2 - Launching Ubuntu Server 12.04.1 LTS step by step guide.

Here are some guidelines:
  • Uncheck Delete on Termination for the root volume
  • Add port 22, 80 and 443 to the Security Group, call it Nginx.

Installing Nginx

ssh into your instance.
ssh -i {your key} ubuntu@{your_ec2_public_address}
sudo apt-get update

sudo apt-get install -y nginx

Check the nginx version
nginx -v
If this is not the latest version, do the following:

sudo vi /etc/apt/sources.list

deb http://nginx.org/packages/ubuntu/ precise nginx
deb-src http://nginx.org/packages/ubuntu/ precise nginx 
sudo apt-get update

You will get:
W: GPG error: http://nginx.org precise Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY ABF5BD827BD9BF62
Add the public key:

wget http://nginx.org/packages/keys/nginx_signing.key
cat nginx_signing.key | sudo apt-key add -

sudo apt-get install nginx

You may get the following:

dpkg: error processing /var/cache/apt/archives/nginx_1.2.6-1~precise_amd64.deb (--unpack):
 trying to overwrite '/etc/logrotate.d/nginx', which is also in package nginx-common 1.1.19-1ubuntu0.1
dpkg-deb: error: subprocess paste was killed by signal (Broken pipe)
Errors were encountered while processing:

apt-get remove nginx-common
sudo apt-get install nginx

Check your version to make sure it's the latest version (nginx -v).

Make Nginx start on boot.
update-rc.d nginx defaults

Nginx Basic Commands

sudo service nginx start
sudo service nginx stop
sudo service nginx restart
sudo service nginx status

Checking IP of your browser:
ifconfig eth0 | grep inet | awk '{ print $2 }'

Load balancing servers

We will have the Nginx server to load balance two servers (backend1.example.com and backend2.example.com) in a round robin fashion.

Begin by creating a new virtual host configuration file.
cp /etc/nginx/sites-available/default /etc/nginx/sites-available/{domain}
Put the following into the file:

upstream domain {
    server backend1.example.com:8080;
    server backend2.example.com:8080;
server {
    listen 80;
    server_name domain
    access_log /var/log/nginx/web_portal.access.log;
    location / {
            proxy_pass      http://domain/;
            proxy_next_upstream error timeout invalid_header http_500;
            proxy_connect_timeout 2;
            proxy_set_header        Host            $host;
            proxy_set_header        X-Real-IP       $remote_addr;
            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_intercept_errors on;

Make sure the domain above match with your request domain.

It is very important to have the following two attributes. It defines what happens when a server is down. In this case, it would redirect the client request to the next machine if the server is not responding within 2 secs.
proxy_next_upstream error timeout invalid_header http_500;
proxy_connect_timeout 1;
Check out proxy_read_timeout as well.

ip_hash will always send the client back to the same server based on the IP.

Check the Nginx Wiki for more info.

Disable the default config.
rm /etc/nginx/sites-enabled/default
Enable the configuration by symbolic link to sites-enabled.
sudo ln -s /etc/nginx/sites-available/{domain} /etc/nginx/sites-enabled/{domain}
If Nginx doesn't seem to pick up on the configuration, make sure /etc/nginx/nginx.conf has the following within the http block:
include /etc/nginx/sites-enabled/*;
Restart the server.
service nginx restart
To deploy code without service interruption, read Nginx - How to deploy code without service disruption.


  1. This comment has been removed by the author.

  2. Nice article! One image is worth thousand words. The only thing I would mention is tiny is difference between installing it on Amazon AMI (ContOS based) and say... Ubuntu (debian based). I was writing a blog post about it while ago, elaborating about 2nd method, which is compilation, which is required if you would like to get sockets enabled, for example for node.js socket.io. Full tutorial can be found here.

  3. Thanks a bunch for this post it really helped me with mine. I needed to setup Ghost with Nginx on an EC2 instance so I could completely Continuously Deliver it.

    I love your attention to detail on issues with Ubuntu 14.04 on Amazon EC2 as well.

    You can read up on my progress http://devangst.com/how-to-drive-ghost-blog-using-continuous-delivery-part-1/ with Part 2: http://devangst.com/how-to-drive-ghost-blog-using-continuous-delivery-part-2/

    Third and final part coming soon. Thanks again and feel free to comment

  4. Awesome post presented by you..your writing style is fabulous and keep update with your blogs
    AWS Online Training