Let's Encrypt for Internal Servers
Obtaining a trusted Let's Encrypt certificate for a Neth server that isn't accessible from the Internet.
The Problem
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.
The Solution
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 -s email=you@yourdomain.com
Substitute a valid email address in the command above, which will be used to register your account with Let's Encrypt. You should only receive messages there if a certificate is about to expire, which shouldn't happen. 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.
Default Certificate Authority
Since late 2021, acme.sh has defaulted to obtaining certificates from ZeroSSL rather than Let's Encrypt. These certificates are also provided at no cost, and have no difference with respect to security. But if you'd prefer to obtain certs from Let's Encrypt, you can change the default. To change this default, run:
acme.sh --set-default-ca --server letsencrypt
Configuration
Next, you’ll need to set some configuration database entries:
config setprop pki CrtFile /etc/pki/tls/certs/cert.crt config setprop pki ChainFile /etc/pki/tls/certs/cert-chain.crt config setprop pki KeyFile /etc/pki/tls/private/cert.key
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.
If using Acme DNShttps://wiki.nethserver.org/doku.php?id=userguide:let_s_encrypt_acme-dns&s[]=acme:
export ACMEDNS_BASE_URL="https://auth.acme-dns.io" export ACMEDNS_USERNAME="<username>" export ACMEDNS_PASSWORD="<password>" export ACMEDNS_SUBDOMAIN="<subdomain>"
Your credentials can be obtained by curl -s -X POST https://acme.example.com:8675/register | python -m json.tool
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.crt \ --ca-file /etc/pki/tls/certs/cert-chain.crt \ --key-file /etc/pki/tls/private/cert.key \ --reloadcmd "/sbin/e-smith/signal-event certificate-update"
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.