Skip to content

nginx static runbook

Severin FERRAND edited this page Oct 24, 2018 · 15 revisions

Overview

In this section I will explain how to configure nginx for serving static content Nginx 1.10.x This is a simple setup I use for serving my resume.

Since this is a bit too simple we will also add the following content:

  • HTTPS (SSL) configuration
  • Resource Deployment from Git using deployment keys

As of October 2017, this configuration passed the Qualys SSL test with A+ https://www.ssllabs.com/ssltest/analyze.html?d=pi.resume.severin.jp

Prerequisites

Configuration Files

  • /etc/nginx/
    • nginx.conf
    • global/
      • letsencrypt.conf
      • restrictions.conf
    • sites-available
      • resume.severin.jp
    • sites-enabled

Serving directories

I am serving my files from /web directory with a sub-directory for each of my website. For my resume i will use resume.severin.jp . Let's create directories:

www directory for content: sudo mkdir -p /web/resume.severin.jp/www/

logs directory for logs: sudo mkdir -p /web/resume.severin.jp/logs/

I change the owner to www-data to allow nginx to read/write files:

$ sudo chown -R www-data:www-data /web/resume.severin.jp/

Change permissions to 750, if you have properly added your user to www-data then you should be able to see content of directory:

$ sudo chmod -R 750 /web/resume.severin.jp/
drwxr-x--- 4 www-data www-data 4096  9月 28 20:59 resume.severin.jp

Main (generic) startup file

/etc/nginx/nginx.conf

Global restrictions file

/etc/nginx/global/restrictions.conf

# Global restrictions configuration file.
# Designed to be included in any server {} block.</p>
location = /favicon.ico {
	log_not_found off;
	access_log off;
}

location = /robots.txt {
	allow all;
	log_not_found off;
	access_log off;
}

# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
	deny all;
}

Virtual Server Configuration (for my website resume.severin.jp)

For the full site configuration see the file /etc/nginx/sites-available/resume.severin.jp

Below I will explain each configuration part.

HTTPS Virtual Server Configuration

##
# Root Site : HTTPS : resume.severin.jp
##
server {

        listen	443 ssl default_server; ## listen for ipv4; this line is default and implied
        #listen   [::]:443 default_server ipv6only=on; ## listen for ipv6

        # Get SSL setup
        ssl                 on;
        ssl_certificate     /etc/letsencrypt/live/pi.severin.jp/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/pi.severin.jp/privkey.pem;
	ssl_session_timeout 5m;
        ssl_session_cache         shared:SSL:50m;

 	# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
 	# Generate with:
 	#   openssl dhparam -out /etc/nginx/dhparam.pem 2048
	ssl_dhparam /etc/nginx/dhparam.pem;
        
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
	ssl_ciphers	'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        ssl_prefer_server_ciphers on;

	# Enable HSTS ( see http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security ) (ngx_http_headers_module is required) (15768000 seconds = 6 months)
        #add_header Strict-Transport-Security max-age=15768000;
	add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

        # OCSP Stapling
        ssl_stapling            on;
        ssl_stapling_verify     on;
        ssl_trusted_certificate /etc/letsencrypt/live/pi.severin.jp/fullchain.pem;
        resolver                8.8.8.8;

	### NOW CONFIGURE YOUR SITE BELOW

        root /web/resume.severin.jp/www;
        index index.html index.htm;

        # Make site accessible from http://mysite.com.local/
        server_name resume.severin.jp.local resume.severin.jp pi.resume.severin.jp;

        # add log configuration
        error_log /web/resume.severin.jp/logs/error.log error;
        access_log /web/resume.severin.jp/logs/access.log;

        # include global files for php wordpress
        include global/restrictions.conf;

        # include global file for LetsEncrypt
        include global/letsencrypt.conf;
	
	#error_page 404 /404.html;

	# location directices
	
	# try url with and without trailing slash, try to append .html to find html files
	location / {
    		try_files $uri $uri/ $uri.html =404;
	}

	# Directives to send expires headers and turn off 404 error logging.
	location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
		expires 24h;
		log_not_found off;
	}

}

If you have not yet generated the SSL Certificates, I am explaining how to get SSL Certificate in letsencrypt-runbook

Enabling HTTP Strict Transport Security (HSTS)

Based on HTTP Strict Transport Security (HSTS) and NGINX documentation , I specified in my virtual server block:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Redirect HTTP to HTTPS

I don’t want users to access content over HTTP. Instead, I want to redirect all HTTP requests on severin.jp subdomains to use HTTPS.

in the listen port default_server means that we set explicitly which server should be default. See How nginx processes a request for more information

# REDIRECT HTTP TO HTTPS and set default server for listen port
server {
    listen 80 default_server;
    #listen [::]:80 default_server; ## no IPv6 at this time
    server_name *.severin.jp;

    # Discourage deep links by using a permanent redirect to home page of HTTPS site
    return 301 https://$host;

    # Alternatively, redirect all HTTP links to the matching HTTPS page
    return 301 https://$host$request_uri;
}

Enable Virtual Server

$ sudo ln -s /etc/nginx/sites-available/resume.severin.jp /etc/nginx/sites-enabled/

Check configuration file:

sudo nginx -t

then reload nginx

sudo service nginx reload

Website Deployment from GitHub repository

Configure deployment keys

I want to be able to deploy website content using www-data user, so we will assign a Github SSH deployment key to www-data and configure this Deploy key in the repository containing our website resources.

based on documentation fro https://gist.github.com/zhujunsan/a0becf82ade50ed06115

First generate a key from my user:

$ ssh-keygen -t rsa -b 4096 -C "deploy@severin.jp"

saved as .ssh/git_deploy_id_rsa

Create a config file for ssh client under ~/.ssh/config

Host github.com
	HostName github.com
	User git
	IdentityFile ~/.ssh/git_deploy_id_rsa

Then copy the config to www-data home directory under ~/.ssh (see cat /etc/passwd if you don't know where www-data home dir is located. In my case this is /home/www-data/)

$ sudo mkdir /home/www-data/.ssh
$ sudo cp git_deploy_id_rsa* /home/www-data/.ssh/
$ sudo cp config /home/www-data/.ssh/
$ sudo chown -R www-data:www-data /home/www-data/.ssh
$ ll /home/www-data/.ssh/

Private key git_deploy_id_rsa should have a 600 permission :

total 12
-rw-r--r-- 1 www-data www-data   87  9月 28 22:14 config
-rw------- 1 www-data www-data 3243  9月 28 22:14 git_deploy_id_rsa
-rw-r--r-- 1 www-data www-data  743  9月 28 22:14 git_deploy_id_rsa.pub

we can now confirm :

$ sudo -u www-data ssh -T git@github.com

we should get a successfully authenticated message :

The authenticity of host 'github.com (192.30.255.112)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,192.30.255.112' (RSA) to the list of known hosts.
Hi Seburan/resume! You've successfully authenticated, but GitHub does not provide shell access.

Deploy content

Well this is pretty straightforward, in just one command:

Initial deploy, i am cloning the repository:

$ sudo -u www-data git clone git@github.com:Seburan/resume.git /web/resume.severin.jp/www/

Further deploy, I will pull the content:

$  cd /web/resume.severin.jp/www/
$  sudo -u www-data git pull

See Also

References

Clone this wiki locally