Skip to content

Instantly share code, notes, and snippets.

@plentz
Last active March 31, 2024 18:40
Show Gist options
  • Save plentz/6737338 to your computer and use it in GitHub Desktop.
Save plentz/6737338 to your computer and use it in GitHub Desktop.
Best nginx configuration for improved security(and performance)
# to generate your dhparam.pem file, run in the terminal
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
# don't send the nginx version number in error pages and Server header
server_tokens off;
# 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 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
# currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
# http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
# 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020
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'";
# redirect all http traffic to https
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name .forgott.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name .forgott.com;
ssl_certificate /etc/nginx/ssl/star_forgott_com.crt;
ssl_certificate_key /etc/nginx/ssl/star_forgott_com.key;
# enable session resumption to improve https performance
# http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# enables server-side protection from BEAST attacks
# http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html
ssl_prefer_server_ciphers on;
# disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0
ssl_protocols TLSv1.2 TLSv1.3;
# ciphers chosen for forward secrecy and compatibility
# http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
# enable ocsp stapling (mechanism by which a site can convey certificate revocation information to visitors in a privacy-preserving, scalable manner)
# http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/
resolver 8.8.8.8 8.8.4.4;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/star_forgott_com.crt;
# config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
# also https://hstspreload.org/
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
# ... the rest of your configuration
}
@guptarohit
Copy link

I compiled few optimization hacks to increase requests/second.
Optimizations: Tuning Nginx for better RPS of an HTTP API
☮️ 🍰 ✨

@nsgoyat
Copy link

nsgoyat commented Dec 20, 2019

The X-Content-Type-Options nosniff should only be applied for Javascript and CSS files.
For anything else, it's just an extraneous useless HTTP header transferred with every request.

To avoid such pitfalls, use ngx_security_headers module which knows when to set respective header and also accounts for things like not sending headers during conditional GET requests.

security_headers on;

I see you currently have X-Content-Type-Options nosniff applied to your own website's HTML (index page) and all other assets.

@andreiavrammsd
Copy link

TLSv1.3 should be added: ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

@rooch84
Copy link

rooch84 commented Feb 25, 2020

TLSv1 & TLSv1.1 should be removed. Otherwise the HTTPS rating is capped at B. ssl_protocols TLSv1.2 TLSv1.3;

https://blog.qualys.com/ssllabs/2018/11/19/grade-change-for-tls-1-0-and-tls-1-1-protocols

@plentz
Copy link
Author

plentz commented Mar 1, 2020

@rooch84 thanks, I've updated it.

@bms8197
Copy link

bms8197 commented Mar 7, 2020

These are my settings for nginx with LetsEncrypt SSL for an A+ score on Qualys:

ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
ssl_buffer_size 1400;
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_session_tickets off;

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_protocols TLSv1.2 TLSv1.3;

ssl_prefer_server_ciphers on;
ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;

resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001];
resolver_timeout 5s;
ssl_stapling on;
ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;

For dhparam.pem I've used this:
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

I would suggest installing haveged and have it running prior of dhparam.pem generation (otherwise it would take quite some long time)

@dohlin
Copy link

dohlin commented Mar 16, 2020

These are my settings for nginx with LetsEncrypt SSL for an A+ score on Qualys:

ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
ssl_buffer_size 1400;
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_session_tickets off;

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

ssl_protocols TLSv1.2 TLSv1.3;

ssl_prefer_server_ciphers on;
ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;

resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001];
resolver_timeout 5s;
ssl_stapling on;
ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;

For dhparam.pem I've used this:
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

I would suggest installing haveged and have it running prior of dhparam.pem generation (otherwise it would take quite some long time)

Thanks for this! Very useful indeed!

@hongbo-miao
Copy link

hongbo-miao commented Sep 12, 2020

Here is HTTP/3 support
https://www.nginx.com/blog/introducing-technology-preview-nginx-support-for-quic-http-3/

server {
    listen 443 ssl;              # TCP listener for HTTP/1.1
    listen 443 http3 reuseport;  # UDP listener for QUIC+HTTP/3

    ssl_protocols       TLSv1.3; # QUIC requires TLS 1.3
    ssl_certificate     ssl/www.example.com.crt;
    ssl_certificate_key ssl/www.example.com.key;

    add_header Alt-Svc 'quic=":443"'; # Advertise that QUIC is available
    add_header QUIC-Status $quic;     # Sent when QUIC was used
}

@rfl890
Copy link

rfl890 commented Jan 17, 2022

You should probably change the resolver to
1.1.1.1
1.0.0.1
Which are Cloudflare's DNS servers, which are privacy focused and faster than Google

@rooch84
Copy link

rooch84 commented Jan 17, 2022

@rfl890 do you have any supporting evidence? I don't dispute your claims, but I think changes should be made objectively.

@rfl890
Copy link

rfl890 commented Jan 24, 2022

@rooch84 Well if you go to their website (https://1.1.1.1/) and scroll down a bit, it shows a comparison between DNS resolvers and it shows that it is indeed the fastest. They might be lying, but what reason would they have? You don't pay for using the DNS itself, it's free. And in the privacy policy (https://www.cloudflare.com/application/privacypolicy/), in section 2, they specifically say they only collect the minimum amount of data needed and all data is anonymized. I'm not trying to "root for them" or anything, but well, you asked for it

@Peneheals
Copy link

@rooch84 You can check the relevant data about latency/speed here.

And a privacy-focused report, made by a 3rd party audit company (KPMG) here (bottom mid section leads to this pdf).

@rooch84
Copy link

rooch84 commented Feb 2, 2022

Thanks @rfl890 and @Peneheals for the info. Looks like a sensible change to me.

@arch-user-france1
Copy link

Getting an unknown variable "quic". Http/3 works on Chromium but not Firefox, what do I have to do?

@rlSimonLi
Copy link

@Wiilf
Copy link

Wiilf commented Apr 15, 2023

EECDH+AESGCM:EDH+AESGCM:AES128+EECDH:AES128+EDH

This prioritizes cipher suites that support PFS and use ECC, while also using 128-bit encryption for improved performance on older devices.

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