Part 5 of 7 in "Self-Hosting WordPress"

  1. Self-Hosting WordPress – Ubuntu
  2. Self-Hosting WordPress – Nginx
  3. Self-Hosting WordPress – MariaDB
  4. Self-Hosting WordPress – PHP
  5. Self-Hosting WordPress – SSL
  6. Self-Hosting WordPress – Installation
  7. Self-Hosting WordPress – Performance

Free SSL certificate? Don’t mind if I do.

SSL is important, even Google is using it in the ranking algorithms now but historically it could be quite costly. Now that we have full server control, albeit virtual, we can use the Let’s Encrypt client to get a certificate for ourselves. And, as always – in a ridiculously straightforward way.

At this point I’m going to make a few assumptions. In order to get an SSL certificate you must own the domain you are trying to get it for. And additionally, it must be pointed at the server you are trying to authenticate. You can do this by setting an A Record to point the domain to the IP address.

It’s possible to do this step at any stage, but I much prefer doing it before installing WordPress in order to make the process smoother.

Firstly, ssh into your server and then run the following commands.

sudo apt-get update
sudo apt-get install letsencrypt

We are updating the repository list and then installing the letsencrypt client. This has actually been renamed to certbot however the version included in the Ubuntu 16.04 repositories is perfectly fine for now!

You now have the client installed, awesome right? 

Webroot Validation

The webroot plugin inside Let’s Encrypt makes a special file in http://server_ip/.well-known/. Their service then validates this file from their servers to check that we have control of the domain and server.

Let’s go ahead and explicitly allow access to ensure we don’t get any errors.

sudo nano /etc/nginx/sites-available/default

Directly below location ~ /\.ht, inside the server block add the following:

location ~ /.well-known {
    allow all;
}

Save and close the file, then check it!

sudo nginx -t

If there are no errors, go ahead and restart nginx.

sudo systemctl restart nginx

By default, the webroot path is /var/www/html, you can find it in the same file we just closed if you have changed it. We will need this to tell the letsencrypt client where to make that special file.

It is possible to make an individual certificate work with multiple domain names. I recommend the domain name without www., with www. and the ip address. However, you can set it up as you need. Check the webroot path matches what you found earlier.

sudo letsencrypt certonly -a webroot --webroot-path=/var/www/html -d example.com -d www.example.com

At this point you’ll be asked for your email, enter it and then accept the terms of service.

The output will be something similar to:

IMPORTANT NOTES:
 - If you lose your account credentials, you can recover through
   e-mails sent to sammy@digitalocean.com
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/example.com/fullchain.pem. Your
   cert will expire on 2017-06-20. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - Your account credentials have been saved in your Let's Encrypt
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Let's
   Encrypt so making regular backups of this folder is ideal.
 - If you like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

You now have a few files available:

  • cert.pem: Your domain’s certificate
  • chain.pem: The Let’s Encrypt chain certificate
  • fullchain.pem: Both cert.pem and chain.pem
  • privkey.pem: Your private key

We can access them at a symlink at /etc/letsencrypt/live/domain_name substituting domain_name.

We will also generate a strong Diffie-Hellman group too.

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

At this point we have all the files we need to setup our SSL. We will now create a few configuration files to improve maintainability to serve the certificates over Nginx.

sudo nano /etc/nginx/snippets/ssl-params.conf
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

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

There’s quite a lot going on so let’s talk through it.

Lines 1 and 2 load and set the certificate settings.

Lines 4-11 setup the ssl settings.

Lines 12-13 configure Google as the DNS resolver.

Lines 14-16 setup some secure headers to return.

Line 18 includes the Diffie-Hellman group we created earlier.

Now all there is to do is add it to our config!

sudo nano /etc/nginx/sites-available/default

At the moment the file probably looks like this:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    ...

We’re going to split this server block into 2, one for HTTP requests and one for HTTPS.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    # SSL configuration
        
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    include snippets/ssl-params.conf;
    ...

You’ll need to substitute the server_name as appropriate.

This setup will redirect http traffic to https traffic, awesome! Except Nginx is currently blocking that…

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx Full                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx Full (v6)            ALLOW       Anywhere (v6)

Let’s test the configuration.

sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

And restart nginx to allow the changes to take effect.

sudo systemctl restart nginx

Phew! SSL is now working on our domain.

Auto Renew

In 3 months, the certificate will expire and bad things will happen. We can, however, setup auto renewal!

sudo crontab -e

Choose nano if asked and add the following lines to the bottom.

# Renew SSL
0 3 * * 1 /usr/bin/letsencrypt renew >> /var/log/ssl-renewal.log
5 3 * * 1 /bin/systemctl reload nginx

This means that at 3am every monday we will check to renew the ssl certificate. At 3:05, we will restart nginx.

Got this far? Awesome, you’re now using an SSL certificate.

Continue reading "Self-Hosting WordPress"

There are currently no comments.