Generating Intranet and Private Network SSL Certificates using LetsEncrypt

This post is a follow up to my previous one Automating SSL Certificates using Nginx & LetsEncrypt. This time we’ll be generating SSL certificates for intranet and non-public networks.


Before we get started, you’ll want to make sure that the following items are true.

  • You must use a real/purchased domain. Reserved domains/TLD’s like *.example, *.test, *.local will never work.
  • You must have an external DNS provider that has an API.
    • If your DNS provider doesn’t have an API, you can use cloud for free.
  • You must have python 2.6+ installed

Install Dehydrated

The first step is to install a Letsencrypt client. The official client is a bit bloated and complicated to setup. I prefer to use the dehydrated client instead as its code is easier to understand, has few dependencies and its incredibly simple to automate.

# install dehydrated dependencies (most should already be installed)
apt-get install -y openssl curl sed grep mktemp git

# install dehydrated into /srv/dehydrated
git clone /srv/dehydrated

Configure Dehydrated

Dehydrated requires some configuration, but not much, the defaults work out of the box. That means that all you need to do is

  • create a domains.txt file with the url(s) of the site(s) you’re generating ssl certificates for

Here’s how we can do that.

# First we need to make the client executable
chmod +x /srv/dehydrated/dehydrated
# Then we need to specify the intranet/private domain
echo "" > /srv/dehydrated/domains.txt

Install Lexicon

Next we’re going to install the Lexicon library. Lexicon provides a way to manipulate DNS records on multiple DNS providers in a standardized way.

#  install python requests library dependencies
apt-get install -y build-essential python-dev curl libffi-dev libssl-dev
pip install requests[security]
pip install dns-lexicon

Configure Lexicon

The Lexicon library lets you automatically configure your DNS provider using Letsencrypt DNS challenges without having to deal with creating API calls yourself. Its perfect for generating internal/intranet SSL certs.

Dehydrated requires a hook file to complete dns-01 challenges. The Lexicon repo has an example one that wires up the deploy_challenge and clean_challenge calls to Lexicon commands.

curl -O /srv/dehydrated
chmod +x /srv/dehydrated/

The only information that Lexicon requires is:

  • authentication information such as username/password or token.
    • In general your API token should be availble in your DNS provider’s account settings page.
  • provider name

We can pass all that information to Lexicon by setting a handful of environmental variables. If don’t want to do that, you can modify the hook file and add the --auth-username and --auth-password parameters to all lexicon commands.

#If our DNS provider is cloudflare
export PROVIDER=cloudflare
export LEXICON_CLOUDFLARE_TOKEN=234dcef90c3d9aa0eb6798e16bdc1e4b

Generate Certificates

Now that we’ve finished configuring everything, it’s time to generate the certificates. Its as simple as:

# Lets generate the Letsencrypt SSL certificates
/srv/dehydrated/dehydrated --cron --hook /srv/dehydrated/ --challenge dns-01

Our certificates will be available in the following folder:



At this point we have working Letsencrypt SSL certificates for an internal/intranet domain that’s not accessible on the public internet.

I’ve written an example Dockerfile that you can reference if you’re curious. Just make sure to use docker run -e "PROVIDER=cloudflare" -e .. to set the environmental variables that you need.

If you’re wondering how to automate this whole process, check out my previous post: Automating SSL Certificates using Nginx & LetsEncrypt

Jason Kulatunga

Build Automation & Infrastructure guy @Adobe. I write about, and play with, all sorts of new tech. All opinions are my own.

San Francisco, CA

Subscribe to Sparktree

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!