Saturday, 4 March 2017

Let's Encrypt SSL Recipes -- HTTPS with Apache or Nginx

This post is aimed at people who run their own web servers.  These days there is no real excuse for not using HTTPS instead of HTTP on a web site, and the reasons for switching from HTTP to HTTPS are many:
  • Traffic to and from HTTPS sites is encrypted, HTTP traffic is not encrypted.
  • Google and other search engines rank HTTPS web sites more highly than HTTP web sites.
  • New versions of Chrome and some other web browsers will soon start displaying warnings when accessing a HTTP web site.
With the advent of the Let's Encrypt service which offers free SSL certificates for all web sites, there is no no real excuse for using HTTP instead of HTTPS -- using HTTPS is free and easy.

I'll start by providing some simple recipes to obtain Let's Encrypt certificates and install them on a web server -- then I'll follow up with some more posts about using Let's Encrypt certificates for other reasons.

On a recent Linux server, it's now possible to use a simple recipe to install the Let's Encrypt certbot program, which creates certificates:

wget --no-check-certificate https://dl.eff.org/certbot-auto
chmod +x certbot-auto
mkdir -p /root/bin
mv certbot-auto /root/bin
 
You can run certbot and create the certificate using this recipe:

/root/bin/certbot-auto certonly --webroot --webroot-path /var/www/html

This should work on most recent Linux variants -- Ubuntu, Debia, and Red Hat or CentOS.  Replace /var/www/html in the above recipe with your actual web root.  Certbot will ask you some questions (including your site name) and then create the certificate after checking that the site actually points to the server that you're running on.

The next thing is to update your Apache configuration (the default web server on Red hat and CentOS -- I will get to nginx later).

In your Apache virtualhost configuration you will need some lines like this:

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/mysite.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/mysite.com/privkey.pem
    SSLCACertificateFile /etc/letsencrypt/live/mysitecom/chain.pem
    SSLProtocol all -SSLv2 -SSLv3
    SSLHonorCipherOrder on
    SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS" 
    SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
    # HSTS
    Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;" 

In the above recipe replace mysite.com with your site name.

I have included a SSLCipherSuite line that should work for most people -- on reasonably recent Apache 2.2 or 2.4 versions.  If you want to be more specific about which cipher suites you want to support then try the Mozilla SSL Configuration Generator which will give you various options for most versions of Apache and nginx.

Note I have also included a line for HSTS which your site should support if you are running an HTTPS only site.

The next thing to do is to redirect HTTP to HTTPS.  This is done using the following lines in your Apache configuration:

    # Redirect HTTP to HTTPS
    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
 
For nginx there are actually a lot of recipes around on the internet about how to incorporate Let's Encrypt certificates.  Here are the nginx settings that I use.  All of this goes into a configuration file which on CentOS could be something like /etc/nginx/conf.d/ssl.conf:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    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';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/mysite.com/chain.pem;

    #resolver <IP DNS resolver>;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
        ## Put location specific configuration here.
    }
}

To generate the dhparam.pem file referred to in the configuration above, run this command:

openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Finally, you should test the HTTPS security component of your web site using the SSL Labs SSL Server Test tool.  Hopefully you should get an A+ rating on this tool, if not then note any issues that the tool raises and fix them.

No comments:

Post a Comment