DirectAdmin 1.706

Let us know if you find any corner cases where the new system could be improved! Thanks.

Uh, yeah! It is not possible to give lego parameters. Before the change it was easy, i just added the flags (like --preferred-chain) in the letsencrypt.sh file.
Now i've disabled the auto download for the lego binairy, created hookscritps and... and... and..., just to add a flag!
Please stop killing directadmin by moving everthing to the binary en remove all possibilities for customization!
 
@Joriz, you can remove the certificate management page section by adding the `domain-tls` command to never_commands. Example:

Code:
# da config-set never_commands domain-tls --restart

(note this will replace any existing commands listed there, if you already use this feature append the domain-tls command instead of replacing).
 
@Joriz, you can remove the certificate management page section by adding the `domain-tls` command to never_commands. Example:

Code:
# da config-set never_commands domain-tls --restart

(note this will replace any existing commands listed there, if you already use this feature append the domain-tls command instead of replacing).
This completely disables the 'Manage certificate' feature. We only want to disable the ACME feature as we have already Let's Encrypt automated.

Customers still want/need to install certificates manually they eg bought at Comodo.
 
@fln

this has been re-written with ai, to try to make it more clear and a lot less wall-text that what i had.


Following up on #23/#27. We run 10 DA servers, ~6,600 domains with `ssl=ON`. In the last two weeks alone we have handled **91 SSL cases**. We have now finished auditing and remediating the whole fleet, and the causes turned out to be a small number of specific behaviours. Ranked by how much damage they do to us:

---

**1. DA never adopts a certificate it did not issue, and cannot be made to.**

If a certificate arrives any other way (cPanel migration, transfer, restore), DA serves it, shows `ssl=ON` and `acme_provider=letsencrypt`, and then never renews it. Nothing in the UI or the domain config distinguishes it from a managed certificate. The only reliable discriminator we found is whether this exists:

```
/usr/local/directadmin/data/users/<user>/domains/acme_provider_cert_logs/<domain>.log
```

Fleet-wide that was **714 domains**. After filtering out those legitimately out of scope (website hosted elsewhere, or no DNS at all), **262 genuinely needed adopting**. We ran `letsencrypt.sh request` against every one:

- **141 adopted successfully.** Every single one had an already-expired certificate.
- **121 refused.** Every single one still has a valid certificate.

The split is exactly along the expiry line, which makes this a catch-22:

- While the certificate is valid, DA refuses to reissue (#24), so the domain cannot enroll.
- Once it expires, the site is already down, and only then does DA act.

On one server that ratio is 4 adopted out of 97, purely because that server's migration is more recent. Those 121 have a known break date: **7 this month, 78 in September, 33 in October.** We know exactly which sites will go down and when, and the only lever available is deleting certificate files out from under live vhosts, which we will not do at scale.

Compounding it: `admin_ssl_replace_all_expired_invalid` is the only mechanism that catches these, but with `admin_ssl_check_expiry_offset=0` it evaluates a certificate only **after** expiry:

```
Ssl::admin_ssl_should_domain_retry:<user>:<domain>: domain certificate has expired:
expiry(1785544163 - 0days(1785544163)) < now(1785544216)
```

53 seconds after expiry. That offset is not exposed in the new ACME options UI.

**Ask:** adopt unmanaged certificates at the normal renewal threshold, and/or give us `letsencrypt.sh request --force`. Who originally issued a certificate should not determine whether it gets renewed.

---

**2. The HTTP pre-check uses the local resolver, and the error message blames DNS.**

A customer created a subdomain. DA refused with:

> DNS names listed here cannot get automatic certificates because an HTTP request for these names does not reach this server. It can happen if there are no DNS records for these names or DNS records point to a different server.

All of that was false. The record existed in the zone, resolved correctly worldwide, and the ACME challenge returned HTTP 200 when fetched from an external host. The actual cause:

```
dig +short newsub.example.cl A @127.0.0.1 -> empty
dig +short newsub.example.cl A @1.1.1.1 -> <our server IP>
```

The local resolver had a **cached negative answer** from before the subdomain was created. `www.newsub` had never been queried, so it resolved fine, and DA issued a certificate covering `www.newsub` only, which is the one name the customer does not use. `unbound-control flush_zone` fixed it.

**Ask:** the pre-check should not trust a local recursive resolver for names the server is itself authoritative for, and the error text should say the check failed locally rather than asserting the customer's DNS is wrong. As written it sends operators and customers to debug the wrong thing.

---

**3. `letsencrypt.sh request` ignores the DNS name list it is given.**

Passing an explicit comma-separated list does not select those names. DA re-applies `letsencrypt_list_selected` and issues whatever it decides. Requesting `sub.example.cl,www.sub.example.cl` logs `dns-names=[sub.example.cl]` and produces a single-name certificate; requesting only `mail/pop/smtp` still triggers challenges against the apex, `www` and `ftp`. We hit this three times in two days in unrelated scenarios. If the argument is documented as selecting names, it should select them, and there is currently no supported way to put a bare name and its `www` into one certificate.

---

**4. Names that pass validation are discarded when the primary name fails.**

A customer hosts their website elsewhere and uses us only for mail. `mail`, `pop` and `smtp` all validated successfully. DA threw them away:

```
debug DNS name skipped because of failed HTTP challenge check dnsName=example.cl
debug DNS name skipped because of failed HTTP challenge check dnsName=www.example.cl
debug DNS name skipped because no valid certificate id exists to store it \
challengeType=HTTP-01 dnsName=mail.example.cl
```

A partial success becomes a total failure and the domain ends up with no certificate at all. The cPanel certificate being replaced covered exactly `cpanel/mail/webmail`, so this is clearly issuable.

Related: with DNS hosted externally (Cloudflare, in most of our cases), the default `www:mail:ftp:pop:smtp` list routinely contains names that do not exist in the zone. `ftp` is the usual offender. That should be a skipped name, not a failed request.

---

None of these are exotic configurations. Items 1 and 2 in particular produce outages that we cannot prevent and that customers discover before we do. Happy to provide full logs or run diagnostics on our side.
 
As of yesterday had a couple of servers to work on with a bunch of domains which I had to address manually (they had worked fine for years with valid Letsencrypt certificates). Here is what I found:

1. New ACME feature does propagate to use nameservers from /etc/resolv.conf. For some reasons DNS resolvers from DC are enough slow to catch challenge records in DNS. And a certificate renewal/issue breaks. So here again we need to use none-caching DNS resolvers such as 1.1.1.1,8.8.8.8.

2. Stealth nameservers in a DNS zone break a DNS validation. So I had to clean every domain with wrong nameservers.

Even fixed the both, still some domains fail for unknown reasons. So I had to disable wildcard- certificate mode, which is enabled by default.

Too much pain when users/admins are on vacations alongside with multiple vulnerabilities in WP and kernels.

p.s. Not complaining, but trying to master the new feature. Funny)))
 
@Zhenmue, thanks for sharing the details about the problems you have encountered. Hope I can help to shed some light on the cert system.

1. DA never adopts a certificate it did not issue, and cannot be made to.
This was true for the old TLS system, but no longer true for new TLS system. If new TLS system is enabled (the acme_enabled=yes in domain.conf file). It will try issuing new certificates when old certificates are near expiration. The only way to opt out from the ACME certificates when the new ACME mode is enabled is to list the manually managed certificates in the acme_skip_dns_names lists (in domain.conf).

This is the main difference from the old system. In the old system you had to explicitly request a set of names to be covered with certificates. New system tries to always cover all names.

Options admin_ssl_replace_all_expired_invalid and admin_ssl_check_expiry_offset are for the old TLS system. If the new system is enabled they are ignored (in single domain scope, some domains can use the old system while others are using the new one).

The new system will issue new certs when certificate will expire in less than letsencrypt_renew_before_expiry_days. You can force new certificates to be issued now by deleting the old certificate.

I think the assumption that certificates will not be renewed is a misunderstanding by applying the old system behaviour on the new TLS system. Even if ./letsencrypt.sh domain.com reports that nothing needs to be done right now, the certificate will be renewed in due time.

2. The HTTP pre-check uses the local resolver, and the error message blames DNS.

Yes. DA uses the default system resolver for all DNS lookups. Using local bind as system resolved will cause all kinds of problems. Please update the server configuration and never use local authoritative bind server as a system resolver!

Having nameserver 127.0.0.1 in /etc/resolv.conf is literally asking for trouble. If you do not want to use public resolvers please use local Unbound:
Code:
da build set unbound yes
da build set unbound_as_default_resolver
da build unbound

3. `letsencrypt.sh request` ignores the DNS name list it is given.

Yes. The core principal of the new system is that users no longer need to manually list all the DNS names they want. DA will issue certificates for all the names that passes preliminary tests (HTTP challenge or DNS challenge).

4. Names that pass validation are discarded when the primary name fails.

This issue is fixed in the DA 1.707 release. If the main domain name is not reachable a certificate with additional domains will still be issued.
 
@zEitEr, in the last DA release we are adding a special permanent DNS cache busting record:
Code:
dig +short _acme-challenge.example.com in txt
"persistent-record"

This makes sure that even if you are using a caching DNS resolver it will detect new DNS records in 2 minutes.

This was added in DA 1.707 because lego v5 uses DNS much more aggressively and almost always poison the DNS cache with NXDOMAIN answer before DNS challenge can be solved.



DA uses NS record mismatch to detect if DA is actually managing the domain or not. If system resolver says domain.com uses ns1.example.com and ns2.example.com, but local bind says domain.com uses ns1.server.com and ns2.server.com, this is a flag for DA to assume local bind does not control this domain and to not try DNS challenge with local bind (it would still use DNS challenge it if custom DNS provider is configured).

If DA do actually control the domain DNS zone, then syncing NS records will unlock the automatic ACME DNS challenge. If DA does not actually control the domain DNS zone, then syncing NS records will break ACME DNS challenge.
 
Yes. The core principal of the new system is that users no longer need to manually list all the DNS names they want. DA will issue certificates for all the names that passes preliminary tests (HTTP challenge or DNS challenge).
But why? Maybe someone doesn't want SSL for a certain subdomain. Also generating Let's Encrypt SSL automatically triggers a bot-scanning attack a few minutes later when certificate appears in crt.sh etc.
If there are hundreds of these subdomains, it's a ready recipe for server crashing.
 
@pat0, if TLS is disabled for the domain certificates will not be issues. Individual subdomains can be excluded. That is why ACME DNS challenge and wild-card certificates are preferred by default.

I think there are more users out there who prefer to have all subdomains functional over TLS than those who want to use subdomains with plain-text HTTP only.
 
@zEitEr, in the last DA release we are adding a special permanent DNS cache busting record:


Why would DA persist on trying DNS for a domain with wrong nameservers?

Failed with "no such host" error:

Code:
Failed to issue a TLS certificate for some-hosting-here.nl, *.some-hosting-here.nl DNS names.
--- Command output
2026-08-04T14:08:18.478800702+02:00 INFO  Obtaining SAN certificate. domains="some-hosting-here.nl, *.some-hosting-here.nl"
2026-08-04T14:08:19.305825877+02:00 INFO  Authorization is already valid; skipping the challenge. domain=some-hosting-here.nl
2026-08-04T14:08:19.305954629+02:00 INFO  Use solver. domain=*.some-hosting-here.nl type=dns-01
2026-08-04T14:08:19.306021498+02:00 INFO  dns01: preparing to solve the challenge. domain=*.some-hosting-here.nl
2026-08-04T14:08:20.908828922+02:00 INFO  2026/08/04 14:08:20  info executing task            task=action=dns&do=add&domain=some-hosting-here.nl&name=_acme-challenge&ttl=120&type=TXT&value=%22persistent-record%22
2026-08-04T14:08:21.609531113+02:00 INFO  2026/08/04 14:08:21  info finished task             duration=700.657856ms task=action=dns&do=add&domain=some-hosting-here.nl&name=_acme-challenge&ttl=120&type=TXT&value=%22persistent-record%22
2026-08-04T14:08:22.595703921+02:00 INFO  2026/08/04 14:08:22  info executing task            task=action=dns&do=add&domain=some-hosting-here.nl&name=_acme-challenge&named_reload=yes&ttl=120&type=TXT&value=%22EYJvDjgwzw0sJ48wpCY1mSVs4ZnHZns7qYkDyMlwTXw%22
2026-08-04T14:08:25.447797058+02:00 INFO  2026/08/04 14:08:25  info finished task             duration=2.852790748s task=action=dns&do=add&domain=some-hosting-here.nl&name=_acme-challenge&named_reload=yes&ttl=120&type=TXT&value=%22EYJvDjgwzw0sJ48wpCY1mSVs4ZnHZns7qYkDyMlwTXw%22
2026-08-04T14:08:25.449561299+02:00 INFO  dns01: trying to solve the challenge. domain=*.some-hosting-here.nl
2026-08-04T14:08:25.451230280+02:00 INFO  dns01: waiting for record propagation timeout=5m0s interval=30s domain=*.some-hosting-here.nl
2026-08-04T14:08:55.492523428+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:09:25.535715454+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:09:55.567085684+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:10:25.584110022+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:10:55.629399278+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:11:25.661063644+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:11:55.695945681+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:12:25.730335945+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:12:55.772213378+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:13:25.788622877+02:00 INFO  dns01: waiting for record propagation. domain=*.some-hosting-here.nl
2026-08-04T14:13:55.814759907+02:00 INFO  dns01: cleaning DNS-01 challenge. domain=*.some-hosting-here.nl
2026-08-04T14:13:57.590725943+02:00 INFO  2026/08/04 14:13:57  info executing task            task=action=dns&do=delete&domain=some-hosting-here.nl&name=_acme-challenge&named_reload=yes&type=TXT&value=%22EYJvDjgwzw0sJ48wpCY1mSVs4ZnHZns7qYkDyMlwTXw%22
2026-08-04T14:13:59.809815720+02:00 INFO  2026/08/04 14:13:59  info finished task             duration=2.219632235s task=action=dns&do=delete&domain=some-hosting-here.nl&name=_acme-challenge&named_reload=yes&type=TXT&value=%22EYJvDjgwzw0sJ48wpCY1mSVs4ZnHZns7qYkDyMlwTXw%22
2026-08-04T14:14:00.218425179+02:00 INFO  Skipping deactivating of valid authorization. url=https://acme-v02.api.letsencrypt.org/acme/authz/815647577/749576892911
2026-08-04T14:14:00.347368192+02:00 INFO  Deactivating authorization. url=https://acme-v02.api.letsencrypt.org/acme/authz/815647577/752723352141
2026-08-04T14:14:00.504742136+02:00 ERROR Error error="obtain certificate: resolver: one or more domains had a problem: [*.some-hosting-here.nl: dns01: time limit exceeded: last error: authoritative nameservers: DNS call error: dial udp: lookup ns2.knothhosting39.nl. on 127.0.0.253:53: no such host [ns=ns2.knothhosting39.nl.:53, question='_acme-challenge.some-hosting-here.nl. IN  TXT']]"
---

another domain failed with stealth nameservers with the error "server misbehaving":

Code:
Failed to issue a TLS certificate for xb*******er.nl, *.xb*******er.nl DNS names.
--- Command output
2026-08-04T13:51:14.559153720+02:00 INFO  Obtaining SAN certificate. domains="xb*******er.nl, *.xb*******er.nl"
2026-08-04T13:51:15.293548023+02:00 INFO  Authorization is already valid; skipping the challenge. domain=xb*******er.nl
2026-08-04T13:51:15.293574825+02:00 INFO  Use solver. domain=*.xb*******er.nl type=dns-01
2026-08-04T13:51:15.293588594+02:00 INFO  dns01: preparing to solve the challenge. domain=*.xb*******er.nl
2026-08-04T13:51:17.410227275+02:00 INFO  2026/08/04 13:51:17  info executing task            task=action=dns&do=add&domain=xb*******er.nl&name=_acme-challenge&ttl=120&type=TXT&value=%22persistent-record%22
2026-08-04T13:51:17.984317151+02:00 INFO  2026/08/04 13:51:17  info finished task             duration=574.189447ms task=action=dns&do=add&domain=xb*******er.nl&name=_acme-challenge&ttl=120&type=TXT&value=%22persistent-record%22
2026-08-04T13:51:18.637222345+02:00 INFO  2026/08/04 13:51:18  info executing task            task=action=dns&do=add&domain=xb*******er.nl&name=_acme-challenge&named_reload=yes&ttl=120&type=TXT&value=%22VnXb_TLkPD_0F0UIWu0XsuNbexfWagfNrXWsmuq5shw%22
2026-08-04T13:51:19.891304738+02:00 INFO  2026/08/04 13:51:19  info finished task             duration=1.251878673s task=action=dns&do=add&domain=xb*******er.nl&name=_acme-challenge&named_reload=yes&ttl=120&type=TXT&value=%22VnXb_TLkPD_0F0UIWu0XsuNbexfWagfNrXWsmuq5shw%22
2026-08-04T13:51:19.915411084+02:00 INFO  dns01: trying to solve the challenge. domain=*.xb*******er.nl
2026-08-04T13:51:19.916063093+02:00 INFO  dns01: waiting for record propagation timeout=5m0s interval=30s domain=*.xb*******er.nl
2026-08-04T13:51:50.235786171+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:52:20.429373473+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:52:50.633755285+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:53:20.994157162+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:53:51.326496917+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:54:21.554639586+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:54:51.811439149+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:55:22.081537465+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:55:52.212475326+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:56:22.488250205+02:00 INFO  dns01: waiting for record propagation. domain=*.xb*******er.nl
2026-08-04T13:56:52.518676468+02:00 INFO  dns01: cleaning DNS-01 challenge. domain=*.xb*******er.nl
2026-08-04T13:56:54.126282552+02:00 INFO  2026/08/04 13:56:54  info executing task            task=action=dns&do=delete&domain=xb*******er.nl&name=_acme-challenge&named_reload=yes&type=TXT&value=%22VnXb_TLkPD_0F0UIWu0XsuNbexfWagfNrXWsmuq5shw%22
2026-08-04T13:56:56.199307022+02:00 INFO  2026/08/04 13:56:56  info finished task             duration=2.072896434s task=action=dns&do=delete&domain=xb*******er.nl&name=_acme-challenge&named_reload=yes&type=TXT&value=%22VnXb_TLkPD_0F0UIWu0XsuNbexfWagfNrXWsmuq5shw%22
2026-08-04T13:56:56.649055964+02:00 INFO  Skipping deactivating of valid authorization. url=https://acme-v02.api.letsencrypt.org/acme/authz/815647577/742911946965
2026-08-04T13:56:56.801267327+02:00 INFO  Deactivating authorization. url=https://acme-v02.api.letsencrypt.org/acme/authz/815647577/752715420361
2026-08-04T13:56:56.984392441+02:00 ERROR Error error="obtain certificate: resolver: one or more domains had a problem: [*.xb*******er.nl: dns01: time limit exceeded: last error: authoritative nameservers: DNS call error: dial udp: lookup ns2.none-existing.nl. on 127.0.0.253:53: server misbehaving [ns=ns2.none-existing.nl.:53, question='_acme-challenge.xb*******er.nl. IN  TXT']]"
---
 
Back
Top