Home » Secure HTTPS Setup With nginx and Let’s Encrypt (Part 2)

Secure HTTPS Setup With nginx and Let’s Encrypt (Part 2)


In part 1 of this post, I covered getting nginx configured to securely handle HTTPS content.  Now, we’ll get Let’s Encrypt installed, get a certificate issued, and make nginx listen on the HTTPS port.

Let’s Encrypt!

Currently, the best way to get the most up-to-date version of the Let’s Encrypt client is via git, so if your server does not currently have the git client installed you’ll have to do that first:

Fedora / CentOS / RHEL / (yum-based systems):

Debian / Ubuntu / (apt-based systems):

Next, we’ll grab a copy of the repo with the following (feel free to replace /opt/letsencrypt with another location if you’d prefer it be installed elsewhere):

Assuming no errors, you now have the latest Let’s Encrypt client in /opt/letsencrypt — you can update it in the future by doing “sudo git pull” in /opt/letsencrypt or wherever else you cloned to.  The client includes several plugins to authenticate the fact that you actually control the domain you want a certificate for, but in this post we’re going to use the “webroot” plugin.  How this plugin works is that the client writes some files to a specific directory (‘.well-known’) in the document root of the website, then attempts to read them back over the internet.  Inherent in this is that you must first have DNS for the domain (or domains) pointed to your nginx server, and at least a basic HTTP vhost set up for it (check out http://robido.com/nginx/configure-an-nginx-virtual-host-with-phpmyadmin-and-php-fpm/ for some info on that if you have a fresh nginx install with no vhosts defined.)  If you have some form of access restriction (password, IP, etc.) on your website, you’ll have to allow access to the URLs Let’s Encrypt expects; you can do so by adding the following inside the ‘server’ block of your vhost configuration file (and then doing a ‘sudo nginx -t’ to test the configuration followed by ‘sudo nginx -s reload’ to pick up the changes):

On to making a certificate!  Enter the following:

The call to letsencrypt-auto supports multiple -d options for the same document root, creating a SAN certificate (that is, a certificate that is valid for all the domains listed).  You only need to provide one, but all of them will be checked so make sure DNS is pointed correctly or you’ll get an error.  You can also create multiple certificates at the same time like:

The script will make sure the necessary packages are installed on your system, install them if any are missing, then execute.  On the very first time, you’ll be asked for some information:

Enter an email address that Let’s Encrypt can send lost key recovery and certification expiration notice emails to:

Let's Encrypt email

And then agree to their subscriber agreement (after reading it, of course! …) :

Let's Encrypt agreement

Once you’ve gotten through those screens, the script will verify the domains you entered actually point to the server and document root you entered, and if all is well you’ll receive a message with some “IMPORTANT NOTES”.  They actually are important, you may want to read them 😀

Put That Cert To Work

Assuming the steps above went well, you now have some files in /etc/letsencrypt/live/sitedomain.com/.  In case you’re wondering what those files are:

  • cert.pem:  The actual certificate for the domain.
  • chain.pem: The intermediate chain certificate for Let’s Encrypt (what gives them the authority to sign your cert).
  • fullchain.pem: cert.pem with chain.pem appended to the end of it.
  • privkey.pem: The private key for your cert.pem.

Sharp-eyed admins may notice that these files are actually just symlinks; this allows us to point nginx at them, and when we renew the certificate, Let’s Encrypt updates the symlinks for us.  On that note, let’s actually get nginx speaking HTTPS for your vhost; open up the nginx config file for your vhost in your favorite text editor (/etc/nginx/conf.d/domain.com.conf or whatever convention you chose to use).  Eventually, unless you have an exceptional reason not to, you’re going to want to force all HTTP traffic to HTTPS, but for now we’ll just duplicate your HTTP configuration as an HTTPS one with some added parameters.

A simple nginx vhost config might look like (WordPress or other PHP-based sites will have additional configuration parameters for PHP handling and so forth):

Simply duplicate that server block, change “listen 80” to “listen 443 ssl”, and add in the ssl_certificate and ssl_certificate_key parameters like (you may also wish to log SSL traffic to different log files):

Test your configuration afterwards with “sudo nginx -t”, and reload if all is well with “sudo nginx -s reload” to pick up the changes.  Accessing your site on HTTPS now may be a mess because of mixed content — resources linked via HTTP from an HTTPS page.  In the last part of this series of posts, we’ll force all HTTP links that the server has control over to go over HTTPS instead for security reasons, but it’s generally a good idea to fix these issues on your site instead of relying on the server to fix it for you (especially if you are loading some resources from other locations where we can’t re-write those!).  If you have any sort of default SSL vhost (often at /etc/nginx/conf.d/ssl.conf for example) with more SSL parameters than just the ‘ssl_certificate’ and ‘ssl_certificate_key’ defined, you’ll probably want to remove them to ensure they don’t overwrite our secure configuration.

One final wrinkle — you may find when attempting to connect to your site on HTTPS that the firewall is blocking you.  Opening port 443 on your firewall varies from Linux distro to distro, but for firewalld-based systems you’ll want to do:

sudo firewall-cmd –permanent –zone=public –add-service=https; sudo firewall-cmd –reload

The next step will be to clean up and finish tightening up your configuration, including forcing all connections to your site to be HTTPS once you’ve fixed up your site, enabling HSTS (HTTP Strict Transport Security) once you’re really sure the site works with HTTPS, and setting up a cron job to automatically renew your Let’s Encrypt certificates so they never expire.

If you’d like to setup an Auto Renew Script to automatically renew your certificates on a cron job, then continue to part 3 of this tutorial.

Leave a Reply

Your email address will not be published. Required fields are marked *