Repository navigation
nginx static runbook
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
-
/etc/nginx/nginx.conf-
global/letsencrypt.confrestrictions.conf
-
sites-availableresume.severin.jp
sites-enabled
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
/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;
}
For the full site configuration see the file /etc/nginx/sites-available/resume.severin.jp
Below I will explain each configuration part.
##
# 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
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;
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;
}
$ 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
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.
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
- Nginx documentation: serving static content
- HTTP Strict Transport Security (HSTS) and NGINX
- Nginx Beginner’s Guide
- Nginx Module ngx_http_limit_req_module
- https://gist.github.com/zhujunsan/a0becf82ade50ed06115
- https://developer.github.com/v3/guides/managing-deploy-keys/
- https://gist.github.com/jexchan/2351996