Maybe an intermediate certificate is missing?

My domain is:
mail.algasol.com

I ran this command:
From gmail attempting to connect with both port 995 and port 993 fails.
openssl s_client -showcerts -connect mail.algsol.com:993 -servername mail.algasol.com

It produced this output:
For gmail:Server returned error: "SSL error: No path found from the leaf certificate to any root. Maybe an intermediate certificate is missing?"

For openssl:
139939043341888:error:2008F002:BIO routines:BIO_lookup_ex:system lib:crypto/bio/b_addr.c:730:Name or service not known

My web server is (include version):
algasol.com

The operating system my web server runs on is (include version):
$ cat /etc/debian_version
bullseye/sid

My hosting provider, if applicable, is:
linode

I can login to a root shell on my machine (yes or no, or I don't know):
yes

I'm using a control panel to manage my site (no, or provide the name and version of the control panel):
virtualmin

The version of my client is (e.g. output of certbot --version or certbot-auto --version if you're using Certbot):
2021-09-02 15:43:30,913:DEBUG:certbot._internal.main:certbot version: 1.13.0

cat certbot_command_docker.sh
#!/bin/sh -x
# Resorting to the docker image for certbot/dns-linode since version alignment between various packages is such a nightmare that things keep breaking.
docker run -it --rm --name certbot \
            -v "/root/.linode_api:/root/.linode_api" \
            -v "/etc/letsencrypt:/etc/letsencrypt" \
            -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
            -v "/var/log:/var/log" \
            -v "/etc/letsencrypt/renewal-hooks/deploy" \
            certbot/dns-linode renew
# Substitute the following line for the above to reinitialize the renewal variables
#            certbot/dns-linode certonly -a dns-linode --dns-linode-credentials /root/.linode_api/certbot_token -d *.algasol.com -d albusaurum.com -d *.albusaurum.com -d *.aquatuta.com -d *.algasolrenewables.com -d algasol.com -d aquatuta.com -d algasolrenewables.com

# The following lines are necessary because the docker container doesn't
# know where all the directories are that must be accessed to run the
# deploy hooks.  So the "copytodomains" script does this.
export RENEWED_LINEAGE=/etc/letsencrypt/live/algasol.com
/etc/letsencrypt/copytodomains algasol.com albusaurum.com algasolrenewables.com aquatuta.com
1 Like

Not missing, more like very old and not in use any longer, expired to be exact:

Certificate chain
 0 s:CN = *.algasol.com
   i:C = US, O = Let's Encrypt, CN = R3
 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
   i:O = Digital Signature Trust Co., CN = DST Root CA X3

How did you install the certificates? I.e., what's the mailservers configuration regarding TLS?

By the way, the above is for your Dovecot IMAP service. Your SMTP server isn't sending the intermediate at all.

2 Likes

Are you referring to the installation of intermediate certificates? I don't recall how the intermediate certificates were installed, unless you are referring to the copying of letsencrypt's "fullchain" file to the respective domains home directories. If the latter, then it was accomplished by the virtualmin script script used in "copytodomains" referred to above. That script is used in the deploy stage of renewal:

#!/bin/bash -x
RENEWED_DOMAINS="$@"
set -e

for domain in $RENEWED_DOMAINS; do
        if [[ ! $domain =~ ^\* ]]; then virtualmin install-cert --domain $domain --cert "$RENEWED_LINEAGE/cert.pem" --key "$RENEWED_LINEAGE/privkey.pem";  fi;

done

Regarding TLS for dovecot:

/etc/dovecot# grep -Ri tls
conf.d/10-ssl.conf:ssl_min_protocol = TLSv1.2
conf.d/10-ssl.conf:ssl_cipher_list = ECDHE-RSA-AES256-SHA384:AES256-SHA256:AES256-SHA256:RC4:HIGH:MEDIUM:+TLSv1:+TLSv1.1:+TLSv1.2:!MD5:!ADH:!aNULL:!eNULL:!NULL:!DH:!ADH:!EDH:!AESGCM
dovecot-new-2.3.conf:ssl_cipher_list = ECDHE-RSA-AES256-SHA384:AES256-SHA256:AES256-SHA256:RC4:HIGH:MEDIUM:+TLSv1:+TLSv1.1:+TLSv1.2:!MD5:!ADH:!aNULL:!eNULL:!NULL:!DH:!ADH:!EDH:!AESGCM
dovecot.conf:ssl_cipher_list = ECDHE-RSA-AES256-SHA384:AES256-SHA256:AES256-SHA256:RC4:HIGH:MEDIUM:+TLSv1:+TLSv1.1:+TLSv1.2:!MD5:!ADH:!aNULL:!eNULL:!NULL:!DH:!ADH:!EDH:!AESGCM
dovecot.conf:ssl_min_protocol = TLSv1.2
dovecot-new-2.3.1.conf:ssl_cipher_list = ECDHE-RSA-AES256-SHA384:AES256-SHA256:AES256-SHA256:RC4:HIGH:MEDIUM:+TLSv1:+TLSv1.1:+TLSv1.2:!MD5:!ADH:!aNULL:!eNULL:!NULL:!DH:!ADH:!EDH:!AESGCM
dovecot-new-2.3.1.conf:ssl_min_protocol = TLSv1.2
1 Like

It doesn't look like that command actually uses the fullchain.pem or chain.pem files, just the certificate in cert.pem.

The configuration directive you want to check is ssl_cert. (TLS is the modern name of the older protocol once called SSL.. But many applications still use the old ssl name unfortunately.)

3 Likes

The virtualmin install-cert command apparently copies the fullchain*.pem to ssl.combined under the respective domain home directories:

# diff /home/algasol/ssl.combined /etc/letsencrypt/archive/algasol.com/fullchain11.pem
34d33
<

Then in /etc/dovecot/dovecot.conf we find:

ssl_cert = </etc/dovecot/dovecot.pem
ssl_cipher_list = ECDHE-RSA-AES256-SHA384:AES256-SHA256:AES256-SHA256:RC4:HIGH:MEDIUM:+TLSv1:+TLSv1.1:+TLSv1.2:!MD5:!ADH:!aNULL:!eNULL:!NULL:!DH:!ADH:!EDH:!AESGCM
ssl_dh =< /etc/dovecot/dh.pem
# -----BEGIN DH PARAMETERS-----
#MIGHAoGBAOjmlowcgKAswlMmqQdDt1oIl0/BsFbvUG5fok8b42RiJa5CwA1PEIkC
#YIAtwCb5UG4gx1rZUJuNXffzQQFPx6T9hRfmfateGDg+lZmTzmHCEmLkH7SHLTju
#PLc4SyND+HhZmBhtwWSxzOYVXg7Vh+l9K2NLFyYsB7pOkk+MTD6rAgECAAAAAAAA
#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
#-----END DH PARAMETERS-----
ssl_key = </etc/dovecot/private/dovecot.pem
ssl_min_protocol = TLSv1.2
userdb {
  driver = passwd
}
local_name algasol.com {
#  ssl_ca = </etc/letsencrypt/live/algasol.com/chain.pem
#  ssl_cert = </home/algasol/ssl.cert
  ssl_cert = </home/algasol/ssl.combined
  ssl_key = </home/algasol/ssl.key
}

Then tracking down the ssl_cert configuration /etc/dovecot/dovecot.pem we have:

root@li1186-128:/etc/dovecot# ls -alt /etc/dovecot/dovecot.pem
lrwxrwxrwx 1 root root 47 Mar 16  2020 /etc/dovecot/dovecot.pem -> /etc/letsencrypt/live/algasol.com/fullchain.pem
root@li1186-128:/etc/dovecot# ls -alt /etc/letsencrypt/live/algasol.com/fullchain.pem
lrwxrwxrwx 1 root root 41 Sep  2 16:28 /etc/letsencrypt/live/algasol.com/fullchain.pem -> ../../archive/algasol.com/fullchain11.pem
root@li1186-128:/etc/dovecot# ls -alt /etc/letsencrypt/live/algasol.com/../../archive/algasol.com/fullchain11.pem
-rwxr-x--- 1 root root 3657 Oct  4 15:46 /etc/letsencrypt/live/algasol.com/../../archive/algasol.com/fullchain11.pem

Which, as previously shown, is identical to the ssl.combined file except for a blank line between certs.

1 Like

Could you please upload /etc/letsencrypt/live/algasol.com/fullchain.pem?

2 Likes
# cat /etc/letsencrypt/live/algasol.com/fullchain.pem
-----BEGIN CERTIFICATE-----
MIIFnzCCBIegAwIBAgISBAK7hkbDMgFP+UUZQX2JarmqMA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMTA5MDIxNTI4NDBaFw0yMTEyMDExNTI4MzlaMBgxFjAUBgNVBAMM
DSouYWxnYXNvbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH
rA4EZPufqwCSEBGADTxogQWMysYR0hDRAgR+gQzyWqnuCZn5hcMawGr2mewrnaL+
PHvuRzMiMBXQArQ2GazPOQuN8fl4mJLbfifNLU4Roq6uKWMCoplo1sAOvNz8ytea
mfxZeiQ6OtQUkx3RY/4KpqFwNjxdXaUXdU6I42CkEdFFgqed85JruX31gVSYBbsF
L2k+0OWgwFSN7WyCH9LyLqK9NKbN1EnIP2+IH6QykwmorMDB3Q8tCHilCT4EQUin
GnZ9lxCrUjTZ/xG3NPWf1stqOeIyA7uoTPg11JZ+uKTPywVhpvzNd4FUvOvYlS82
oGR4KbGO0pBEZABCgJjDAgMBAAGjggLHMIICwzAOBgNVHQ8BAf8EBAMCBaAwHQYD
VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0O
BBYEFMGhL0W+suNFKi3Th+fAXOkrmIw0MB8GA1UdIwQYMBaAFBQusxe3WFbLrlAJ
QOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggrBgEFBQcwAYYVaHR0cDovL3Iz
Lm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRwOi8vcjMuaS5sZW5jci5vcmcv
MIGXBgNVHREEgY8wgYyCECouYWxidXNhdXJ1bS5jb22CDSouYWxnYXNvbC5jb22C
FyouYWxnYXNvbHJlbmV3YWJsZXMuY29tgg4qLmFxdWF0dXRhLmNvbYIOYWxidXNh
dXJ1bS5jb22CC2FsZ2Fzb2wuY29tghVhbGdhc29scmVuZXdhYmxlcy5jb22CDGFx
dWF0dXRhLmNvbTBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAo
MCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQMGCisG
AQQB1nkCBAIEgfQEgfEA7wB1AJQgvB6O1Y1siHMfgosiLA3R2k1ebE+UPWHbTi9Y
TaLCAAABe6dXSeoAAAQDAEYwRAIgW9MDOo7MUueMYahPbBO13nJKuRDV+CQH4Rdi
CYW2ivECIB3ki1AeZqoI7QjfEPf9TrP3ezxMHWGj1rWXb93IVHi6AHYAfT7y+I//
iFVoJMLAyp5SiXkrxQ54CX8uapdomX4i8NcAAAF7p1dKDwAABAMARzBFAiEA9+JL
dh+6EAqv09XsgjakF58VR/rGtovIVfQ1sr5PcGACIBGWScEvpAjfOHTdlWEvQaDH
w77pSWpjmWJtukqj5km2MA0GCSqGSIb3DQEBCwUAA4IBAQB4fIXWPPwpII8k7JPE
aB3qYyTG1yhUgwWzh5JFmboNZFCc8c3YDH5U5/iwVJP7zxvov2rHLmMy+gCcdQzv
135aLWBcKNg6McFLfjUvm3fx7xY8VznXjnzlvhCugQgacyhC9NBRPEVUrXXIEwOp
+mDv78FP+bHzAxJ0IegZ7UdTQ7HHmfjjIyDGPzL9OkwFu0rOGa+jjzBXdGOJ//AS
3yt4We9G0fA1f5zIsCT1P9ZpVsOZ4POwy5h1AwIeoibEwwYgfRPHVFd5SXP/b/2g
5DKkN/q/HrFMQgiIug/IHt5LLa4scx5ceXnE3GxlF/+CGi8M9dKN3hWNiOerP2xg
Fy0S
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----
1 Like

Hello :slightly_smiling_face:

The certificates you've posted are:

The certificates you need are:

2 Likes

It's really weird that you have a leaf certificate signed by R3 (as you should) then the Let's Encrypt Authority X3 intermediate certificate (as you shouldn't). I surmise that your virtualmin needs its intermediate database updated.

I'm wondering if it might be an out-of-date certbot/certbot docker image:

# docker images
REPOSITORY           TAG       IMAGE ID       CREATED         SIZE
certbot/dns-linode   latest    56cb3c466315   7 months ago    117MB
certbot/certbot      latest    67cfe9e9c63f   7 months ago    95.5MB
hello-world          latest    bf756fb1ae65   21 months ago   13.3kB
1 Like

The full chain is provided by Boulder (Let's Encrypt's CA software) to certbot (or whatever ACME client is being used) each time a certificate is generated. The ACME client doesn't/shouldn't keep a database of intermediate certificates. Since you have an R3-signed certificate, your ACME client must have been sent the current chain, which would include R3 and not include Let's Encrypt Authority X3. What you've currently presented is like buying a Honda vehicle then popping the hood to find a Toyota engine. We see this problem commonly with control panel and other site management software that does keep a database of intermediate certificates (that are often not updated). That does not appear to be the case here though. The problem may potentially be due to some custom script work as @swelljoe mentions below.

1 Like

I just want to note that I don't think this script is generated by Virtualmin? I can't find any mention of it in our repos, and I don't think this is how renewal happens.

We don't ship an intermediate database. Up to Webmin 1.870 we did have a copy of the LE intermediate cert included (I think due to the minimal ACME_tiny client we used by default, I don't remember details), but that hasn't been the case for some time. I'm not sure how this system is getting the old one...we grab a new one on every renewal, as far as I know, and all modern systems should be using certbot for the cert and chain request, by default.

I want to be clear, I do not understand this issue (the cross-chain signing issue, which is still plaguing our users and lots of others), but I do know we stopped shipping the old intermediate chain in the distant past. It should not be an issue on up-to-date Virtualmin systems.

But, even with certificates generated after the expiration of that DST Root CA X3 cert, I still see it show up as a certification path (even though there is a valid certification path for newer clients), and I don't understand why. This exact same thing happens for certificates generated directly with certbot, without Virtualmin involved, so it is unrelated to Virtualmin (though OP does seem to have something wrong if they're getting the old intermediates, but it's not the case in my Virtualmin deployments, so something is unusual with OPs Virtualmin system or the way certs are being generated/used).

e.g. this is a cert issued after the expiration:

I can reproduce this same broken certification path on a certbot-generated certificate, as well, again with no Virtualmin or Webmin involved. In this case, Virtualmin isn't doing anything unique to cause this problem, and I don't know how to solve it, if certbot also generates a certificate that can fail for some clients.

I tested on an Ubuntu 16.04 system, where I can reliably reproduce the issue, and found that if I simply removed the DST_Root_CA_X3 certificate from the system CA bundle, a valid certification path could be found without it...but if it exists, requests fail.

2 Likes

That's not a broken chain, that's all correct and intended.

Let's Encrypt is intentionally serving a chain up to the now expired DST Root CA X3, because that helps with Android compatibility. All clients that are not Android shall use the path leading up to ISRG Root X1 for validation, ignoring the expired DST Root CA X3.

We're aware that there are some libraries (e.g older OpenSSL) that can't do this*, which is why Let's Encrypt offers an alternate chain which does not include the certificate leading up to DST Root CA X3 (instead terminating at ISRG Root X1). This alternate chain can be requested by the ACME client, if Android compatibility is not desired.

*Some libraries, e.g OpenSSL 1.0.2 have a workaround where simply removing DST Root CA X3 from the trust store makes them compatible with the default chain. This is also why some vendors (Ubuntu) have recently started shipping patches which remove DST Root CA X3.

6 Likes

OK, that answers my question/confusion. I assumed I was seeing a representative example of the problem when I was testing on Ubuntu 16.04, but it seems to be somewhat different problem with the same symptoms.

This also confirms that Virtualmin with Webmin in any version after 1.870 is doing the right thing WRT the chain (it's using whatever certbot gives it). So, I don't know why OP has the old intermediate chain...seems to be something in custom scripts.

2 Likes

Thanks for the confirmation of that @swelljoe. This information not only helps whittle down the issue here, but can be recycled in other cases in the future.

:sparkling_heart:

2 Likes

I just want to note that I don't think this script is generated by Virtualmin? I can't find any mention of it in our repos, and I don't think this is how renewal happens

I was unclear in my wording. The script is my own and it uses the virtualmin-supplied script virtualmin install-cert.

The reason for this is that I had a requirement for wild card domain names a while ago, which virtualmin's system didn't support. So I had to generate my own certificates. The script was a letsencrypt deploy hook script.

2 Likes

Where do I put the two files so that certbot will grab them:

Trying to figure out where certbot might be grabbing this stuff, I ran bash commands like:
cp /etc/letsencrypt/live/algasol.com/fullchain.pem .
split the two certs into fc1.pem and fc2.pem

locate Authority |egrep '\.(pem|crt)' >cafiles.log
locate CA |egrep '\.(pem|crt)' >>cafiles.log

wrote a perl script

cat difflength.pl
while(<>){
        chomp $_;
        $df = `diff fullchain.pem $_`;
        $len = length($df);
        print $len,' ',$_,"\n";
}
perl difflength.pl <cafiles.log  >lensfc.log

did the same for fc1.pem and fc2.pem
for each file I took the 0 length diff full paths and put them into a files named {fc*}paths.log
then I wrote another perl script:

 cat chompfilename.pl
while(<>){
        s/[^\/]*$//;
        print;
        print "\n";
}

and finally
ls *paths* |xargs cat|perl chompfilename.pl |uniq
producing:

0 /snap/core20/1081/etc/ssl/certs/
0 /snap/core20/1026/etc/ssl/certs/
0 /snap/core18/2128/etc/ssl/certs/
0 /snap/core18/2074/etc/ssl/certs/
0 /snap/core/11743/etc/ssl/certs/
0 /snap/core/11606/etc/ssl/certs/
0 /snap/core20/1081/etc/ssl/certs/
0 /snap/core20/1026/etc/ssl/certs/
0 /snap/core18/2128/etc/ssl/certs/
0 /snap/core18/2074/etc/ssl/certs/
0 /snap/core/11743/etc/ssl/certs/
0 /snap/core/11606/etc/ssl/certs/
0 /snap/core20/1081/etc/ssl/certs/
0 /snap/core20/1026/etc/ssl/certs/
0 /snap/core18/2128/etc/ssl/certs/
0 /snap/core18/2074/etc/ssl/certs/
0 /snap/core/11743/etc/ssl/certs/
0 /snap/core/11606/etc/ssl/certs/

So I'm not sure what all these directories are but, unless as I suspected in my concern about the docker image for certbot I'm using, one of these directories is where I should copy the certificate authority files.

I also, after updating the docker certbot, forced renew and although there are new certs in the right places, even after a restart of the services I'm still getting the intermediate chain error.

1 Like

Your leaf certificate and two intermediate certificates (R3 and ISRG Root X1) should already be in fullchain.pem produced by certbot. If you're only seeing your leaf certificate and the R3 intermediate certificate in fullchain.pem then you have certbot configured for the alternate/short chain instead of the default/long chain.

2 Likes

The phrase "certbot configured" would direct me to this documentation on certbot which has information on the configuration file (and command line options) but the word "authority" occurs only once and not in reference to a configurable parameter.

The only other sense in which the word "configured" may be applicable that I can think of is in terms of version alignments between packages included in the certbot environment and that brings me back to my question about the Docker image for certbot. I ended up going to the Docker image for certbot precisely to avoid version alignment problems. Indeed, the reason Docker is in such widespread use is that people want to avoid version alignment problems.

Should I start digging into the build spec for the Docker build for certbot?

1 Like

The certbot parameter of concern here is --preferred-chain.

1 Like