Created
February 12, 2017 20:11
-
-
Save andrielfn/caba58bb14f1069d0ff5daccfb6e41f9 to your computer and use it in GitHub Desktop.
Best Nginx config for security.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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