-
-
Save plentz/6737338 to your computer and use it in GitHub Desktop.
# 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 | |
} |
Should add prime256v1 to ssl_ecdh_curve too, if you want to connect to app in Android <= 7
Ref: https://stackoverflow.com/questions/47232191/letsencrypt-does-not-work-on-android
Should use a privacy respecting and worlds fastest DNS resolver instead of Google's 8.8.8.8
and 8.8.4.4
IPv4 resolver what is slow and Does not respect privacy or security. Cloudflares resolver also includes both IPv4 IPv6 resolver and alternative fallback DNS resolver alternative resolver for is for IPV4 is 1.0.0.1
and IPv6 2606:4700:4700::1001
as can be found on their website privacy security and speed comes first.
Here is my code for their resolver to support both IPv4 and IPv6 (Can disable IPv6 and will still work universal setup)
#Cloudflare resolver 1dot1dot1dot1.cloudflare-dns.com
resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001];
https://1.1.1.1/#explanation
https://www.cloudflare.com/learning/dns/what-is-1.1.1.1/
https://blog.cloudflare.com/announcing-1111/
Fastest DNS resolvers in the world (1.1.1.1 is the fastest most secured and private unlike google)
https://www.dnsperf.com/#!dns-resolvers
I like this portion better for 301 redirect from http to https, rather than a hardcoded URL value:
return 301 https://$host$request_uri;
@C0nw0nk, Here is a list of Open DNS servers that can prove that my highly hardened personal website is a secured and “un-hackable”. Basically this test was done using the “dig” tool with ad notation of whether DNSSEC is supported (and a small notation if ca is supported too)
The command used is:
dig +dnssec mywebsiteredacted.net. @# and 'ad' flag appears as authenticated,# and note any absense of 'ca' flag
DNSSEC? IP Provider Name
YES 185.228.168.9 CleanBrowsing DNS
YES 185.228.169.9 CleanBrowsing DNS
YES 156.154.70.1 DNS Advantage
YES 156.154.71.1 DNS Advantage
YES 84.200.69.80 DNS Watch
YES 84.200.70.40 DNS Watch
YES 216.146.35.35 Dyn
YES 216.146.36.36 Dyn
YES 81.218.119.11 GreenTeamDNS
YES 74.82.42.42 HurricaneElectric
YES 156.154.70.1 NeuStar
YES 156.154.71.1 NeuStar
YES 9.9.9.9 Quad9
YES 149.112.112.112 Quad9
If you are using any of the DNS servers below this line, then when you visit your banking website, your transaction will not be safe:
YES 199.85.126.10 Norton ConnectSafe (discontinued)
YES 199.85.126.20 Norton ConnectSafe (discontinued)
YES 199.85.127.10 Norton ConnectSafe (discontinued)
no 1.0.0.1 Cloudflare
no 109.69.8.51 puntCAT
no 1.1.1.1 Cloudflare
no 176.103.130.130 AdGuard
no 176.103.130.131 AdGuard
no 176.103.130.132 AdGuard Family
no 176.103.130.134 AdGuard Family
no 195.46.39.39 SafeDNS
no 195.46.39.40 SafeDNS
no 198.101.242.72 AlternateDNS
no 209.244.0.3 Level 3
no 209.244.0.4 Level 3
no 23.253.163.53 AlternateDNS
no 37.235.1.174 FreeDNS
no 37.235.1.177 FreeDNS
no 77.88.8.1 YandexDNS
no 77.88.8.8 YandexDNS
no 8.8.4.4 Google DNS
no 8.8.8.8 Google DNS
no 89.233.43.71 UncensoredDNS
no 91.239.100.100 UncensoredDNS
no bind.odvr.dns-oarc.net DNS OARC
no NOcd 208.67.220.123 OPENDNS FamilyShield
no NOcd 208.67.220.220 OPENDNS
no NOcd 208.67.222.123 OPENDNS FamilyShield
no NOcd 208.67.222.222 OPENDNS
no NOcd 8.20.247.20 Comodo
no NOcd 8.26.56.26 Comodo
For letsencrypt:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
(...)
ssl_stapling on;
ssl_stapling_verify on;
#ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
Edit: changed ssl_certificate
from cert.pem
into fullchain.pem
. This solves "B rating" on https://www.ssllabs.com. Also, according to https://community.letsencrypt.org/t/incomplete-chain-when-using-nginx-1-8-0-and-1-9-9/8500 ssl_trusted_certificate
is not needed after we use fullchain.pem
in ssl_certificate
field. That's why I'm commenting out ssl_trusted_certificate
field.
Thanks for the config. I try to implement using nginx 1.16.0 stable.
My redirect point to proxy_pass. if user types " https://my.domain.com" or " https://my.domain.com/anything" I need to redirect.
Rest of it must show a error page. I reconfigure to point all the error page must shows the index.html.
What is wrong with my config (etc/nginx/conf.d/default.conf) file? I am keep getting nginx default 404. I can not override error 400 and 500 to points the my index.html file.
Any idea how to correct the issue.
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# redirect all http traffic to https
server {
charset UTF-8;
listen 80 default_server;
listen [::]:80 ipv6only=on default_server;
server_name my.domain.com;
# define error pages
error_page 401 403 404 /index.html;
location = /index.html {
root /usr/share/nginx/html;
internal;
}
# redirect server error pages
error_page 500 502 503 504 /index.html;
location = / {
root /usr/share/nginx/html;
internal;
}
# deny access to .htaccess files
location ~ /\.ht {
deny all;
}
# Deny access to hidden files (beginning with a period)
location ~ /\. {
deny all;
}
if ($host = my.domain.com) {
return 301 https://my.domain.com$request_uri;
}
return 404;
}
server {
charset UTF-8;
listen 443;
listen [::]:443 ipv6only=on;
server_name my.domain.com;
error_log /var/log/nginx/host.error.log;
access_log /var/log/nginx/host.access.log main;
# define error pages
error_page 401 403 404 /index.html;
location = /index.html {
root /usr/share/nginx/html;
internal;
}
# redirect server error pages
error_page 500 502 503 504 /index.html;
location = / {
root /usr/share/nginx/html;
internal;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass "http://127.0.0.1:8888/";
try_files $uri $uri/ =404;
}
# Only allow these request methods, Do not accept DELETE, SEARCH and other methods
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 404;
}
}
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;
Hi @plentz,
When use add_header
on multiple blocks, nginx only get the last one and ignore all parents blocks. Let check again plz
I compiled few optimization hacks to increase requests/second.
Optimizations: Tuning Nginx for better RPS of an HTTP API
☮️ 🍰 ✨
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.
TLSv1.3 should be added: ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
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
@rooch84 thanks, I've updated it.
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)
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 4096I 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!
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
}
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
@rfl890 do you have any supporting evidence? I don't dispute your claims, but I think changes should be made objectively.
@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
Thanks @rfl890 and @Peneheals for the info. Looks like a sensible change to me.
Getting an unknown variable "quic". Http/3 works on Chromium but not Firefox, what do I have to do?
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.
The config I've provided on the 7th of March 2020 is still working and you're getting an A+ grade on Qualys SSL check.
The config I've provided on the 7th of March 2020 is still working and you're getting an A+ grade on Qualys SSL check.
That does depend on what version of NGINX you're using it with, and what your target audience is..
I second what @mhcerri said. It's a gotcha.