45 Main St. Suite 1100
Brooklyn, NY 11201
Call Us:

718.395.7934

Press opportunities:

cHJlc3NAY2Fycm90Lmlz

Nginx for Developers: An Introduction

by Jeff and Kyle on 6/18/2013

If you are a web developer, you've probably heard of nginx (pronounced engine-x). Nginx is a fast and extremely powerful http and reverse proxy server that can be used to quickly and easily serve webpages.

Unfortunately, like many sysops tools, there is very little documentation and very few tutorials that explain how it works and how to get up and running. There is a wiki, which is extensive and confusing - showing you all possible options rather than presenting the important ones as you need them. After struggling with it myself for a bit, I finally got down the basics of how to work with nginx, and wanted to share it so that other developers would have an easier time picking it up.

So let's dive right into it. For this tutorial, you're going to want a VPS of some sort, preferably fresh so that you can avoid potential conflict with other old setups etc.

initial setup

Assuming you are running an ubuntu box (probably from digital ocean), once you have set up your login and have apt updated, just run apt-get install nginx and everything should install cleanly. Visit your server's IP address in a web browser and you'll see the "welcome to nginx" message. Great success.

finding nginx

When nginx is installed (through apt), it provides a solid basic structure for how to set up your config files. All nginx config files are located in /etc/nginx, so cd there and poke around. The place you'll want to add new configurations is the sites-enabled folder. If you check this folder out, you'll find that there's a single text file called default in there, and opening that up you'll see an nginx configuration and the code that causes the "welcome to nginx" page to display. Now let's make our own config file with the bare basics to display a page. Touch a new file inside sites-enabled called 'test', open it up in your text editor of choice, and let's get to it.

note: You'll also find a /etc/nginx/sites-available directory. If you find yourself managing many different sites that are coming up-and-down, this folder can help keep things organized. Add your nginx configuration files here instead and then symlink them to sites-enabled. This command might look something like this...

 ln -s /etc/nginx/sites-available/dotcom /etc/nginx/sites-enabled/dotcom

Only configurations in sites-enabled will actually be public to visitors, but you may want to keep some configurations in sites-available for archival and symlinking purposes.

configuring a static server

Nginx config files use their own language, but the good news is that it's super simple. Much like css, namespaces are declared followed by a block which is bound on either side by curly braces. The top level block we want to enter is server, which would look like this:

server {

}

Inside this block, we can, again much like css, add key-value pairs followed by semicolons, or (more like sass), we can add a nested block. We'll be doing both of these for the basic setup, and it should be no problem to follow.

There are a ridiculous amount of possible key-value pairs or blocks we can add (called directives, will be referring to them this way through the rest of the tutorial), and if you jump into the documentation, you will find a few hundred. For a basic server setup though, only a few are important to know, and we'll go over those here. I'll include links to the official nginx docs for each directive we go over if you are interested. Since the official docs are the only official way to get around nginx, it's important to become familiar with how they work if and when you want to set up something more advanced later.

listen This directive specifies the port that your server will listen at. If you have ever worked with rails, you'd know that the local server runs on port 3000. Roots runs on port 1111. SSL runs on port 443. The default port for the internet is 80, so if there's no port in a url, that means it's 80. Since you are likely trying to run a production server here, it's likely that you will be after port 80, so let's enter that here.

server {
  listen 80;
}

Note that this is the default and is not strictly necessary to enter, but it's good to do it anyway in this case to show what's going on. Bam, first directive written. Feels great. Let's keep rolling.

server_name This directive is essentially a matcher for the url bar. Whenever any sort of request comes in to nginx, it takes a look at the url and looks for a server block that has a matching server_name directive. So if your site was at http://example.com, your server_name for the root would be example.com. If you used an A Record to also route http://snargles.com through to your server, you could add another server block with a server_name of snargles.com, and that block would match requests coming in from that domain.

This is quite powerful. If you think about it, this means you can host numerous sites, even coming from different domains, on a single nginx configuration. All you have to do is set up an A Record that points the domain to your box's IP, then sort out the rest with nginx server configs.

It's worth noting two more interesting aspects of server_name. First, you can use this directive to also deal with subdomains. If you want to match http://test.example.com, you can easily do this, and even map it to an entirely different app. Second, you can perform some wizardry with the value of server_name. You can use both wildcards, indicated by *, or regular expressions to match routes. As you can imagine, this can be extremely powerful. Let's write a quick config for the root domain of example.com.

server {
  listen 80;
  server_name example.com;
}

Sweet. Only a couple more directives till we can get our site in production.

root This is the key to serving static sites. If you are just trying to lay down some html and css, the root directive specifies the directory that you have stored your files in. I like to store my sites in /var/www, so let's go make a folder there. Just mkdir a folder called /var/www/example, and inside this, touch an index.html file and add a paragraph saying hello world or something. Now that we're good, let's get back to our config and add our new document root:

server {
  listen 80;
  server_name example.com;
  root /var/www/example;
}

Now that we've got the basic variables set, let's actually listen for hits to a specific route.

location Location takes two parameters, a string/regex and a block. The string/regex is a matcher for a specific location. So if you wanted anyone who went to example.com/whatever to hit a specific page, you would use 'whatever' as the uri. In this case, we are just trying to match the root, so we can use / as the uri here. Let's fill in an empty block for now, which we will complete in a second.

server {
  listen 80;
  server_name example.com;
  root /var/www/example;

  location / {

  }
}

Note that the first parameter has a number of options which you can see in the linked documentation, and that the ability to match by regex is quite powerful. Inside that block, we want to actually route to the result page. Also note that this / uri will match all urls, since it's treated as a regex. If you want a location block to match only an exact string, you can preface it with an equals sign, as shown below. But in this case, it's ok for it to match all urls.

location = / { ... }

Now to fill in that block from before... We can use another directive inside the block to serve a file called try_files. Try files takes a list of filenames or patterns that it will try to find in you root directory, and it will serve the first one it finds. For our simple static server, we want to try to find a file with the name of whatever comes after the slash, like 'whatever.html'. If there is nothing after the slash, it should go for index.html. There are a few other technical aspects to how you write these which are laid out in the docs linked above, here's a very simple implementation.

server {
  listen 80;
  server_name example.com;
  root /var/www/example;

  location / {
    try_files $uri $uri/ /index.html;
  }
}

Now you might ask yourself, where did this $uri business come from? Well, that's the magic of nginx. As soon as that request comes in, nginx makes a bunch of variables available to you that hold information about the request. In this case uri is exactly what we were after. So let's walk through the list.

Now try to imagine the flow if we were to add a test.html file to the root directory and go to http://example.com/test.html. Then try it and see what happens.

Note that you can twist this configuration any way you want. For example, on carrot.is, we have it configured so that when you hit a filename without the .html extension, try_files looks for $uri.html and matches that as well. So you could go to http://carrot.is/about as well as http://carrot.is/about.html, and they would both return the same document. The amount of wizardry you can do with the server config is limited only to your crazy ambitions.

ship it

Okay, so what have we actually done here? What we've done is that we've added a server declaration to nginx's configuration. When nginx runs, it slurps up all of the configuration files you have put into /etc/sites-enabled and uses those to know what to display to your viewers. But wait! if you stopped here, you might not be able to see your new server -- this is because nginx doesn't quite know about your new changes yet. To get nginx to know about your new configuration you need to reload nginx so that it can pull in your new configuration. The easiest way to do this is to run

service nginx reload

note: This service command actually just aliases to running the reload command on the configuration files that apt installed into your server's file system. In this example it aliases to /etc/init.d/nginx reload.

Another thing you may want to do is test your configurations to assure they are valid. To do this simply run, service nginx -t. (Thanks to Dustin for reminding us of this tip)

Then just visit your server's IP address again and you should see your shiny new page!

to conclude

Hope this was helpful, and if you have any questions, comments, or concerns, feel free to hit us up on twitter @carrotcreative and we'll do our best to answer. Next post in this short series will cover how to run a ruby or node app that's running on a specific port, so stay tuned! If you want us to go over another nginx topic, feel free to ask.