Skip to content

Instantly share code, notes, and snippets.

@inetbiz
Forked from paskal/site.conf
Last active March 25, 2023 18:56
Show Gist options
  • Save inetbiz/a07ba3bdbc7ee392020eec811ed02c08 to your computer and use it in GitHub Desktop.
Save inetbiz/a07ba3bdbc7ee392020eec811ed02c08 to your computer and use it in GitHub Desktop.
Nginx configuration for best security and modest performance. Full info on https://terrty.net/2014/ssl-tls-in-nginx/
# read more at https://terrty.net/2014/ssl-tls-in-nginx/
# latest version on https://gist.github.com/paskal/628882bee1948ef126dd/126e4d1daeb5244aacbbd847c5247c2e293f6adf
# security test score: https://www.ssllabs.com/ssltest/analyze.html?d=terrty.net
# your nginx version might not have all directives included, test this configuration before using in production against your nginx:
# $ nginx -c /etc/nginx/nginx.conf -t
server {
# public key, contains your public key and class 1 certificate, to create:
# (example for startssl)
# $ (cat example.com.pem & wget -O - https://www.startssl.com/certs/class1/sha2/pem/sub.class1.server.sha2.ca.pem) | tee -a /etc/nginx/ssl/domain.pem > /dev/null
ssl_certificate /etc/nginx/ssl/domain.pem;
# private key (decoded), decode encoded with RSA key with command:
# $ openssl rsa -in decoded.key -out domain.key
ssl_certificate_key /etc/nginx/ssl/domain.key;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
# to generate your dhparam.pem file, run in the terminal:
# $ openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# don't forget to set secure rights to these files:
# $ chmod 400 /etc/nginx/ssl/*
# http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_cache
# make it bigger for more sessions, one megabyte for ~ 4000 session
ssl_session_cache shared:SSL:100m;
ssl_session_timeout 60m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ciphers are latest modern from https://wiki.mozilla.org/Security/Server_Side_TLS (only place you can trust on web)
# working example:
# ssl_ciphers 'EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DES';
ssl_ciphers '<paste intermediate ciphersuite here>';
ssl_prefer_server_ciphers on;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
# dns resolver, we're using Google IPv4 and IPv6 servers
resolver 8.8.8.8 [2001:4860:4860::8888];
# verify chain of trust of OCSP response using Root CA and Intermediate certs, example for StartSSL:
# $ wget -O - https://www.startssl.com/certs/ca.pem https://www.startssl.com/certs/class1/sha2/pem/sub.class1.server.sha2.ca.pem | tee -a ca-certs.pem > /dev/null
ssl_trusted_certificate /etc/nginx/ssl/root_CA_cert_plus_intermediates;
# consider turning 'deferred' off on old versions of nginx if you occur any problems
listen 443 deferred http2 ssl;
listen [::]:443 deferred http2 ssl ipv6only=on;
server_name example.com;
root /var/local/www/example;
index index.html;
autoindex off;
charset utf-8;
#don't send the nginx version number in error pages and Server header
server_tokens off;
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
# http://nginx.org/en/docs/http/ngx_http_headers_module.html
# enabling HSTS(HTTP Strict Transport Security)
# https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# enabling Public Key Pinning Extension for HTTP (HPKP)
# https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning
# tool for checking and generating proper certificates: https://report-uri.io/home/tools
# to generate use on of these:
# $ openssl rsa -in my-website.key -outform der -pubout | openssl dgst -sha256 -binary | base64
# $ openssl req -in my-website.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64
# $ openssl x509 -in my-website.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64
add_header Public-Key-Pins 'pin-sha256="base64+info1="; max-age=31536000' always;
# config to don't allow the browser to render the page inside an frame or
# iframe and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
# if you need to allow [i]frames, you can use SAMEORIGIN
# or set an uri with ALLOW-FROM uri
# warning, this option breaking some analitics tools
add_header X-Frame-Options DENY;
# when serving user-supplied content, include a
# X-Content-Type-Options: nosniff header along with the Content-Type:
# header to disable content-type sniffing on some browsers.
# https://github.com/blog/1482-heads-up-nosniff-header-support-coming-to-chrome-and-firefox
add_header X-Content-Type-Options nosniff;
# this header enables the Cross-site scripting (XSS) filter, it's usually
# enabled by default anyway, so the role of this header is to re-enable
# the filter for this particular website if it was disabled by the user.
add_header X-XSS-Protection "1; mode=block";
location / {
# try_files might be dangerous, please read: http://blog.volema.com/nginx-insecurities.html
try_files $uri $uri/ =404;
}
# deny access to files, starting with dot (hidden) or ending with ~ (temp)
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
location ~ ~$ {
access_log off;
log_not_found off;
deny all;
}
# block of rules for static content
location ~ /(favicon.ico|favicon.png|robots.txt)$ {
access_log off;
log_not_found off;
expires 1y;
add_header Cache-Control public,max-age=259200;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|mp3)$ {
expires 30d;
add_header Cache-Control public,max-age=259200;
}
}
server {
# catch all unsecure requests (both IPv4 and IPv6)
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
# this means example.com, *.example.com
server_name .example.com;
# permanently redirect client to https version of the site
return 301 https://example.com;
}
@biinari
Copy link

biinari commented Jan 13, 2021

Thanks @inetbiz !

While we're at it, it would be nice if you could change spdy to http2 on the listen lines (for current versions of nginx since 1.9.5)

and the braces {} to () in:

        location ~ /(favicon.ico|favicon.png|robots.txt)$ {

@inetbiz
Copy link
Author

inetbiz commented Jan 14, 2021

Thanks @inetbiz !

While we're at it, it would be nice if you could change spdy to http2 on the listen lines (for current versions of nginx since 1.9.5)

and the braces {} to () in:

        location ~ /(favicon.ico|favicon.png|robots.txt)$ {

https://gist.github.com/inetbiz/a07ba3bdbc7ee392020eec811ed02c08#file-site-conf-L47 and https://gist.github.com/inetbiz/a07ba3bdbc7ee392020eec811ed02c08#file-site-conf-L115 modified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment