How to Host a Static Website with Nginx

in #tutorial7 years ago

Static site generators are a fantastic way to manage a website. Static sites are faster and safer than dynamic sites. They can be easily generated by a wide variety of static site generators. My favorite is Hugo. Nginx is an ideal web server for serving these static files. In this tutorial we will set up a server and optimize it for serving our static site.

This server is going to be optimized for static sites. I recommend keeping your static websites and your dynamic websites on separate systems. In the long run, this separation will save time and frustration, VPSs are super cheap. I recommend Linode and I do so without an affiliate code.

This guide assumes that you already have a properly configured remote server. If you need help setting up a basic server, check out Setting Up a Basic Server with Ubuntu 16.04. This guide is intended for and has been tested on Ubuntu 16.04.

Install

Install Nginx web server.

sudo apt-get install nginx

Controlling Nginx

The following commands will help you control Nginx.

This will start Nginx

sudo systemctl start nginx

To stop Nginx

sudo systemctl stop nginx

To restart Nginx

sudo systemctl restart nginx

To reload Nginx configurations.

sudo systemctl reload nginx

Firewall

Your server should be running a firewall. I recommend the Uncomplicated Firewall (UFW). If you need help with UFW, check out, A Guide to the Uncomplicated Firewall (UFW) for Linux. The following command will allow HTTP and HTTPs traffic.

sudo ufw allow 'Nginx HTTP'

Then we need to reload the firewall rules.

sudo ufw reload

If you are using another firewall and don't know how to allow HTTP or HTTPS traffic, then you should consider switching to UFW. Firewalls are too import to be convoluted. UFW allows mere mortals to create firewall rules.

Verify

At this point, we should verify that the server is operational. Visit your servers IP address in a web browser. You should be greeted by a generic Nginx info screen from the default site. If that does not happen then something when wrong.

Make a Dummy Site

I want to serve files from a directory within my home directory. This directory will be called www.

cd ~
mkdir www

In this new directory we will make a dummy index.html page.

nano ~/www/index.html

Inside just put anything. We don't need actual html, just something kinda unique.

Welcome to test.jasonrigden.com. This is the dummy index page.

Now we need to change the www directory permissions. This will allow Nginx to access the files.

chmod 0755  ~/www

Nginx Configuration Directory

Let's enter the directory containing the Nginx configuration files.

cd /etc/nginx

ls this directory to take a look around. In this tutorial we only care about a couple files and directories. The file nginx.conf is the central configuration file for our Nginx instance. The sites-available and sites-enabled directories contain the site specific configuration files.

nginx.conf

It is a good practice to make backups of configuration files before editing them. Make a backup of of nginx.conf.

sudo cp nginx.conf OLD.nginx.conf

Now open up the primary Nginx configuration file and take look around.

sudo nano nginx.conf

First of all, lines starting with a # are comments and are ignored by Nginx. Directives need to end with a semicolon ;. Configuration is organized into blocks such as http, server, location. Nginx configuration files can also include other files. If l you look near the bottom of the http block you should see a line, include /etc/nginx/sites-enabled/*;. The configuration files in the sites-enabled will be included as part of the Nginx configuration. The sites-enabled will be where our website specific settings files will be. The nginx.conf will be where the server wide settings will be.

sites-available

Enter the sites-available directory.

cd sites-available

Generally speaking, the sites-available directory contains configuration files for individual websites. Let's take a look at the default configuration file.

sudo nano default

In this file you should see more blocks. Look for the server and location blocks. Exit nano and then copy this default file. Let's make a new configuration file for a new website. I would name the new file for the domain you will be using. In my case that is jasonrigden.com.

sudo nano test.jasonrigden.com

This will be the site specific configuration file for the website at test.jasonrigden.com. Edit the file and change the values as appropriate.

server {
        listen 80;
        server_name test.jasonrigden.com;
        root /home/jason/www;
        index index.html;
}

Nginx needs to know a few things before it can actually start serving up web pages. Notice that our settings will live in a server block. We tell Nginx to listen for connections on port 80. That this server block is for the domain test.jasonrigden.com. That the files to server are located at /home/jason/www.

Remember earlier when we talked about included configuration files? Configuration files in the sites-enabled directory will be included in our Nginx instance. Create a symbolic link for the configuration files we want to enable.

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

Then restart the Nginx server.

sudo systemctl restart nginx

Check to see if the sites is up.

curl test.jasonrigden.com

Which should return the contents of the index.html that we made earlier.

Welcome to test.jasonrigden.com. This is the dummy index page.

It works

At this point we have a working website. All you need now is to have your static site generator output to /home/jason/www. Anything in that folder will be served by the Nginx. The next few sections will cover various optional features and optimizations that you can choose.

Logs

Writing web logs takes resources. If you want to save these resources, disable logging. Open up the main Nginx configuration file.

sudo nano /etc/nginx/nginx.conf

Find the logging section.

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

Comment out the access_log and the error_log.

##
# Logging Settings
##

#access_log /var/log/nginx/access.log;
#error_log /var/log/nginx/error.log;

Client Side Caching

Telling our clients to cache resources like js, css, and images files can significantly improve performance. I like to use the a shortened version of the rules from H5BP's server-configs-nginx.

# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
  access_log off;
  add_header Cache-Control "max-age=2592000";
}


# CSS and Javascript
location ~* \.(?:css|js)$ {
  add_header Cache-Control "max-age=31536000";
  access_log off;
}

These rules can be added to your site configuration file.

sudo nano /etc/nginx/sites-available/test.jasonrigden.com

Is should look something similar to this.

server {
        listen 80;
        server_name test.jasonrigden.com;
        root /home/jason/www;
        index index.html;
}

Add the caching rules to the end of the block.

server {
        listen 80;
        server_name test.jasonrigden.com;
        root /home/jason/www;
        index index.html;
        
        # Media: images, icons, video, audio, HTC
        location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
          access_log off;
          add_header Cache-Control "max-age=2592000";
        }

        # CSS and Javascript
        location ~* \.(?:css|js)$ {
          add_header Cache-Control "max-age=31536000";
          access_log off;
        }
}

Pre-compression

Compression should be already be activated by default on your server. We can save server resources and get higher compression levels with by pre-compressing our files. We will enable pre-compressed files by editing the main Nginx configuration file.

sudo nano /etc/nginx/nginx.conf

Find the section:

##
# Gzip Settings
##

gzip on;

And just add gzip_static on;.

##
# Gzip Settings
##
gzip_static on;
gzip on;

Then restart the Nginx server.

sudo systemctl restart

Our example index.html from earlier will not really benefit from compression. But, we will do it anyhow for the sake of the demonstration.

gzip -v -k -f --best index.html

-v is for verbose, -k is for keeping the original file, -f is to overwrite any older zipped file with the same name, and --best is for the best compression. Your static site generator will probably have an option for pre-compression. Check the documentation.

HTTPS

Properly enabling encryption in your web server used to be terrible. Signed certificates were expensive and the setup was complicated. Our friends at the EFF and Let's Encrypt fixed that. We are no longer beholden to the corrupt and frequently incompetent certificate authority cartel. Signed certificates are now available free from Let's Encrypt. And the certbot program sets up the server for us.

Install certbot.

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

Run certbot.

sudo certbot --nginx

This should bring up a dialog.

    Which names would you like to activate HTTPS for?
    -------------------------------------------------------------------------------
    1: jasonrigden.com
    2: cryotek.jasonrigden.com
    3: test.jasonrigden.com
    -------------------------------------------------------------------------------
    Select the appropriate numbers separated by commas and/or spaces, or leave input
    blank to select all options shown (Enter 'c' to cancel): 

On my server I have a couple of sites. Select the site you would like to activate HTTPS for. After making your selection, certbot will do some work and then ask if you would like to redirect traffic to HTTPS.

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 

I would choose to redirect. If all goes well, you will see a congratulations message.

Then restart the Nginx server.

sudo systemctl restart nginx

Visit the site with your browser. If you chose to redirect you will automatically be sent to the HTTPS version of the site.

Certificates must be renewed or the will expire. The following command will do this. Add it to your crontab to run regularly.

sudo certbot renew

Enable HTTP/2

HTTP/2 is a major improvement for the web. It can give you a large improvement in client performance. You will need to have enabled HTTS for HTTP/2. Open up the configuration file for test.jasonrigden.com.

sudo nano /etc/nginx/sites-available/test.jasonrigden.com

You will see certbot has done some editing. Find the listen line.

listen 443 ssl; 

change that to:

listen 443 ssl http2;  

Then restart the Nginx server.

sudo systemctl restart nginx

Conclusion

You now have an web server optimized for serving static content.