Introduction

Nginx is one of the most popular web servers in the world and is responsible for hosting some of the largest and highest-traffic sites on the internet. It is more resource-friendly than Apache in most cases and can be used as a web server or a reverse proxy.

This tutorial describes a fast way to setup nginx server, configuring the server for better performance and adding the ssl layer (https connection).

Prerequisites

I assume that you already have read my first tutorial, so you know how to login to your server via ssh not withroot, create and edit files with vim and use root privileges with sudo.

Contents

This tutorial includes these three parts:

  1. Setting up nginx with server blocks (essential)
  2. Configuring nginx for better performance (recommended)
  3. Adding free SSL cert (https) for your site (optional)

Let’s start with installing nginx and setting up server blocks.

1. Setting up nginx with server blocks (essential)

Install nginx

Nginx is available in Ubuntu's default repositories, so the installation is rather straightforward.

Since this is our first interaction with the apt packaging system in this session, we will update our local package index so that we have access to the most recent package listings. Afterwards, we can install nginx:


sudo apt update
sudo apt install nginx

Adjust the Firewall

Before we can test Nginx, we need to reconfigure our firewall software to allow access to the service. Nginx registers itself as a service with ufw, our firewall, upon installation. This makes it rather easy to allow Nginx access.

We can list the applications configurations that ufw knows how to work with by typing:


sudo ufw app list

You should get a listing of the application profiles:

Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

As you can see, there are three profiles available for Nginx:

+ **Nginx Full**: This profile opens both port 80 (normal, unencrypted web traffic) and port 443 (TLS/SSL encrypted traffic)
+ **Nginx HTTP**: This profile opens only port 80 (normal, unencrypted web traffic)
+ **Nginx HTTPS**: This profile opens only port 443 (TLS/SSL encrypted traffic)

It is recommended that you enable the most restrictive profile that will still allow the traffic you've configured. Since we haven't configured SSL for our server yet, in this guide, we will only need to allow traffic on port 80.

You can enable this by typing:


sudo ufw allow 'Nginx HTTP'

You can verify the change by typing:


sudo ufw status

You should see HTTP traffic allowed in the displayed output:

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

Check your Web Server

At the end of the installation process, Ubuntu 16.04 starts Nginx. The web server should already be up and running.

We can check with the systemd init system to make sure the service is running by typing:


systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2016-04-18 16:14:00 EDT; 4min 2s ago
 Main PID: 12857 (nginx)
   CGroup: /system.slice/nginx.service
           ├─12857 nginx: master process /usr/sbin/nginx -g daemon on; master_process on
           └─12858 nginx: worker process

As you can see above, the service appears to have started successfully. However, the best way to test this is to actually request a page from Nginx.

You can access the default Nginx landing page to confirm that the software is running properly. You can access this through your server's domain name or IP address.

If you do not have a domain name set up for your server, you can learn how to set up a domain with DigitalOcean.

If you do not want to set up a domain name for your server, you can use your server's public IP address. If you do not know your server's IP address, you can get it a few different ways from the command line.

Try typing this at your server's command prompt:


ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'

You will get back a few lines. You can try each in your web browser to see if they work.

When you have your server's IP address or domain, enter it into your browser's address bar:

http://server_domain_or_IP

You should see the default Nginx landing page, which should have a heading like: “Welcome to nginx!”.

This page is simply included with Nginx to show you that the server is running correctly.

Manage the Nginx Process

Now that you have your web server up and running, we can go over some basic management commands.

There are several commands which you can use to manage your web server:

  1. start - starts the web server if it’s stopped and config is OK
  2. stop - stops the web server
  3. restart - stops and then starts the web server
  4. reload - reloads configs
  5. enable - sets nginx to start when server boots; nginx is enabled by default
  6. disable - sets nginx not to start at server boot.

You should use these commands in this way:


sudo systemctl start nginx

To test your nginx config before reload use


sudo nginx -t

If your server fails to start due to misconfiguration see last lines (command G in vim) of /var/log/nginx/error.log file.

Get Familiar with Important Nginx Files and Directories

Now that you know how to manage the service itself, you should take a few minutes to familiarize yourself with a few important directories and files.

Content

  • /var/www/html: The actual web content, which by default only consists of the default Nginx page you saw earlier, is served out of the /var/www/html directory. This can be changed by altering Nginx configuration files.

Server Configuration

  • /etc/nginx: The nginx configuration directory. All of the Nginx configuration files reside here.

  • /etc/nginx/nginx.conf: The main Nginx configuration file. This can be modified to make changes to the Nginx global configuration.

  • /etc/nginx/sites-available/: The directory where per-site "server blocks" can be stored. Nginx will not use the configuration files found in this directory unless they are linked to the sites-enabled directory (see below). Typically, all server block configuration is done in this directory, and then enabled by linking to the other directory.

  • /etc/nginx/sites-enabled/: The directory where enabled per-site "server blocks" are stored. Typically, these are created by linking to configuration files found in the sites-available directory.

  • /etc/nginx/snippets: This directory contains configuration fragments that can be included elsewhere in the Nginx configuration. Potentially repeatable configuration segments are good candidates for refactoring into snippets.

Server Logs

  • /var/log/nginx/access.log: Every request to your web server is recorded in this log file unless Nginx is configured to do otherwise.
  • /var/log/nginx/error.log: Any Nginx errors will be recorded in this log.

Set Up Nginx Server Blocks (Virtual Hosts)

When using the Nginx web server, server blocks (similar to the virtual hosts in Apache) can be used to encapsulate configuration details and host more than one domain off of a single server.

Example Configuration

For demonstration purposes, we're going to set up two domains with our Nginx server. The domain names we'll use in this guide are example.com and test.com.

Set Up New Document Root Directories

By default, Nginx on Ubuntu 16.04 has one server block enabled by default. It is configured to serve documents out of a directory at /var/www/html.

We will create a directory structure within /var/www for each of our sites. The actual web content will be placed in an html directory within these site-specific directories. This gives us some additional flexibility to create other directories associated with our sites as siblings to the html directory if necessary.

We need to create these directories for each of our sites. The -p flag tells mkdir to create any necessary parent directories along the way:


sudo mkdir -p /var/www/example.com/html
sudo mkdir -p /var/www/test.com/html

Now that we have our directories, we will reassign ownership of the web directories to our normal user account. This will let us write to them without sudo.

Note: Depending on your needs, you might need to adjust the permissions or ownership of the folders again to allow certain access to the www-data user. For instance, dynamic sites will often need this. The specific permissions and ownership requirements entirely depend on what your configuration. Follow the recommendations for the specific technology you're using.

We can use the $USER environmental variable to assign ownership to the account that we are currently signed in on (make sure you're not logged in as root). This will allow us to easily create or edit the content in this directory:


sudo chown -R $USER:www-data /var/www/example.com/html
sudo chown -R $USER:www-data /var/www/test.com/html

The permissions of our web roots should be correct already if you have not modified your umask value, but we can make sure by typing:


sudo chmod -R 755 /var/www

Our directory structure is now configured and we can move on.

Create Sample Pages for Each Site

Now that we have our directory structure set up, let's create a default page for each of our sites so that we will have something to display.

Create an index.html file in your first domain:


vim  /var/www/example.com/html/index.html

Inside the file, we'll create a really basic file that indicates what site we are currently accessing. It will look like this:

<html>
    <head>
        <title>Welcome to Example.com!</title>
    </head>
    <body>
        <h1>Success!  The example.com server block is working!</h1>
    </body>
</html>

Since the file for our second site is basically going to be the same, we can copy it over to our second document root like this:


cp /var/www/example.com/html/index.html /var/www/test.com/html/

Modify it so that it refers to our second domain:

<html>
    <head>
        <title>Welcome to Test.com!</title>
    </head>
    <body>
        <h1>Success!  The test.com server block is working!</h1>
    </body>
</html>

Create Server Block Files for Each Domain

Now that we have the content we wish to serve, we need to actually create the server blocks that will tell Nginx how to do this.

By default, Nginx contains one server block called default which we can use as a template for our own configurations. We will begin by designing our first domain's server block, which we will then copy over for our second domain and make the necessary modifications.

Create the First Server Block File

Copy and open the new file you created in your text editor with sudo privileges


sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com
sudo vim /etc/nginx/sites-available/example.com

Ignoring the commented lines, the file will look similar to this:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }
}

First, we need to look at the listen directives. Only one of our server blocks on the server can have the default_server option enabled. This specifies which block should serve a request if the server_name requested does not match any of the available server blocks. This shouldn't happen very frequently in real world scenarios since visitors will be accessing your site through your domain name.

You can choose to designate one of your sites as the "default" by including the default_server option in the listen directive, or you can leave the default server block enabled, which will serve the content of the /var/www/html directory if the requested host cannot be found.

In this guide, we'll leave the default server block in place to server non-matching requests, so we'll remove the default_server from this and the next server block. You can choose to add the option to whichever of your server blocks makes sense to you.

server {
        listen 80;
        listen [::]:80;

        . . .
}

Note: You can check that the default_server option is only enabled in a single active file by typing:


grep -R default_server /etc/nginx/sites-enabled/

If matches are found uncommented in more than one file (shown in the leftmost column), Nginx will complain about an invalid configuration.

The next thing we're going to have to adjust is the document root, specified by the root directive. Point it to the site's document root that you created:

server {
        listen 80;
        listen [::]:80;

        root /var/www/example.com/html;

}

Next, we need to modify the server_name to match requests for our first domain. We can additionally add any aliases that we want to match. We will add a www.example.com alias to demonstrate.

When you are finished, your file will look something like this:

server {
        listen 80;
        listen [::]:80;

        root /var/www/example.com/html;
        index index.html index.htm index.nginx-debian.html;

        server_name example.com www.example.com;

        location / {
                try_files $uri $uri/ =404;
        }
}

That is all we need for a basic configuration. Save and close the file to exit.

Create the Second Server Block File

Now that we have our initial server block configuration, we can use that as a basis for our second file. Copy it over to create a new file and open for editing:


sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com
sudo vim /etc/nginx/sites-available/example.com

Again, make sure that you do not use the default_server option for the listen directive in this file if you've already used it elsewhere. Adjust the root directive to point to your second domain's document root and adjust the server_name to match your second site's domain name (make sure to include any aliases).

When you are finished, your file will likely look something like this:

server {
        listen 80;
        listen [::]:80;

        root /var/www/test.com/html;
        index index.html index.htm index.nginx-debian.html;

        server_name test.com www.test.com;

        location / {
                try_files $uri $uri/ =404;
        }
}
Enable your Server Blocks and Restart Nginx

Now that we have our server block files, we need to enable them. We can do this by creating symbolic links from these files to the sites-enabled directory, which Nginx reads from during startup.

We can create these links by typing:


sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/test.com /etc/nginx/sites-enabled/

These files are now in the enabled directory. We now have three server blocks enabled, which are configured to respond based on their listen directive and the server_name (you can read more about how Nginx processes these directives here):
+ example.com: Will respond to requests for example.com and www.example.com
+ test.com: Will respond to requests for test.com and www.test.com
+ default: Will respond to any requests on port 80 that do not match the other two blocks.

In order to avoid a possible hash bucket memory problem that can arise from adding additional server names, we will go ahead and adjust a single value within our /etc/nginx/nginx.conf file. Open the file now:


sudo vim /etc/nginx/nginx.conf

Within the file, find the server_names_hash_bucket_size directive. Remove the # symbol to uncomment the line:

http {
    . . .

    server_names_hash_bucket_size 64;

    . . .
}

Next, test to make sure that there are no syntax errors in any of your Nginx files:


sudo nginx -t

If no problems were found, restart Nginx to enable your changes:


sudo systemctl restart nginx

Nginx should now be serving both of your domain names.

Modify Your Local Hosts File for Testing (Optional)

If you have not been using domain names that you own and instead have been using dummy values, you can modify your local computer's configuration to let you to temporarily test your Nginx server block configuration.

This will not allow other visitors to view your site correctly, but it will give you the ability to reach each site independently and test your configuration. This basically works by intercepting requests that would usually go to DNS to resolve domain names. Instead, we can set the IP addresses we want our local computer to go to when we request the domain names.

to be continued...