System administration for junior devs: Using NGINX to handle HTTP requests

by
(Photo credit: Herkie/Flickr)

In the [previous installment](http://sunlightfoundation.com/blog/2015/05/12/system-administration-for-junior-devs-setting-up-a-virtual-server-with-vagrant/) of this series, we created a networked virtual server that responded to `ping`, but we did not configure it to deal with HTTP requests (the type of requests browsers generally use to communicate to Web servers). In this post, we will take a networked Web server — i.e. one that responds to `ping` at a given IP — and make it respond to HTTP requests at that same IP. We will do this using [NGINX](http://nginx.org/en/docs/).

### Making sure your networked server is available

Assuming you followed along with the [previous tutorial](http://sunlightfoundation.com/blog/2015/05/12/system-administration-for-junior-devs-setting-up-a-virtual-server-with-vagrant/), you should have a networked server with the IP `192.168.33.11`. If not, you can run:

“`
git clone https://github.com/handlers/servers.git
cd servers
vagrant up
“`

Now, run `ping 192.168.33.11` to ensure that your computer can communicate with the virtual server.

### Why a networked server is not enough

Once your server is returning packets on `192.168.33.11`, try pasting that IP address into your browser’s URL bar. It probably does not work. In Chrome, you might see something like this:

>Google Chrome’s connection attempt to 192.168.33.11 was rejected. The website may be down, or your network may not be properly configured.

Your virtual server can respond to `ping`, but it can’t handle _Web requests_ gracefully. It is connected to the network, but not in the right way. If you plan to serve Web pages from that machine, you will need to change something.

For contrast, try pasting a Google IP address (`74.125.22.100`) in your browser’s address bar (you can get this number with `nslookup google.com`). It works! Clearly, Google’s servers have something going on that yours does not.

### Installing NGINX to handle HTTP requests

One difference between your server and Google’s is that their’s is running a program to handle HTTP requests. To make your server handle this type of request, you are going to install and configure a program called [NGINX](http://nginx.org/en/)1:

First, navigate to the directory in which you defined your virtual server (wherever your `Vagrantfile` is), then `ssh` into that server with `vagrant ssh`.

Once you are logged into your virtual machine, run `sudo apt-get install nginx`. This line uses the `apt-get` utility to install NGINX on your server. Note that we are now altering the basic server that was defined in the `Vagrantfile`.

Now, run `sudo nginx -s reload` and visit your [virtual server’s IP](http://192.168.33.11/) in your browser. You should see a screen that says “Welcome to nginx!” If you inspect the page’s source, you will see HTML, indicating that your server is now able to serve HTTP requests.

### Configuring NGINX to handle HTTP requests in a controlled way

Now that the server can _handle_ HTTP requests, you just have to configure the program that performs that task: NGINX. To do this, make sure you are still `ssh`ed into your virtual server, then `cd /etc/nginx`. This is where NGINX’s configuration lives.

Run `ls -al /etc/nginx/sites-enabled` and you will see a single default configuration file. Open this up in a text editor or run `cat /etc/nginx/sites-enabled/default` to see the heavily commented sample config inside:

“`

server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /usr/share/nginx/html;
index index.html index.htm;

# Make site accessible from http://localhost/
server_name localhost;

location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}

“`

In general, this server block:

* tells NGINX that the server configured in this block should [listen](http://nginx.org/en/docs/http/ngx_http_core_module.html#listen) on the standard port for HTTP requests: 80. If you visit the [server’s IP address](http://192.168.33.11/), you will see an HTTP response because the browser automatically makes HTTP requests on port 80. If you specify a different port (add a colon to your IP address and then a number like so: [http://192.168.33.11:83/](http://192.168.33.11:83/)), your Web request will fail, because NGINX is not configured to handle requests to that port;
* tells NGINX to use `/usr/share/nginx/html` as the [root directory](http://nginx.org/en/docs/http/ngx_http_core_module.html#root) for Web requests that this server block applies to;
* defines the default index files for the server block with the [`index` directive](http://nginx.org/en/docs/http/ngx_http_index_module.html#index);
* tells NGINX that this server block applies to HTTP requests with `localhost` in its [Host](http://en.wikipedia.org/wiki/List_of_HTTP_header_fields) header field2, using the `server_name` directive; and
* configures URLs that match the `/` location parameter to “first attempt to serve [the] request as [a] file, then as directory, then fall back to displaying a 404.”

In sum, this configuration will take incoming HTTP requests and look in the `root` directory (`/usr/share/nginx/html`) for matching files. If you run `cat /usr/share/nginx/html/index.html`, you will see the “Welcome to NGINX” page currently served at `192.168.33.11`.

If you edit the text of this file (`sudo nano /usr/share/nginx/html/index.html`) and refresh your browser, your changes should be visible.

### Serving your own project with NGINX

Now, instead of just editing NGINX’s default page, you will create a project on your server and then point NGINX to it.

First, you will need to create a very simple website that you want server visitors to see. Start by creating a directory for your site by running `sudo mkdir -p /var/www/simple-site`. Then navigate to your new project directory with `cd /var/www/simple-site` and `sudo -s` so that you can more easily run commands as root. Then, create a very simple `index.html` file by running `echo ‘

hello, world!

‘ > index.html`. You now have an extremely simple HTML project.

Second, you’ll need configure NGINX to point at your project. Open up your NGINX configuration in an editor with `nano /etc/nginx/sites-available/default`, then edit the server block to point to your project’s directory: `root /var/www/simple-site;`.

Finally, you need to restart NGINX for the changes to take effect: `nginx -s reload`.

If you go to your browser and visit `192.168.33.11` again, you should see your new homepage! So, we have gone from having a server that you can contact over the internet (via `ping`) to having a server that can respond to HTTP requests with HTML.

In the next installment, we will look at how to connect NGINX to a more complex web application through a program called [Unicorn](http://unicorn.bogomips.org/).

1 NGINX is not the only program that can do this. [Apache](http://httpd.apache.org/ABOUT_APACHE.html) and [lighttpd](http://www.lighttpd.net/) can also do the job.

2 If an incoming HTTP request does not match any `server_name` (as in our Web requests, whose Host header will just be the IP `192.168.33.11`), NGINX will fall back to the `default_server`.