Tom Butler's programming blog

Guide: Using Let's Encrypt SSL Certificates for a local or network server

A few people have emailed asking how I got HTTPS with a valid certificate working on my minimal virtual machine. It's useful to be able to work locally with a valid HTTPS certificate, it allows you to determine whether there any HTTPS related issues when moving from development to production and test your site using HTTP 2.0.

Prerequisites

It's surprisingly easy, but you will need three things:

  1. A linux machine, linux virtual machine or web server to run certbot. Note: You will need to renew the certificates every 3 months so will need consistent access to this machine. It may also be possible to run Certbot from Winddows.
  2. A domain name or subdomain which you'll use for development.
  3. Access to the domain name's DNS configuration and ability to create a TXT record
If you don't want to go through the hassle of configuring this yourself, I provide certificates for v.je and any subdomain.v.je below

Setting up your domain

The first thing you need to do is set up your DNS to point to your local server. Edit the DNS for your domain or subdomain e.g. example.org so that it points to 127.0.0.1 or whichever local/network IP you are using.

Getting your certificates

Secondly, you will need to use certbot from a linux computer to generate your certificates using the dns-01 acme challenge:

sudo certbot -d example.org --server https://acme-v02.api.letsencrypt.org/directory --manual --preferred-challenges dns certonly

Where example.org is your domain name. Give it the information it requires. Then, during the process you will need to amend the DNS for the domain and create a TXT record _acme-challenge with the code it generates.

Depending on your DNS provider, you may be able to use a plugin to avoid having to manually configure the TXT record

After creating (or modifying if you are renewing) the TXT record I recommend waiting for at least 60 seconds before pressing continue in certbot to ensure the DNS change has propagated.

This will generate your certificates in /etc/leysencrypt/live/example.org

Moving your certificates to the development machine

If you're using the same machine for your development, you can use the certificates from here. Otherwise, you'll need to copy them to your development machine. To do that you can use the following commands:

mkdir ./certs
sudo cp -Lr /etc/letsencrypt/live/example.org ./certs/example.org
sudo chmod -R 644 ./certs
zip -r certs.zip ./certs

This will create a zip file of your certificates. Transfer this to your development machine and configure your web server to use them.

Configuring your web server

Configure your local/network web server to use the certificates as you normally wouly. Here's some sample configuration for NGINX:

# Redirect http requests to https
server {
        
listen 80;
        
server_name example.org;
        return  
301     https://example.org$request_uri;
}

server {
    
# Listen on port 443 for SSL and enable HTTP2 if you wish
        
listen 443 ssl http2;
        
server_name example.org;

        
# path to  fullchain.pem on local machine, default letsencrypt location or location you extracted the zip file to
        
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;

        
# path to privkey.pem
        
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;

        
# NGINX configuration continues e.g. configuring root and php
        # ....

For Apache, take a look at the Apache Documentation. You'll need to provide paths to the fullchain.pem and privkey.pem files.

Restart your web server and you'll be able to access your domain on HTTPS e.g. https://example.org/

Renewal

You will need to renew the certificates every three months. To do so, run the certbot command again to renew the certificates, then copy them back to your development machine.

Using v.je instead of your own domain

If you don't want the hassle of creating and renewing certificates yourself, you can use v.je as I have made the certificates publicly available to download here.

  1. Configure your server name (nginx: server_name, apache: ServerName) on your web server to listen on v.je
  2. Edit your HOSTS file to point v.je to 127.0.0.1 (or run your web server on the IP 192.168.56.2
  3. Point your webserver to the certificates in the v.je subdirectory

As the certificates have already been generated and are publicly available, you can use them without requiring a linux machine or certbot.

This is insecure the green padlock in your address bar does not mean you are connecting to the correct site, you are susceptible to man-in-the-middle attacks because anyone can use my certificates!.

In reality, if it's a development website running on 127.0.0.1 this is a non-issue. The advantage is that you can avoid issues that arise from developing on HTTP and deploying on HTTPS. It also lets you develop using HTTP 2.0

Quickly renewing v.je certificates

If you want to use the v.je certificates and quickly renew them, the following PHP script can be used to check and renew the certificates. Place this script in the directory that stores your SSL certificates and run it periodically (e.g. in a systemd timer/cron/scheduled task)

<?php
$dir '/path/to/certificate/location';
$update false;
chdir($dir);
if (!
file_exists('./certs/expiry.txt')) {
        
$update true;
}
else {
        
$date = new DateTime(file_get_contents('./certs/expiry.txt'));

        
$diff $date->diff(new DateTime());

        
$dayDiff $diff->format('%R%a');

        if (
$dayDiff >= -7$update true;
}



if (!
$update) die;

echo 
'updating certificates....';
exec('curl -o ./certs.zip https://r.je/tmp/vjecert.zip 2>&1'$output);

$zip = new ZipArchive();
$zip->open('./certs.zip');
$zip->extractTo($dir);

unlink('./certs.zip');

v.je wildcard certificates

The v.je certificates are wilcards which means you can use any subdomain. Add example.v.je to your hosts file, set your server name to example.v.je (or set up a wildcard subdomian) and use the certificates in the v.je-0001 subdirectory.