Acme-dns on Nethserver (now with RPM-y goodness!)


(Dan) #1

I previously wrote up a method to install acme-dns on your Neth server, which gives a couple of significant benefits:

  • It allows you to complete the Let’s Encrypt DNS challenge, and therefore obtain wildcard certificates, with just about any DNS provider, and
  • Even if your existing DNS provider has an API that’s supported by your preferred ACME client, acme-dns is much more limited, and therefore there’s much less exposure if your credentials should be compromised.

I’ve now prepared RPMs which should greatly simplify the process of installing and configuring acme-dns. Read on for instructions.

Caution: This module is in a pre-beta stage. It shouldn’t hurt anything, but may not behave as expected. If you notice unexpected behavior, let me know here and I’ll see what I can do.


Throughout this guide, your domain is represented as If you have more than one domain, this will be your primary domain. If you aren’t sure which domain is primary, config show DomainName will tell you. The external IP address of your Neth server is represented as $EXTERNAL_IP. Make appropriate substitutions below.

DNS Configuration

You’ll need to start by publishing the DNS records establishing your acme-dns instance as the authoritative nameserver for To do this, log in to your DNS provider and add the records below:	A	$EXTERNAL_IP	A	$EXTERNAL_IP		NS		NS

You’re done with DNS records for the time being.

Installing acme-dns

Begin by installing my repository; see the wiki for instructions. Then, simply yum --enablerepo=danb35 install nethserver-acme-dns. Your system will download and install the necessary packages.


The templates should configure acme-dns appropriately. One possible exception is the external IP address on which acme-dns will listen for DNS queries. If all of the following are true, then the templates should set this correctly:

  • You have one, and only one, red interface
  • Your red interface is configured to use a static IP address
  • Your red interface is configured to use a public static IP address
  • The public static IP address on your red interface is reachable from the Internet

If any of these is not true, you’ll need to set the address manually. To do this, do config setprop acme-dns ExternalIP, replacing with your public IP address. Then do signal-event nethserver-acme-dns-update.


To confirm that your acme-dns instance is up and running, run curl -s -X POST http://localhost:8675/register | python -m json.tool. You should get something like this as your output:

    "allowfrom": [],
    "fulldomain": "",
    "password": "x_Trpa04HpgQ4_ZOY7LCF6z23kf6o8i-VV_4qQk4",
    "subdomain": "44255c4e-d669-41f3-a141-672a8bd859e6",
    "username": "cc2d8066-2583-4e2c-a68f-ca45810c4f31"

Install the hook script

Nethserver ships with certbot installed, and certbot doesn’t, by itself, know how to talk to acme-dns. Fortunately, its author has written a script to handle this. Install it by running curl -o /etc/letsencrypt/ followed by chmod 0700 /etc/letsencrypt/ You’ll need to edit the script. Near the top, change ACMEDNS_URL to http://localhost:8675. No other changes need to be made.

Issue a certificate

All the prep work is now done, and it’s time to issue the certificate. Run

certbot certonly --manual --manual-auth-hook /etc/letsencrypt/ \
   --preferred-challenges dns --debug-challenges --post-hook "signal-event certificate-update" \
   -d -d \*

If you want more domains, add them with additional -d flags at the end. Certbot will ask you a few questions (email address, agree to TOS, share email with EFF, log IP address), and then show a message like this:

Output from
Please add the following CNAME record to your main DNS zone: CNAME

Waiting for verification...

Challenges loaded. Press continue to submit to CA. Pass "-v" for more info about
Press Enter to Continue

You’ll need to once again log into your DNS host and add the record specified. You’ll only need to do this once for each hostname. Wait a few minutes, then press Enter.

Enable HTTPS for acme-dns API

You can use acme-dns to validate any domain you control, as long as you can set the appropriate CNAME records. But if you’re going to be accessing its API remotely, you should really secure its API using HTTPS.

Get a certificate

We just created a wildcard certificate above, so we could use that, but it’s better practice to use a unique certificate for this service. To issue that certificate, run the following:

certbot certonly --manual --manual-auth-hook /etc/letsencrypt/ \
   --preferred-challenges dns --debug-challenges --post-hook "signal-event nethserver-acme-dns-update" \

Also as above, you’ll be told to create a CNAME record with your DNS host. Do that, wait a couple of minutes, then press Enter. Your certificate will be generated.

Configure acme-dns for HTTPS

This will take a couple of configuration entries:

config setprop acme-dns-api UseTLS enabled KeyPath /etc/letsencrypt/live/ FullchainPath /etc/letsencrypt/live/ access red,green
signal-event nethserver-acme-dns-update


As above, run curl -s -X POST | python -m json.tool. You should get something like this as your output:

    "allowfrom": [],
    "fulldomain": "",
    "password": "x_Trpa04HpgQ4_ZOY7LCF6z23kf6o8i-VV_4qQk4",
    "subdomain": "44255c4e-d669-41f3-a141-672a8bd859e6",
    "username": "cc2d8066-2583-4e2c-a68f-ca45810c4f31"

Adjust hook script

You’ll also need to update the hook script. Edit /etc/letsencrypt/ and change ACMEDNS_URL to, then save and exit.


Part of the reason for using Let’s Encrypt is that you can automate issuance and renewal of your certificates. To do this, you’ll need to create a simple cron job. Using your favorite text editor, create /etc/cron.daily/certbot with the following contents:

/usr/bin/certbot renew --quiet

Certbot will run every day, and when one of its certificates is within 30 days of expiration, will attempt to renew it.


  • Test, test, test
  • Make sure that the acme-dns systemd service is controlled by the status of the acmedns Nethserver service
  • Build the acme-dns binary from the Go source, rather than just packaging the author’s precompiled binary as an RPM

Community SPRINT
We Are NethServer - Community Overview - Sep 18
Certificate SSL Letsencrypt with wilcards crash ldap
(Dan) #2

On this point–it doesn’t look like it is working as it should, and I think the problem is the disagreement between the name of the service in systemd and the config database keys I’m using. The systemd service is called acme-dns, since that’s what the software is called. But hyphens aren’t valid characters in Perl variable names, so if I try to retrieve a config property of $acme-dns{foo} in a template, Perl complains. As a result, I’m using database keys of acmedns and acmednsapi, and the templates work fine with those.

So I’m probably missing something that’s already there, but I need to have the acme-dns systemd service enabled (and started) when $acmedns{status} = enabled.

(Stéphane de Labrusse) #3
${'acme-dns'}{'status'} eq 'enabled'

(Dan) #4

Is it that simple? Wow. Well, that should be easy to fix, anyway.

(Stéphane de Labrusse) #5


grep -srni 'acme\-dns' /etc/e-smith/templates

This should give back what you missed, grep is the better tools I know for a padawan developer, at least it helped me so much.

Install a nethserver with all modules and you will have an ultimate bank of example

(Dan) #6

That was it indeed. Fantastic. I’m sure it would benefit me to embark on a systematic study of Perl, but it just seems like that would take a lot of time. Though maybe not as much as trying random things I saw in a template somewhere…

(Stéphane de Labrusse) #7

test, break, try, this is what I do most of time :stuck_out_tongue:

when you want to code something, try to figure what you could search, var name is a good start.

(Dan) #8

That got me to the point of knowing that hyphens weren’t legal in Perl variable names, but not to the point of knowing what to do about it–at least yet. Probably would have found something eventually, but you beat me to it.

I still think this is something Neth should consider providing themselves, perhaps as a subscription benefit–it would avoid the issue of access to port 80, as well as enable wildcard certificates, about as simply as possible for the users. The only thing the users would need to do is set up the CNAME records with their DNS host, once for each (sub)domain. The only thing that would need to be packaged with Neth itself is the hook script.

(Dan) #9

Running into another issue, and I think this is due to how my config database keys are set up. In short, when installing software (including updates) through the software center, I get a red error message at the top of the screen indicating a problem with acme-dns. The problem appears to only be cosmetic–the software installs and runs without issues–but “big red warning banner” is a significant cosmetic issue. Looking in the log, I see

Jul  4 07:06:31 neth esmith::event[21173]: Failed to start acme-dns-api.service: Unit not found.

I use two config database keys, acme-dns and acme-dns-api. The main reason I do this is because the firewall settings will (or at least can) be different between the two–acme-dns itself must be accessible on the red interface (it must answer DNS queries from the outside world), while the API doesn’t need to be. However, there’s only one systemd service, and that’s acme-dns. Here’s how those keys are configured by default:

[root@neth ~]# config show acme-dns
[root@neth ~]# config show acme-dns-api

(OK, mostly by default–the fullchain, key, and UseTLS enabled aren’t there by default). How do I need to change this to avoid these errors?

(Markus Neuberger) #10

You may try to change the acme-dns-api to a network service instead of a service:

(Dan) #11

I’d thought about that, but had somehow gotten the idea that the fw_ keys were only appropriate when all you were doing was setting the firewall (the fw_ prefix probably helped me reach that conclusion). If that’s not the case, that sounds like the easy answer.

(Markus Neuberger) #12

The fw_ prefix is not mandatory, it’s just there to have an optical difference between NS controlled services and “firewall only” services.

(Markus Neuberger) #13

I tested the acme-dns module and it works. :+1: I followed the instructions from the wiki.

Again I had to use another domain than my servers domain name so I edited /etc/e-smith/templates/etc/acme-dns/config.cfg/10general and did config setprop acme-dns Domain

my $dmn = ${'acme-dns'}{'Domain'} || $DomainName;

my $domain = "acme.".$dmn;
my $nsname = "ns1.acme.".$dmn;
my $nsadmin = "admin.".$dmn;
my $domaindot = "acme.".$dmn.".";
my $nsnamedot = "ns1.acme.".$dmn.".";
my $ns2namedot = "ns2.acme.".$dmn.".";

HTTP worked without an error, I changed to HTTPS and after executing following command the cert is renewed but I got an error (I added the -v switch to get more output).

certbot certonly --manual --manual-auth-hook /etc/letsencrypt/ --preferred-challenges dns --debug-challenges --post-hook "/sbin/e-smith/signal-event certificate-update" -d -v


Hook command "/etc/letsencrypt/" returned error code 1
Error output from
Traceback (most recent call last):
  File "/etc/letsencrypt/", line 154, in <module>
    client.update_txt_record(account, VALIDATION_TOKEN)
  File "/etc/letsencrypt/", line 65, in update_txt_record
  File "/usr/lib/python2.7/site-packages/requests/", line 108, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/usr/lib/python2.7/site-packages/requests/", line 50, in request
    response = session.request(method=method, url=url, **kwargs)
  File "/usr/lib/python2.7/site-packages/requests/", line 464, in req                                                                                                                                                                                               uest
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python2.7/site-packages/requests/", line 576, in sen                                                                                                                                                                                               d
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.7/site-packages/requests/", line 431, in sen                                                                                                                                                                                               d
    raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:5                                                                                                                                                                                               79)

It worked so maybe the error could be ignored?

Old fashioned ex- and internal domain name for web-apps
(Dan) #14

…and in this case that’s completely fine; you can use any domain you want for this as long as you can control its DNS records. That seems like a worthwhile patch; I’ll try to incorporate that in the nethserver-acme-dns RPM.

Edit: Updated, should be in the repo in a few minutes.

This I haven’t seen before. For now (since it did work for you), I’d say keep an eye on it and see if it recurs.

(Markus Neuberger) #15

Maybe I was too impatient but:

Package nethserver-acme-dns-0.0.1-7.ns7.noarch.rpm is not signed

(Dan) #16

Oops. Should be fixed now.

(Markus Neuberger) #17

Thanks. Working as expected! :clap: