Skip to content

Acme DNS Server

Gridworkz edited this page Nov 13, 2018 · 1 revision

Acme-DNS Server Setup

Acme-DNS is a small DNS server with the sole purpose to handle ACME DNS challenges. This is a great way to automate your challenges without the support of your DNS provider. The server is a t2.micro at AWS running Ubuntu 16.04 LTS.

1. Installing Certbot (no web server)

For Ubuntu, a PPA is provided for Certbot. To install, run:

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot

2. Installation of Acme-DNS

To install acme-dns you need Go

$ sudo apt-get install golang-go

Make sure you install Go 1.9 or higher. You can verify this by typing go version in the console.

$ go version
go version go1.9.4 linux/amd64

Now download acme-dns with the following command:

$ go get github.com/joohoi/acme-dns/…

This downloads acme-dns to the directory /home/<user>/go/bin/acme-dns. Now copy or move the binary to a more appropriate place:

$ sudo cp /home/<user>/go/bin/acme-dns /usr/local/bin/acme-dns

Don’t forget to replace with the user used to download acme-dns.

3. Configuration of Acme-DNS

The acme-dns executable needs a folder for its SQLite database and a configuration file placed in /etc/acme-dns/. So let’s create the two needed folders as root:

sudo mkdir /etc/acme-dns/ /var/lib/acme-dns

Now let’s get the configuration file template from GitHub and placed it in the newly created folder:

$ sudo wget https://raw.githubusercontent.com/joohoi/acme-dns/master/config.cfg -O /etc/acme-dns/config.cfg

You need to execute wget with sudo because the folder is only writeable as root. Now open the downloaded config.cfg file with your favorite console editor, also as root:

$ sudo nano /etc/acme-dns/config.cfg

In the example configuration file, the domain example.org is used. Modify the first section and replace example.org with your domain name.

# domain name to serve the requests off of
domain = "auth.example.org"
# zone name server
nsname = "ns1.auth.example.org"
# admin email address, where @ is substituted with .
nsadmin = "admin.example.org"

In the next section you need to modify the predefined DNS records:

# predefined records served in addition to the TXT
records = [
    # default A
    "auth.example.org. A 192.168.1.100",
    # A
    "ns1.auth.example.org. A 192.168.1.100",
    # NS
    "auth.example.org. NS ns1.auth.example.org.",
]

Again, replace example.org with your domain name. Replace 192.168.1.100 with the public IP address of your host. Remove the two lines with ns2.auth.example.org as we only need one nameserver entry.

Acme-DNS needs two ports. UDP Port 53 for DNS and TCP port 80 for its REST service. You shouldn’t change the port for DNS but you can change the HTTP port. This is necessary, when a web server is already running, like apache2 or nginx. So let’s change the HTTP port to 81.

# listen port, eg. 443 for default HTTPS
port = "81"

You can leave the other values unchanged. You can find more information about the possible configurations at acme-dns GitHub repository

4. Systemd Service to Run Acme-DNS

So that acme-dns can run as a service on your host it’s convenient to create a systemd service which takes care about starting/stopping acme-dns.

Create the user acme-dns with the following command:

$ sudo adduser --system --base-dir /var/lib/acme-dns acme-dns

Change the owner of /var/lib/acme-dns so the freshly created user has the permissions needed.

$ sudo chown acme-dns:acme-dns /var/lib/acme-dns

If you copied the acme-dns binary to another directory remember to change the path accordingly.

Now create and open the acme-dns.service file in /etc/systemd/system/:

$ sudo nano /etc/systemd/system/acme-dns.service

and put the following content into the file:

[Unit]
Description=Limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely
After=network.target

[Service]
User=acme-dns
Group=acme-dns
Type=simple
AmbientCapabilities=CAP_NET_BIND_SERVICE
Restart=on-failure
ExecStart=/usr/local/bin/acme-dns

[Install]
WantedBy=multi-user.target

Make sure the ExecStart value matches the place where you copied the acme-dns binary at in the “Installation of acme-dns” section.

Save and close the service file.

To activate the service we need to reload the systemd manager configuration:

$ sudo systemctl daemon-reload

Now you can start acme-dns:

$ sudo systemctl start acme-dns

To check if acme-dns started successfully type:

$ sudo systemctl status acme-dns
acme-dns.service -- acme-dns Service
Loaded: loaded (/etc/systemd/system/acme-dns.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2018-08-06 00:05:25 CEST; 13min ago
[…]

and check if it’s Active: active (running)

Now enable the acme-dns service so it starts after a reboot:

$ sudo systemctl enable acme-dns

5. Firewall Rules for Acme-DNS

So that acme-dns can answer DNS requests from the Let’s Encrypt servers you need to open port 53 in your firewall.

For firewalld:

$ sudo firewall-cmd --add-port=53/udp --permanent
$ sudo firewall-cmd --reload

For iptables:

$ sudo iptables-A INPUT -p udp -m udp --dport 53 -j ACCEPT
$ sudo iptables -A OUTPUT -p udp -m udp --sport 53 -j ACCEPT

If you want to make the acme-dns REST API public available too, you need to open up the configured HTTP port too. This is not necessarily recommended as this service doesn’t need to be public if you run acme-dns on the same machine as Certbot.

For firewalld:

$ sudo firewall-cmd --add-port=81/tcp --permanent
$ sudo firewall-cmd --reload

For iptables:

iptables -A INPUT -p tcp -m tcp --dport 81 -j ACCEPT

For UFW (both ports):

$ sudo ufw allow 53/udp
$ sudo ufw allow 81/tcp

6. DNS Records

To make acme-dns able to receive DNS requests, we need to add two DNS records on your domains regular DNS provider:

  • NS record for auth.example.org pointing to ns1.auth.example.org.
  • A record for ns1.auth.example.org pointing to the public IP address of your host.

Replace example.org with your domain name. Depending on your DNS provider it may take up to 30 minutes until these records are active.

7. Testing Acme-DNS

You followed a lot of steps to make acme-dns working. Let’s test if everything’s working correctly.

To test if the required DNS NS record is set correctly you can simply use dig. Don’t forget to replace example.org with your domain.

$ dig +noall +answer auth.example.org
auth.example.org. 2366 IN A 192.168.1.100

Verify that auth.example.org is pointing to the public IP address of your host.

$ dig +noall +answer -t NS auth.example.org
auth.example.org. 3598 IN NS ns1.auth.example.org.

Verify that auth.example.org is pointing to ns1.auth.example.org.

Run the following command to get register via the acme-dns REST API. We access the API directly via localhost so no firewall rule is needed.

$ curl -X POST http://localhost:81/register
{“username”:”e0ad1a12-57eb-4916-8ac7-e115e44b018b”,”password”:”rrJSQj1-D4tgEw_vUegB_J28XhBkG31sr-6DKo0i”,”fulldomain”:”e8c5bb21-3e02-4e51-a99f-284d8a631a4a.auth.example.org”,”subdomain”:”e8c5bb21-3e02-4e51-a99f-284d8a631a4a”,”allowfrom”:[]}

If everything works correctly your getting a JSON with acme-dns user credentials. You don’t need to save these as it’s a test only.

8. Setup Acme-DNS Hook for Certbot

To automate the ACME DNS challenge with acme-dns you need a hook for Certbot. There’re two available: One written in Python and one in Go. We proceed using the Python version.

Download the latest hook script from GitHub into the /etc/letsencrypt/ directory and give it the necessary permissions:

$ sudo wget -O /etc/letsencrypt/acme-dns-auth.py https://raw.githubusercontent.com/joohoi/acme-dns-certbot-joohoi/master/acme-dns-auth.py
$ sudo chmod 0700 /etc/letsencrypt/acme-dns-auth.py

Now you need to change the predefined URL in acme-dns-auth.py:

sudo nano /etc/letsencrypt/acme-dns-auth.py
# URL to acme-dns instance
ACMEDNS_URL = "http://localhost:81"

You can define http://localhost:81 here if Certbot is running on the same machine as your acme-dns service. If you defined a different port in the configuration section, change it accordingly. Save and close the file.

9. Running Certbot with acme-dns-hook.py

Verify that you deleted all your _acme-challenge.example.org TXT DNS records to prevent unwanted failures.

Now to finally test Certbot with acme-dns and its' hook run:

$ sudo certbot certonly --server https://acme-v02.api.letsencrypt.org/directory --preferred-challenges dns --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --debug-challenges
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Please enter in your domain name(s) (comma and/or space separated) (Enter ‘c’
to cancel): example.org *.example.org

Replace example.org and *.example.org with your domain name and press enter.

You have an existing certificate that has exactly the same domains or certificate name you requested and isn’t close to expiry.
(ref: /etc/letsencrypt/renewal/example.org.conf)
What would you like to do?
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
1: Keep the existing certificate for now
2: Renew & replace the cert (limit ~5 per 7 days)
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Select the appropriate number [1-2] then [enter] (press ‘c’ to cancel): 2

As we already issued a certificate in the beginning but want to replace it to test the process with acme-dns, hit 2 and press enter. Note that you only can issue 5 certificates per week.

Renewing an existing certificate
Performing the following challenges:
dns-01 challenge for cooby.online
dns-01 challenge for cooby.online
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you’re running certbot in manual mode on a machine that is not
your server, please ensure you’re okay with that.
Are you OK with your IP being logged?
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
(Y)es/(N)o: y
Output from acme-dns-auth.py:
Please add the following CNAME record to your main DNS zone:
_acme-challenge.example.org CNAME 23c2f5c5-e92e-4979-a6c2-5154b5ebb99f.auth.example.org.
Waiting for verification…
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Challenges loaded. Press continue to submit to CA. Pass “-v” for more info about
challenges.
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Press Enter to Continue

Now your asked to add a CNAME DNS record for _acme-challenge.example.org pointing to the URL printed to the console. Here it’s 23c2f5c5-e92e-4979-a6c2-5154b5ebb99f.auth.example.org, but make sure you’re using the URL in your console output.

As a reminder: Verify that you deleted all your _acme-challenge.example.org TXT DNS records to prevent unwanted failures.

After you added the required CNAME DNS record, verify in a separate terminal that it’s already active:

$ dig +noall +answer _acme-challenge.example.org
_acme-challenge.example.org. 263 IN CNAME fd3e11e8-8af4-42dd-b70d-1cc6d9c4482c.auth.example.org.

It may take some time until the record is active. After you verified that the CNAME record is in place, you can continue the certbot process with enter.

Cleaning up challenges
IMPORTANT NOTES:
-- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.org/privkey.pem
Your cert will expire on 2018-11-03. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
“certbot renew”
-- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

If everything worked correctly you should see the message above. If not, check again if you followed all steps correctly. These steps are currently running at cooby.online.

10. Setup cronjob for Automated Renewal

Finally, we can add a cronjob to run certbot renew daily. This command only renews the certificate if it close to expiration.

Run crontab as root:

sudo crontab -e

And add the following text to run cerbot renew every day at 2:30 in the morning:

30 2 * * * /usr/local/bin/certbot renew >> /var/log/le-renew.log

If you’re using the Let’s Encrypt certificate with ngnix or apache2, you can add a post-hook:

30 2 * * * /usr/local/bin/certbot renew --post-hook "systemctl reload nginx" >> /var/log/le-renew.log

Replace systemctl reload nginx with the command needed to restart your web server. If something didn’t work as expected, you can check the output in the /var/log/le-renew.log file with tail -f or less.

Congratulations! You’ve set up the automated renewal of wildcard certificates via Acme-DNS.