Intranet SSL Certificates Using Let’s Encrypt | DNS-01

Let's EncryptLet’s Encrypt is a great service offering the ability to generate free SSL certs.  The way it normally works is using http-01 challenge…  to respond to the Let’s Encrypt challenge the client (typically Certbot) puts an answer in the webroot.  Let’s Encrypt makes an http request and if it finds the response to the challenge it issues the cert.


Certbot is great for public web-servers.

Generating Intranet SSL Certs Using DNS-01 Challenge

But, what if you’re generating an SSL certificate for a mail server, or mumble server, or anything but a webserver?  You don’t want to spin up a web-server just for certificate verification.

Or what if you’re trying to generate an SSL certificate for an intranet server  Many homelabs, organizations and businesses need publicly signed SSL certs on internal servers.  You may not even want external A records for these services, much less a web-server for validation.

ACME DNS Challenge

Fortunately, Let’s Encrypt introduced the DNS-01 challenge in January of 2016.  Now you can respond to a challenge by creating a TXT record in DNS.

ACME Let's Encrypt DNS-01 Challenge Diagram


Lukas Schauer wrote dehydrated (formerly which can be used to automate the process.  If you need to generate SSL certs for Windows I’ve added the ability to output to PFX / PKCFS 12 in my fork.

Here’s a quick guide on Ubuntu 16.04, but it should work on any Linux distribution (or even FreeBSD).

Install dehydrated /

Hook for DNS-01 Challenge

At this point, you need to install a hook for your DNS provider.  If your DNS provider doesn’t have a hook available you can write one against their API, or switch to a provider that has one.

If you need to pick a new provider with a proper API my favorite DNS Providers are CloudFlare and Amazon Route53.  CloudFlare is what I use for  It gets consistently low latency lookup times according to SolveDNS, and it’s free (I only use CloudFlare for DNS, I don’t use their proxy caching service which can be annoying for visitors from some regions).  Route53 is one of the most advanced DNS providers.  It’s not free but usually ends up cheaper than most other options and is extremely robust.  The access control, APIs, and advanced routing work great.  I’m sure there are other great DNS providers but I haven’t tried them.

Here’s how to set up a CloudFlare hook as an example:

In letsencrypt-cloudflare-hook/ change the top line to point at python3:

Config File

Edit the “/etc/dehydrated/config” file… add or uncomment the following lines:


Create an /etc/dehydrated/domains.txt file, something like this:

The first four lines will each generate their respective certificates, the last line creates a multi-domain or SAN (Subject Alternate Name) cert with multiple entries in a single SSL certificate.

Finally, run

The first time you run it, it should get the challenge from Let’s Encrypt, and provision a DNS TXT record with the response.  When validated the certs will be placed under the certs directory and from there you can distribute them to the appropriate applications.  The certificates will be valid for 90 days.

For subsequent runs will check to see if the certificates have less than 30 days left and attempt to renew them.


It would be wise to run dehydrated -c from cron once or twice a day and let it renew certs as needed.

To deploy the certs to the respective servers I suggest using an IT Automation tool like Ansible.  I have a dedicated VM that runs Ansible.  You can configure an ansible playbook to run from a daily cron job to copy updated certificates to remote servers and automatically reload services if the certificates have been updated.  Here’s an example of an Ansible Playbook which could be called daily to copy certs to all web-servers and reload nginx if the certs were updated or renewed:

Create a file web-servers-nginx.yml

Add the below to your Ansible inventory file (mine is namned ‘production’).  “” matches the primary name of the certificate, found in /etc/dehydrated/certs/

Execute the playbook with:

(note that the user that runs this needs to have permissions to read the certificates that dehydrated generated.  Easiest way to do that is to use the same user account to run dehydrated as you do for Ansible.  Also Ansible will need public/private key authentication setup to connect to the remote server without a password).

Then obviously you would have something like this in nginx:

(for the ssl_dhparam to work you’ll need to run the below command once on the web server):

And after that nginx needs to be restarted.

If this is a public server I strongly suggest testing with SSLLabs to make sure chaining and security is setup correctly.


Free SSL Certificates from StartCom

Here’s a quick tutorial on how to obtain and setup a certificate from StartCom.


StartCom offers free personal certificates, these aren’t the fake certs where you have to setup your own CA and it only works when people have your CA cert installed.  These are real certs that work out of the box in just about every OS / browser I’ve tried (OSX, XP SP3 to Windows 8, IE, Firefox, Safari, Chrome, iOS, Android, Windows 8 Phone, etc.).

Validate Your Ownership of the Domain

1. Select Domain Name Validation


2. Enter the domain name you want to validate.


3. Select an address you can receive email at, the final address comes from your whois record which should be the domain owner’s email address.  StartCom will send you a validation code, once entered you have verified domain ownership and can create certificates for 30 days.



4. Generate Certificate Request.  SSH into your server and create a new key and CSR, it is of extreme importance that “Common Name” should be your fully qualified domain name.  StartCom won’t let you enter a naked domain (e.g. here, you must enter a sub-domain (such as  or in the example below I used reader.  The cert will also be good for your naked domain.


Skip the generate cert option (since you’ve already generated it) and paste the contents of the CSR file you create into the certificate request form.




5. Here you select the domain the certificate will fall under, then the subdomain for your certificate (must be the same as your certificate request).




6. StartCom will give you your certificate, paste it into a .crt file.  Also BE SURE to download the intermediate and root certs.


7.  Now you have a SSL Certificate (.csr) and Key (.key)


8. Configure Apache2.  …this goes below the directory directive in your site config: (e.g. /etc/apache2/sites_available/  be sure to reference your certificate and key as well as StartCom’s root certificate, and chain (this will help out older browers).  Note that the certificate can be used for just about any purpose including (IMAP, SMTPS, Mumble server, etc.)