Skip to content

Instantly share code, notes, and snippets.

@andrielfn
Created February 12, 2017 20:11
Show Gist options
  • Save andrielfn/caba58bb14f1069d0ff5daccfb6e41f9 to your computer and use it in GitHub Desktop.
Save andrielfn/caba58bb14f1069d0ff5daccfb6e41f9 to your computer and use it in GitHub Desktop.
Best Nginx config for security.
# Best Nginx configuration for security.
#
# Score A in https://securityheaders.io.
# Score A+ in https://www.ssllabs.com/ssltest.
#
# References
#
# - https://letsecure.me/secure-web-deployment-with-lets-encrypt-and-nginx/
# - https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
# - https://gist.github.com/plentz/6737338
# - https://michael.lustfield.net/nginx/getting-a-perfect-ssl-labs-score
server {
listen 443 ssl default deferred;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Disable SSLv3 since it's less secure then TLS
#
# http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0
ssl_protocols TLSv1.2;
# Ciphers chosen for forward secrecy and compatibility.
#
# http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
# Enables server-side protection from BEAST attacks.
#
# http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html
ssl_prefer_server_ciphers On;
# Header to enable HSTS (HTTP Strict Transport Security) to avoid ssl stripping.
#
# https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
# Header to don't allow the browser to render the page inside an frame or iframe.
# Also avoid clickjacking. http://en.wikipedia.org/wiki/Clickjacking
# If you need to allow [i]frames, you can use SAMEORIGIN or even set an URI with ALLOW-FROM URI.
#
# https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
add_header X-Frame-Options SAMEORIGIN;
# 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://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header X-Content-Type-Options nosniff;
# This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
# 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.
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header X-XSS-Protection "1; mode=block";
# with Content Security Policy (CSP) enabled(and a browser that supports it(http://caniuse.com/#feat=contentsecuritypolicy),
# you can tell the browser that it can only download content from the domains you explicitly allow
# http://www.html5rocks.com/en/tutorials/security/content-security-policy/
# https://www.owasp.org/index.php/Content_Security_Policy
# I need to change our application code so we can increase security by disabling 'unsafe-inline' 'unsafe-eval'
# directives for css and js(if you have inline css or js, you will need to keep it too).
# more: http://www.html5rocks.com/en/tutorials/security/content-security-policy/#inline-code-considered-harmful
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com https://assets.zendesk.com https://connect.facebook.net; img-src 'self' https://ssl.google-analytics.com https://s-static.ak.facebook.com https://assets.zendesk.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://assets.zendesk.com; font-src 'self' https://themes.googleusercontent.com; frame-src https://assets.zendesk.com https://www.facebook.com https://s-static.ak.facebook.com https://tautt.zendesk.com; object-src 'none'";
# SSL Stapling doesn't exactly make you any more secure, but it does help the client significantly.
# In short, you help the client by telling them they can use your server for OCSP information for your
# domain instead of letting the browser make the request to an often unreliable resource.
#
# http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/
resolver 8.8.8.8;
ssl_stapling on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_stapling_verify on;
# Enable session resumption to improve https performance.
#
# http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 5m;
# It turns out, some OpenSSL implementations don't provide a nice default for Nginx to inherit,
# so it becomes a good idea to specify this manually.
ssl_ecdh_curve secp384r1;
# By default, Nginx will use the default DHE (Ephemeral Diffie-Hellman) paramaters provided by OpenSSL.
# This uses a weak key that gets lower scores. The best thing to do is build your own.
# You can create a 2048 bit key, but let's go ahead and toss 4096 at it.
#
# Use the following command to generate the key:
#
# openssl dhparam -dsaparam -out /etc/nginx/ssl/dhparam.pem 4096
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
root /example.com/public;
error_page 500 502 503 504 /500.html;
error_page 404 /404.html;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_pass http://localhost:3000;
}
location '/.well-known/acme-challenge' {
default_type "text/plain";
root /tmp/letsencrypt-auto;
}
location ~* ^/(assets|android|apple|favicon|safari|twitter|opengraph).*\.(ico|svg|png|js|css|jpe?g|webp)$ {
expires 1y;
add_header Cache-Control public;
add_header Access-Control-Allow-Origin https://example.com;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
}
location /status {
stub_status;
}
}
# redirect all http traffic to https
server {
listen 80;
server_name .example.com;
return 301 https://$host$request_uri;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment