Let's Encrypt for Internal Servers

Obtaining a trusted Let's Encrypt certificate for a Neth server that isn't accessible from the Internet.

You want to get a TLS Certificate from Let’s Encrypt for an internal Nethserver installation that can’t be reached (specifically, can’t be reached on port 80) from the Internet. But the built-in support for Let’s Encrypt certs requires that your server be publicly accessible on port 80.

Background

Nethserver 7 includes the capability to automatically obtain and renew a trusted TLS certificate from Let’s Encrypt. This is a very useful capability, but due to the method it uses to validate your control over your domain name, it isn’t suitable for internal servers that can’t be reached from the Internet. Fortunately, Let’s Encrypt supports another validation method that’s much more suitable for this use case.

The built-in Let’s Encrypt support relies on the HTTP-01 validation mechanism. For this to work, the Let’s Encrypt servers need to be able to connect to http://your_fqdn/.well-known/acme-challenge/pseudorandomfilename and obtain the right content from that URL. If your server isn’t accessible from the Internet, with port 80 open to the Internet, this won’t work.

The alternate validation mechanism is the DNS-01 validator. In this method, a DNS TXT record is created for _acme-challenge.your_fqdn, with a long pseudorandom string as its contents. This method is only practical for automated use if your DNS host provides an API to allow client software to update your DNS records automatically. Although this validator is supported by the official client, Certbot, it has better support from some of the third-party clients.

Here, I’m going to describe how to use acme.sh to obtain a cert using DNS validation, assuming your DNS is hosted at Cloudflare. Cloudflare provides DNS hosting at no cost, and they have a robust, well-supported API which works well for these purposes. However, acme.sh supports the APIs of a number of DNS hosts; the list, along with instructions for use, can be found in the acme.sh documentation. All the commands below will be run as root from the shell on your Neth server.

If you do not have your DNS hosted with Cloudflare, you cannot follow these instructions as written–you'll need to adapt them for your DNS hosting solution.

If your DNS provider doesn't have a supported API, you may want to look into using acme-dns instead.

Installation

First, install acme.sh:

curl https://get.acme.sh | sh

This will download the acme.sh files, store them in ~/.acme.sh, and update your PATH environment variable to include that path.
Log out and back in to activate the new PATH.

Configuration

Next, you’ll need to set some configuration database entries:

config setprop pki CrtFile /etc/pki/tls/certs/cert.pem
config setprop pki ChainFile /etc/pki/tls/certs/chain.pem
config setprop pki KeyFile /etc/pki/tls/private/privkey.pem

Then, you’ll need to set the environment variables corresponding to your DNS validation credentials. The example below is for Cloudflare; this is where you’d need to make adjustments if you use a different supported DNS host–see the link above to the acme.sh documentation for details.

export CF_Key="YourCloudflareGlobalAPIKey"
export CF_Email="user@example.com"

Your API key can be obtained through your user profile page on Cloudflare. Cloudflare offers two keys, one with read-only access, and the other with full control. You’ll need to use the one with full control, which they call the Global API key. The email address above is the address you used to register for Cloudflare.

Issue the certificate

Next, actually issue the certificate:

acme.sh --issue --dns dns_cf -d your_fqdn -d your_other_fqdn -d \*.third_fqdn \
  --cert-file /etc/pki/tls/certs/cert.pem \
  --ca-file /etc/pki/tls/certs/chain.pem \
  --key-file /etc/pki/tls/private/privkey.pem \
  --reloadcmd "/sbin/e-smith/signal-event certificate-update"

dn This command will issue your certificate, specify the paths for the cert, key, and chain files to be copied to, and indicate that signal-event certificate-update is to be run whenever this cert renews. You can include as many FQDNs in the cert as you want by just adding more -d fqdn parameters. As above, if you aren’t using Cloudflare, change dns_cf to the appropriate API for your DNS host, as described at the documentation linked above.

To avoid exceeding the Let's Encrypt rate limits, you should use the –test flag until you're sure everything is working properly. The command above would then look like:

 acme.sh --issue --test --dns ...

That’s it! Your certificate is issued, and will renew automatically every 60 days.