How to Host a Static Website with Nginx
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.