In this post an acme-dns server will be set up and a client will acquire a Let’s Encrypt certificate using the DNS-01 challenge.

Acme-dns provides a simple API exclusively for TXT record updates and should be used with ACME magic “_acme-challenge” - subdomain CNAME records. This way, in the unfortunate exposure of API keys, the effects are limited to the subdomain TXT record in question. https://github.com/joohoi/acme-dns

Network topology

In this post the following is assumed:

The future acme-dns server has an IP address of 192.0.2.100 . The following DNS records have been created:

acme-dns.example.com. A 192.0.2.100 a.acme-dns.example.com. NS acme-dns.example.com.

If you manage your own DNS or your provider supports it, you can just use acme-dns.example.com. NS acme-dns.example.com. . Cloudflare does not support records for a host if a different nameserver was set, so I will use the subdomain a. for the acme-dns-managed DNS entries.

Prerequisites

To install acme-dns we need git, gcc and go.

sudo yum install git gcc -y # install go: wget https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.11.4.linux-amd64.tar.gz sudo ln -s /usr/local/go/bin/* /usr/local/bin

Install acme-dns as a service

The following will build and install the acme-dns binary.

go get github.com/joohoi/acme-dns/... sudo mv ~/go/bin/acme-dns /usr/local/bin/acme-dns

Now we need to add a user for the acme-dns service and set up the service itself

sudo adduser --system --home /var/lib/acme-dns acme-dns sudo mkdir /var/lib/acme-dns sudo chown acme-dns: /var/lib/acme-dns sudo wget -O /etc/systemd/system/acme-dns.service https://raw.githubusercontent.com/joohoi/acme-dns/master/acme-dns.service sudo systemctl daemon-reload

As I was getting errors trying to set the capabilities (allow binding to a port <1000) in the service configuration, I removed that part from the configuration and gave the executable the required permissions directly:

sudo sed -i 's/AmbientCapabilities/#AmbientCapabilities/g' /etc/systemd/system/acme-dns.service sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/acme-dns sudo systemctl daemon-reload

Configure acme-dns

We can use the example configuration file with our own dns-name and ip address.

sudo mkdir /etc/acme-dns sudo wget -O /etc/acme-dns/config.cfg https://raw.githubusercontent.com/joohoi/acme-dns/master/config.cfg sudo sed -i 's/^listen = .*/listen = ":53"/g' /etc/acme-dns/config.cfg sudo sed -i 's/auth.example.org/a.acme-dns.example.com/g' /etc/acme-dns/config.cfg sudo sed -i 's/198.51.100.1/192.0.2.100/g' /etc/acme-dns/config.cfg sudo sed -i 's/^connection = .*/connection = "\/var\/lib\/acme-dns\/acme-dns.db"/g' /etc/acme-dns/config.cfg

Acme-dns supports acquiring it’s own SSL certificate via Let’s Encrypt and serving it’s API on https.

sudo sed -i 's/^tls = .*/tls = "letsencrypt"/g' /etc/acme-dns/config.cfg sudo sed -i 's/^port = .*/port = "443"/g' /etc/acme-dns/config.cfg sudo sed -i 's/^api_domain = .*/api_domain = "acme-dns.example.com"/g' /etc/acme-dns/config.cfg sudo sed -i 's/^acme_cache_dir = .*/acme_cache_dir = "/var/lib/acme-dns/cert"/g' /etc/acme-dns/config.cfg

Starting the service

sudo systemctl enable acme-dns.service sudo systemctl start acme-dns.service

Client-side

Now we can switch to the client that is supposed to get it’s own certificate issued. First we need to register a new subdomain on the acme-dns server. The response will contain the details needed for the next steps.

curl -X POST https://acme-dns.example.com/register { "username" : "eabcdb41-d89f-4580-826f-3e62e9755ef2" , "password" : "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0" , "fulldomain" : "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.a.acme-dns.example.com" , "subdomain" : "d420c923-bbd7-4056-ab64-c3ca54c9b3cf" , "allowfrom" : [] }

We can now set up DNS accordingly. In this example, the response contains the subdomain d420c923-bbd7-4056-ab64-c3ca54c9b3cf and we want to set up the domain server01.example.com so that a certificate can be issued using acme-dns.

_acme-challenge.server01.example.com. CNAME d420c923-bbd7-4056-ab64-c3ca54c9b3cf.a.acme-dns.example.com.

When the entries finished propagating we can install acme.sh and issue a certificate using the acme-dns method. All settings will be saved and the certificate will be renewed automatically.

curl https://get.acme.sh | sh export ACMEDNS_UPDATE_URL = "https://acme-dns.example.com/update" export ACMEDNS_USERNAME = "eabcdb41-d89f-4580-826f-3e62e9755ef2" export ACMEDNS_PASSWORD = "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0" export ACMEDNS_SUBDOMAIN = "d420c923-bbd7-4056-ab64-c3ca54c9b3cf" ~/.acme.sh/acme.sh --issue --dns dns_acmedns -d server01.example.com