-
Notifications
You must be signed in to change notification settings - Fork 0
Acme DNS Server
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.
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
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.
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
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
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
To make acme-dns able to receive DNS requests, we need to add two DNS records on your domains regular DNS provider:
-
NS
record forauth.example.org
pointing tons1.auth.example.org
. -
A
record forns1.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.
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.
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.
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.
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.