I recently spent a few hours trying to get a perfect score on Qualy's SSL Labs Tester. While I was not able to achieve a "100" in every category, I feel I got pretty close:

This post will detail the steps for getting an A+ SSL rating using Nginx.

Generate a Certificate

The first step in securing your server with SSL is to generate an SSL certificate. At this time, the only way to get a verified certificate that will be trusted across most Internet browsers is to pay for a certificate. I chose RapidSSL, but you can choose any respectable provider.

You do not need to purchase an extended validation (EV) certificate to achieve an A+ rating. For personal blogs or sites that are not processing secure information, a regular certificate is fine. There is no additional encryption added with an EV certificate - just a pretty green bar that makes users feel better.

Depending on the provider you chose, you will need to generate a CSR and securely transmit the files onto your server. You may also need to install an intermediate certificate.

Install the Packages

In my case, I used Nginx and OpenSSL. The latest version of OpenSSL in Ubuntu's is good enough, but the latest Nginx does not support the SSL stapling we want to use later.

$ sudo apt-get install openssl

Because these instructions could easily become out of date, I recommend following the steps for compiling Nginx from source on the Nginx website.

Choose Protocols

This is arguably the hardest decision you will need to make. If you want to achieve an A+ rating, you will need to neglect a small percentage of your user base.

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 ;

This tells Nginx to explicitly only allow TLS, which means older clients (namely IE 6 and Windows XP users) will get certificate errors when visiting your website. If any of these are your target audience, you must also add SSLv3 to the list, but you will be unable to get an A+ by doing so (you can still get an A).

Choose Ciphers

Below, we only permit 256-bit encryption schemes. The ECDHE suite gives us Forward Secrecy (although we will generate a new set of dhparams in a later step). It is important to note that these values are in order of specificity, so the ordering is from best to worst.

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

Again, if you plan to support IE6 or older clients, you may need to add additional cipher suites. Doing so will reduce your rating.

Generate new dhparams

With Forward Secrecy, if an attacker gets a hold of the server's private key, it will not be able to decrypt past communications. The private key is only used to sign the DH handshake, which does not reveal the pre-master key. Diffie-Hellman ensures that the pre-master keys never leave the client and the server, and cannot be intercepted by a MITM.

All versions of Nginx as of 1.4.4 rely on OpenSSL for input parameters to Diffie-Hellman (DH). Unfortunately, this means that Ephemeral Diffie-Hellman (DHE) will use OpenSSL's defaults, which include a 1024-bit key for the key-exchange. Since we're using a 2048-bit certificate, DHE clients will use a weaker key-exchange than non-ephemeral DH clients.

We need generate a stronger DHE parameter:

$ cd /etc/ssl/certs $ openssl dhparam -out dhparam.pem 4096

And then tell Nginx to use it for DHE key-exchange:

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

Please note: this section was adopted from Strong SSL Security on nginx at Raymii.org.

Turn on SSL

In your Nginx configuration, you will need to activate SSL. The code below is documented inline to describe each option.

# Enable SSL on all domains - you may also want to enable this on a per-site # basis instead if you are supporting multiple virtual hosts. ssl on ; # Cache SSL sessions for 10m (this is about 40,000 sessions), timing them out # after 24 hours. ssl_session_cache shared:SSL:10m ; ssl_session_timeout 24h ; # Set the buffer size to 1400 bytes (that way it fits into a single MTU). ssl_buffer_size 1400 ;

OCSP Stapling

When connecting to a server, clients should verify the validity of the server certificate using either a Certificate Revocation List (CRL), or an Online Certificate Status Protocol (OCSP) record.

ssl_stapling on ; ssl_stapling_verify on ; resolver 8 .8.4.4 8 .8.8.8 valid=300s ; resolver_timeout 10s ;

HSTS

HTTP Strict Transport Security (HSTS) instructs browsers to communicate with your website only over SSL.

# Enable HSTS add_header Strict-Transport-Security max-age=63072000 ; # Do not allow this site to be displayed in iframes add_header X-Frame-Options DENY ; # Do not permit Content-Type sniffing. add_header X-Content-Type-Options nosniff ;

Intermediate Certificates

Depending on when you purchase your certificate, you may be issued a certificate that uses SHA1 encryption. Many browsers, such as Chrome and Safari will soon distrust these certificates and show a warning.

In my case, with RapidSSL, I needed 256-bit GeoTrust and RapidSSL intermediate certificates. It took some searching, but I was able to find the SHA 256 intermediate certificates on each of the provider's websites. You may need to contact your SSL certificate provider to obtain the SHA 256 intermediate certificate. You must have a certificate using SHA 256 to obtain an A+ on the SSL labs tester.

GeoTrust SHA256 Intermediate Certificate

-----BEGIN CERTIFICATE----- MIIERDCCAyygAwIBAgIDAjp4MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMTQwODI5MjIyNDU4WhcNMjIwNTIwMjIyNDU4WjBmMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UECxMURG9tYWluIFZh bGlkYXRlZCBTU0wxIDAeBgNVBAMTF0dlb1RydXN0IERWIFNTTCBDQSAtIEc0MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA30GUetr35DFDtuoBG1zOY+r6 baPZau4tmnX51ZxbvTTf2BzJbdgEiNputbe18DCuQNZd+sRTwdQinQROEaaV1UV8 QQVY4Ezd+e5VvV9G3K0TCJ0s5PeC5gcrng6MNKHOxKHggXCGAAY/Lep8myiuGyiL OQnT5/BFpLG6EWeQVXuP3u04XKHh44PEw3KRT5juHMKAqmSlPoNiHMzgnvhawBMS faKni6PnnyrXm8rL7ZcBnCiEUQRQQby0/HjpG88U6h8P/C4BMo22NcsKGDvsWj48 G9OZQx4v973zWxK5B17tPtGph8x3cifU2XWiY0uTNr3lXNe/X3kNszKnC7JjIwID AQABo4IBHTCCARkwHwYDVR0jBBgwFoAUwHqYaI2J+6sFZAwRfap9ZbjKzE4wHQYD VR0OBBYEFAtQ7HfvKpv/7AOhCv+txuQqGMc+MBIGA1UdEwEB/wQIMAYBAf8CAQAw DgYDVR0PAQH/BAQDAgEGMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9nLnN5bWNi LmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUH MAGGEmh0dHA6Ly9nLnN5bWNkLmNvbTBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYw MzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2Vz L2NwczANBgkqhkiG9w0BAQsFAAOCAQEAMyTVkKopDDW5L8PHQpPAxhBLAwh2hBCi 4OdTEifyCtp/Otz9XHlajxd0Q1Ox1dFdWbmmhGTK8ToKWZYQv6mBV4tch9x/4+S7 BXqgMgkTThCBKB+cA2K89AG1KYNGB7nnuF3I6dHdrTv4NNvB0ZWpkRjtPCw3EU3M /lM+UEP5w1ZBrFObbAWymuLgWVcwMrYmThMlzfpIcA91VWAR9TvVXlo8i1sPD2JC SGGFixD0wYi/f1+KwtfNK5RcHzRKCK/rromoSHVVlR27wJoBufQDIj7U5lIwDWe5 wJH9LUwwjr2MpQSRu6Srfw/Yb/BmAMmjXPWwj4PmnFrmtrnFvL7kAg== -----END CERTIFICATE-----

RapidSSL SHA256 Intermediate Certificate

-----BEGIN CERTIFICATE----- MIIEJTCCAw2gAwIBAgIDAjp3MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i YWwgQ0EwHhcNMTQwODI5MjEzOTMyWhcNMjIwNTIwMjEzOTMyWjBHMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXUmFwaWRTU0wg U0hBMjU2IENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv VJvZWF0eLFbG1eh/9H0WA//Qi1rkjqfdVC7UBMBdmJyNkA+8EGVf2prWRHzAn7Xp SowLBkMEu/SW4ib2YQGRZjEiwzQ0Xz8/kS9EX9zHFLYDn4ZLDqP/oIACg8PTH2lS 1p1kD8mD5xvEcKyU58Okaiy9uJ5p2L4KjxZjWmhxgHsw3hUEv8zTvz5IBVV6s9cQ DAP8m/0Ip4yM26eO8R5j3LMBL3+vV8M8SKeDaCGnL+enP/C1DPz1hNFTvA5yT2AM QriYrRmIV9cE7Ie/fodOoyH5U/02mEiN1vi7SPIpyGTRzFRIU4uvt2UevykzKdkp YEj4/5G8V1jlNS67abZZAgMBAAGjggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7 qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kwEgYD VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARF MEMwQQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3Ry dXN0LmNvbS9yZXNvdXJjZXMvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQCjWB7GQzKs rC+TeLfqrlRARy1+eI1Q9vhmrNZPc9ZE768LzFvB9E+aj0l+YK/CJ8cW8fuTgZCp fO9vfm5FlBaEvexJ8cQO9K8EWYOHDyw7l8NaEpt7BDV7o5UzCHuTcSJCs6nZb0+B kvwHtnm8hEqddwnxxYny8LScVKoSew26T++TGezvfU5ho452nFnPjJSxhJf3GrkH uLLGTxN5279PURt/aQ1RKsHWFf83UTRlUfQevjhq7A6rvz17OQV79PP7GqHQyH5O ZI3NjGFVkP46yl0lD/gdo0p0Vk8aVUBwdSWmMy66S6VdU5oNMOGNX2Esr8zvsJmh gP8L8mJMcCaY -----END CERTIFICATE-----

Final Configuration

If you are just looking for a copy-paste solution to get an A+, you can copy and paste the Nginx configuration below.

ssl on ; ssl_session_cache shared:SSL:10m ; ssl_session_timeout 24h ; ssl_buffer_size 1400 ; ssl_session_tickets off ; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 ; ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL ; ssl_prefer_server_ciphers on ; ssl_certificate /etc/ssl/website.com.crt ; ssl_certificate_key /etc/ssl/website.com.key ; ssl_dhparam /etc/ssl/dhparam.pem ; ssl_stapling on ; ssl_stapling_verify on ; resolver 8 .8.4.4 8 .8.8.8 valid=300s ; resolver_timeout 10s ; spdy_keepalive_timeout 300 ; spdy_headers_comp 9 ; add_header Strict-Transport-Security max-age=63072000 ; add_header X-Frame-Options DENY ; add_header X-Content-Type-Options nosniff ;

You will still need to generate and install the proper certificates. I hope this blog post helps you install and secure your website. Please feel free to leave a comment or suggestion!