Help me understand acme-dns

Hi @danb35,

Yes to the download and install part ;). Regarding the init script, if your distribution uses systemd you can create the service conf, for example, create a new file /etc/systemd/system/acme-dns.service with this conf:

[Unit]
Description=acme-dns Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/acme-dns/acme-dns

[Install]
WantedBy=multi-user.target

Note: you should change the path to acme-dns with the right one.

Edit: I forgot to say that if you use the above init script the config file for acme-dns must be in /etc/acme-dns/config.cfg

And enable it:

systemctl enable acme-dns

Well, indeed you only need to define one domain, in your case I will use acme.example.com. With this configured you will be able to use it for all your domains.

Yes, if port 80 and 443 are in use you should choose another one ;).

As example.com points to the same server you installed acme-dns that will work but I think it would be a bit clear if you use another subdomain, acme.example.com.

You can use curl to register a new entry:

$ curl -X POST http://acme.example.com:port/register

And if all is correct you will receive a response like this:

{"username":"175d7b7s-6bb6-4b66-a597-cb4de62d89av","password":"Ac23UEL1hX0ZxQarQ2adBJ08IrAZkHdccHMjt4Dk","fulldomain":"a2f7df8a-e3d6-4225-a130-5ed56a1db8f3.acme.example.com","subdomain":"a2f7df8a-e3d6-4225-a130-5ed56a1db8f3","allowfrom":[]}

Yes, you need to save the credentials and you will need to repeat the process for every domain/subdomain, in your example, yes, three registrations.

Yes, using the example registration, if you want to use that registration for example.com you will need to create a CNAME record for _acme-challenge.example.com pointing to a2f7df8a-e3d6-4225-a130-5ed56a1db8f3.acme.example.com

I'm following the example of acme.example.com so you will need to create in your dns zone for example.com a NS record for domain acme.example.com pointing to for example ns1.acme.example.com and an A or AAAA record for ns1.acme.example.com pointing to the ip of the acme-dns server.

And edit the conf file for acme-dns to be something like this:

[general]
# dns interface
listen = ":53"
# protocol, "udp", "udp4", "udp6" or "tcp", "tcp4", "tcp6"
protocol = "udp"
# domain name to serve the requests off of
domain = "acme.example.com"
# zone name server
nsname = "ns1.acme.example.com"
# admin email address, where @ is substituted with .
nsadmin = "admin.acme.example.com"
# predefined records served in addition to the TXT
records = [
    # default A
    "acme.example.com. A 203.0.113.21",
    # A
    "ns1.acme.example.com. A 203.0.113.21",
    # NS
    "acme.example.com. NS ns1.acme.example.com.",
]
# debug messages from CORS etc
debug = false

[database]
# Database engine to use, sqlite3 or postgres
engine = "sqlite3"
# Connection string, filename for sqlite3 and postgres://$username:$password@$host/$db_name for postgres
# Please note that the default Docker image uses path /var/lib/acme-dns/acme-dns.db for sqlite3
connection = "/etc/acme-dns/acme-dns.db"
# connection = "postgres://user:password@localhost/acmedns_db"

[api]
# domain name to listen requests for, mandatory if using tls = "letsencrypt"
api_domain = ""
# listen ip eg. 127.0.0.1
ip = "0.0.0.0"
# disable registration endpoint
disable_registration = false
# autocert HTTP port, eg. 80 for answering Let's Encrypt HTTP-01 challenges. Mandatory if using tls = "letsencrypt".
autocert_port = "80"
# listen port, eg. 443 for default HTTPS
port = "8080"
# possible values: "letsencrypt", "cert", "none"
tls = "none"
# only used if tls = "cert"
tls_cert_privkey = "/etc/tls/acme.example.com/privkey.pem"
tls_cert_fullchain = "/etc/tls/acme.example.com/fullchain.pem"
# CORS AllowOrigins, wildcards can be used
corsorigins = [
    "*"
]
# use HTTP header to get the client ip
use_header = false
# header name to pull the ip address / list of ip addresses from
header_name = "X-Forwarded-For"

[logconfig]
# logging level: "error", "warning", "info" or "debug"
loglevel = "debug"
# possible values: stdout, TODO file & integrations
logtype = "stdout"
# file path for logfile TODO
# logfile = "./acme-dns.log"
# format, either "json" or "text"
logformat = "text"

Let's Encrypt will ask to the zone of your example.com domain what is the content for the TXT record for _acme-challenge.example.com, then the DNS server will say, ooops I've no TXT record but I have a CNAME that points to a2f7df8a-e3d6-4225-a130-5ed56a1db8f3.acme.example.com and Let's Encrypt will follow that domain, and the example.com dns server will say to LE that the authoritative dns server for acme.example.com is ns1.acme.example.com and it will give the ip too, so LE will ask to ns1.acme.example.com what is the TXT record for a2f7df8a-e3d6-4225-a130-5ed56a1db8f3.acme.example.com and acme-dns will answer that question ;), I don't know if I've explained it very well :frowning: seems a bit confusing but it isn't :wink:

Yes, as an example, if LE gives you the token abcdef1234567890987654321abcdef123456789098 in our example you need to create the TXT record as follows:

$ curl -X POST http://acme.example.com:port/update -H "X-Api-User: 175d7b7s-6bb6-4b66-a597-cb4de62d89av" -H "X-Api-Key: Ac23UEL1hX0ZxQarQ2adBJ08IrAZkHdccHMjt4Dk" --data '{"subdomain": "a2f7df8a-e3d6-4225-a130-5ed56a1db8f3", "txt": "abcdef1234567890987654321abcdef123456789098"}'

If you are trying to reach the acme-dns API from a remote machine you should consider using https instead of http.

I hope this helps.

Cheers,
sahsanu

2 Likes