Hosting a static website with nginx

by @ralfebert · updated June 26, 2021

This is my recipe for configuring a static website on Debian 10:

Requirements

For this tutorial you need to have good knowledge of Linux server administration using a command line shell.

USE THIS ARTICLE AT YOUR OWN RISK: None of the authors, in any way whatsoever, can be responsible for your use of the information contained in these web pages. Do not rely upon any information found here without independent verification.

Setting up nginx

  1. I recommend using a DigitalOcean VM - works fine for many years for myself now (if you use this link, you'll get $100 in credit so you can set up a VM for free).

  2. Create a new droplet and select Debian 10 x64 as Image (Ubuntu should work the same but I didn't test it). Also select the size for your droplet (warning: you can easily upgrade to larger sizes, but it is not possible to downgrade to a size with a smaller disk):

    Create a DigitalOcean droplet
  3. Add an SSH key for logging in to your server without a password:

    Add SSH Key

    If you don't have used SSH keys before, check out the guide How To Use SSH Keys with DigitalOcean Droplets.

  4. Create the Droplet and wait for the VM to be created, then log-in to the system:

    ssh root@serverip
    
  5. Update all packages:

    apt update && apt upgrade
    
  6. Enable the firewall so that unconfigured services will not be exposed (the IP ranges of VM providers are frequently scanned for not fully configured servers):

    apt install ufw && ufw allow 22 && ufw logging off && ufw enable && ufw status
    

    The firewall rules are automatically saved and restored on reboot.

  7. Install the following required packages:

    apt install nginx certbot python3-certbot-nginx
    
  8. Edit the nginx default configuration:

    nano /etc/nginx/sites-enabled/default
    

    to return a 404 error by default. This will apply when a request with an unknown domain name if requested.

    server {
    	# return 404 both via IPv4/6 when no other configuration handles the host
    	# '[::]:80' is neccessary for IPv6 - see https://serverfault.com/a/842515
    	listen 80 default_server;
    	listen [::]:80 default_server;
    	return 404;
    }
    

Setting up HTTP

  1. The following steps assume you're setting up a site example.com. For every site a separate user is used.

    At first, create a new user for the site:

    SITE_NAME=www-example
    adduser $SITE_NAME --disabled-password --gecos ""
    
  2. Add your SSH public key to the user home so you can log-in as the app user.

    To copy the SSH keys from root to the user:

    mkdir /home/$SITE_NAME/.ssh
    cp ~/.ssh/authorized_keys /home/$SITE_NAME/.ssh/
    chown $SITE_NAME.$SITE_NAME /home/$SITE_NAME/.ssh -R
    chmod go-rwx /home/$SITE_NAME/.ssh -R
    
  3. Log-out and log-in as the app user:

    ssh www-example@serverip
    
  4. Create a directory public and create an index.html page:

    mkdir public
    echo "Hello world" > public/index.html
    
  5. Switch back to the root user and create a configuration file for the site:

    nano /etc/nginx/sites-available/www-example
    

    Example configuration as a starting point (here a forward from www.example.com -> example.com is configured as well):

    server {
        listen 80;
        listen [::]:80;
        server_name example.com;
    
        root        /home/www-example/public;
        charset     utf-8;
    
        location / {
        }
    }
    
    server {
        listen 80;
        listen [::]:80;
        server_name www.example.com;
    
        return      301 http://example.com$request_uri;
    }
    
  6. Enable the site configuration:

    ln -s /etc/nginx/sites-available/www-example /etc/nginx/sites-enabled/www-example
    
  7. Reload nginx if the nginx configuration is valid:

    nginx -t && systemctl reload nginx
    
  8. Enable port 80 in the firewall:

    ufw allow 80
    
  9. Check accessing the site using HTTP using the domain name (assuming you changed the DNS entry already, otherwise you could temporarily add it to your /etc/hosts file):

    curl -L http://www.example.com
    curl -L http://example.com
    

Setting up HTTPs

  1. On Debian, out of the box, adding SSH certificates to a domain works fully automated via the certbot package, including automatic certicate renewal:

    certbot --nginx
    

    This will ask for which domains certificates should be created. It will then update the site configuration accordingly and also set up a HTTP -> HTTPs redirect.

  2. Allow HTTPs in the firewall:

    ufw allow 443
    
  3. Reload the nginx configuration:

    nginx -t && systemctl reload nginx
    
  4. Test accessing your site via http and https:

    curl -L http://example.com/
    curl -L http://www.example.com/
    curl -L https://example.com/
    curl -L https://www.example.com/