Skip to content

Instantly share code, notes, and snippets.

@DakuTree
Last active September 5, 2019 12:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DakuTree/1d809cf213b9bdf8664884fa7b265f48 to your computer and use it in GitHub Desktop.
Save DakuTree/1d809cf213b9bdf8664884fa7b265f48 to your computer and use it in GitHub Desktop.
Nginx - Different SSL protocols per server

Had some trouble with this myself, so I thought it would be good to share my findings.

At work I'm currently managing a fairly large estate of websites. Ideally we'd have everything running TLSv1.2+, however there are various legacy applications which require TLSv1.0 due to various reasons.
Ideally we'd either upgrade said applications to support TLSv1.2, or get rid of them altogether, however it sadly takes some time for the gears to turn, so it isn't really an option.

Now the initial thought would be to just set the ssl_protocols setting on a per server basis. You can try this, reload Nginx and notice there is no change, despite no warning in reload (which should occur here).
Whatever ssl_protocols Nginx sees first, regardless of server, is what is used for all servers. There is a few similar settings where this is the case, however they are usually flagged as such on reload, this one is not.

From my research, there is three possible solutions to this.

  1. Setup a new Nginx server for each different ssl_protocols setup.
    This adds a bunch of unneeded complexity to managing the sites, and would also require an additional IP per server.

  2. Utilize the patch in nginx/trac#844.
    This works and does what is expected, however it does have some limitations.

    • This patch works up to 1.15.2 (2018/07/24), however I did manage to get it working with 1.15.8 (2018/12/25). 1.15.9+ appears to have done some breaking changes which cause the patch to longer work correctly, and I don't have the knowledge enough with C to make it work.
    • According to a comment on the issue, this won't be compatible with the upcoming Encrypted SNI, so even if the patch could work on later versions, it would kill this feature.

    We've used this option for around a year without much issue, however this is obviously not substainable due to the lack of ability to upgrade.

  3. Utilize ssl_ciphers to handle protocol restrictions.
    This is ultimately the best option, albeit the least obvious one. The only information on this is from a three year old post on StackOverflow.

    The way this works is pretty simple:

    1. Set ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; in the http block.
    2. Set protocol specific ssl_ciphers in the server block. Also set other relevant SSL settings (prefer ciphers, dhparam).)

Example

# ...
http {
	# ...

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

	server {
		server_name tls10.example.com;

		# ...

		ssl_prefer_server_ciphers on;
		ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;
		ssl_dhparam               /etc/nginx/ssl-certs/dhparam.pem;

		# ...
	}
	server {
		server_name tls12.example.com;

		# ...

		ssl_prefer_server_ciphers off;
		ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
		ssl_dhparam               /etc/nginx/ssl-certs/dhparam.pem;

		# ...
	}
	server {
		server_name tls13.example.com;

		# ...

		ssl_prefer_server_ciphers off;
		# ssl_ciphers ...; # Default Nginx ciphers should be OK here?

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