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.
 
@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.
 
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.
 
@Zhenmue, thanks for sharing the details about the problems you have encountered. Hope I can help to shed some light on the cert system.


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.



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



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).



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.

Thanks @fln. We re-checked everything against your explanation. Point by point.

---

**1. Certificate adoption**

*Understood:* the new system adopts foreign certificates and renews them at `letsencrypt_renew_before_expiry_days`. `admin_ssl_replace_all_expired_invalid` and `admin_ssl_check_expiry_offset` are old-system only.

*Corrected:* I withdraw the catch-22. Our affected domains had **no `acme_enabled` key at all** in `domain.conf` , absent, not `no`. They were on the old system, with `ssl=ON` and a certificate DA never issued, which the old system will never renew. Real problem, wrong mechanism.

*Data,* one server, `ssl=ON` domains holding a certificate file:

| | |
|---|---|
| old system, cert originally issued by DA | 439 (renew fine) |
| old system, cert DA never issued | 28 (never renew) |
| new system | rest, almost all because we migrated them this week |

*Fix that worked:* `letsencrypt.sh request <domain>`, once per domain, flips it to the new system. 262 domains: 141 got a certificate immediately (all already expired), 121 kept a valid certificate and are now `acme_enabled=yes`.

*Questions:*
1. Is per-domain `letsencrypt.sh request` the supported way to bulk-migrate old→new?
2. Can DA migrate `ssl=ON` domains automatically on upgrade? Nothing does today, so cPanel migrations, restores and older accounts land on the old system and stay there.
3. Can the system a domain uses be exposed in the UI or API? Today `acme_enabled` is only readable by walking `domain.conf` on disk, so "which of my domains are unmanaged" has no supported answer.

---

**2. Local resolver**

*Understood:* DA uses the system resolver; authoritative bind must not be it.

*Not our case:* we already run what you recommend.

```
# ss -lnup | grep 127.0.0.1:53
UNCONN 127.0.0.1:53 users:(("unbound",pid=...))
# named.conf
listen-on port 53 { !127.0.0.1; any; };
```

unbound owns the loopback, named is excluded from it, and the pre-check still failed.

*The actual case:* a **newly created subdomain**. `newsub.example.cl` had been queried before it existed, unbound cached the negative answer, then the record appeared in a zone this same server is authoritative for. `www.newsub` had never been queried, resolved fine, so DA issued a certificate covering `www.newsub` only. `unbound-control flush_zone` fixed it instantly.

*Note:* your debug output in the other thread shows DA already does `flushing unbound dns zone` in the certificate task. The 1.707 `persistent-record` buster does not cover this , that is a TXT for `_acme-challenge`, ours was a plain A lookup in the HTTP-01 pre-check.

*Questions:*
4. Could that flush also run on subdomain creation, or before the HTTP pre-check rather than only in the DNS-challenge path?
5. Could the error text separate "we could not resolve this locally" from "your DNS records are missing or point elsewhere"? Here the record existed, resolved worldwide, and the challenge returned HTTP 200 from an external host. The current wording sends operators to debug the customer's DNS, which was correct all along.

---

**3. Name list ignored**

*Understood and accepted:* by design, DA covers every name that passes its checks.

*One consequence:* there seems to be no way to get a bare name and its `www` into one certificate. After the case above we have a certificate for `newsub.example.cl` only, and `www.newsub.example.cl` returns a hostname mismatch. Re-requesting both logs `dns-names=[newsub.example.cl]`; deleting the certificate and re-requesting gives the same single-name result. On this account the `www.<sub>` names of older subdomains live in the parent domain certificate.

*Question:*
6. Is a newly created subdomain expected to stay half-covered until the parent certificate renews, or should both names be picked up sooner?

---

**4. Partial validation discarded**

*Understood:* fixed in 1.707. Thanks , that was the one costing us a customer with mail-only hosting. We are on 1.706 and will upgrade the fleet tomorrow to 1.707 .
 
Back
Top