Using Let’s Encrypt to secure local services

Hopefully, at this point everyone has secured all their public facing services with HTTPS. Let’s Encrypt makes this quick and easy to do (not to mention free!). What about local services that are only available on your lan though? This is tougher because normal verification methods don’t work, yet it is still important. Part of a defense in depth strategy is to always assume you are in a hostile environment, and with all the router vulnerabilities, Universal Plug and Play problems, and issues such as DNS rebinding attacks, it is not a good assumption that there are no malicious actors on your lan.

To secure your local resources there are a few things that you need.

  1. A domain name - This domain name must be a real domain that you own. For this blog I’ll use
  2. Publicly hosted DNS with a provider that Certbot Supports. DNS providers that I know have plugins for Certbot are:
    1. OVH DNS
    2. LuaDNS
    3. Cloudxns
    4. DNSimple
    5. NS1 dns
    6. Cloudflare
    7. DNS Made Easy
    8. Route 53
    9. Google DNS
    10. Sakura Cloud
    11. Digital Ocean
    12. Gehirn
  3. A local DNS resolver that you can use to serve your internal subdomain.

Once you have these components in place, you can get started.

Setup an internal subdomain

The first step is to setup an internal subdomain. If I own, I might use for local resources. I might host a NextCloud  instance at, an internal wiki at, and maybe a local copy of Gitlab at for extra geek points. For each of these services, you’ll need to create DNS records on your local DNS server so that you computers can find them. Make sure they all have static IP addresses (or static DHCP reservations which is my preferred way to do it) and create an A record for each (and an AAAA record if you use IPv6).

Get credentials to use your DNS provider’s API

I use AWS Route53 to host my DNS. It costs $1/month, but is very good. I have been nothing but happy with their service. Instructions for this part will vary depending on what provider you use. For AWS, you need to create an IAM role that has the following permissions:

  1. route53:GetChange - all resources
  2. route53: ListHostedZones - all resources
  3. route53:ListResourceRecordSets - all resources
  4. route53:ChangeResourceRecordSets - arn of

After setting up this user, click on “Create Security Credentials” and you will be given a Access Key ID and a Secret Key. You need to save these to your server under /root/.aws/credentials.

Download and install Certbot and the plugin for your DNS provider and webserver.

In this case for me, I had to install python2-certbot, python2-certbot-apache and python2-certbot-dns-route53. I am running this on a Centos7 server. Choose your packages as needed.

Run Certbot

for example, to run on your wiki host, you would run:

sudo certbot --installer=apache --dns-route53 -d

This will automatically go out and create a dns record on your dns provider (assuming you got the credentials formatted correctly), verify them, and then clean up the record for you. You get a legitimate, verified, Let’s Encrypt certificate without ever exposing that server to the internet.

Automate renewals

Add a renewal check to your root user’s crontab. This command will check twice a day it renewals are due. For extra credit, forward root’s mail to your email address and you’ll get the results of these renewals in your inbox.

sudo crontab -e

0 0,12 \* \* \* python -c 'import random; import time; time.sleep(random.random() \* 3600)' && certbot renew

That’s all there is to it. Now you have secure HTTPS that browsers trust by default on local services. No need to mess around with self-signed certs or insecure connections.