Open rizaemet opened 2 years ago
Please provode the log with --debug 2
if this is a bug report.
For now, I've done my job like this and problem solved:
I disabled this IF check in .acme.sh/dnsapi/dns_acmedns.sh
#### if [ -z "$ACMEDNS_USERNAME" ] || [ -z "$ACMEDNS_PASSWORD" ]; then
response="$(_post "" "$ACMEDNS_REGISTER_URL" "" "POST")"
_debug response "$response"
ACMEDNS_USERNAME=$(echo "$response" | sed -n 's/^{.*\"username\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_debug "received username: $ACMEDNS_USERNAME"
ACMEDNS_PASSWORD=$(echo "$response" | sed -n 's/^{.*\"password\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_debug "received password: $ACMEDNS_PASSWORD"
ACMEDNS_SUBDOMAIN=$(echo "$response" | sed -n 's/^{.*\"subdomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_debug "received subdomain: $ACMEDNS_SUBDOMAIN"
ACMEDNS_FULLDOMAIN=$(echo "$response" | sed -n 's/^{.*\"fulldomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_info "##########################################################"
_info "# Create $fulldomain CNAME $ACMEDNS_FULLDOMAIN DNS entry #"
_info "##########################################################"
_info "Press enter to continue... "
read -r _
#### fi
The problem with that solution is that you'll need to update your _acme-challenge
CNAME record every time you renew (!) and that it'll create a new user account every single time you renew for every subdomain. In your case, after 4 renewals, you'll end up with 12 accounts on the acme-dns server, 9 of them unused.
The cause of this problem is as follows:
-d example.com -d www.example.com
, two is enough.-d example.com -d *.example.com
, two is enough.-d example.com -d foo.example.com -d bar.example.com
is one too many. One is silently discarded.As credentials are saved per certificate, using multiple config-home directories won't help.
This problem has come up before, but so far I don't think anyone has tackled this issue. It's not specific to subdomains: -d example.com -d example.org -d example.net
would cause this, too.
Solutions to this might be:
dns_acmedns.sh
file also assumes a limit of 2 records: dns_acmedns_rm()
is blank as there's no real reason to clean up after itself.The last option will require some development work and some time testing. I've attached a quick extension to dns_acmedns.sh
but it doesn't include automatic registration or saving credentials. You'll need to do both manually.
The following is by no means battle-tested, but it should work fine and is inspired by this ISPMan integration by @garycnew. It might serve as a jumping-off point for someone to properly edit the original implementation. I personally don't have the time, but I encourage you—or anyone else—to take a shot at it.
curl -X POST https://auth.acme-dns.io/register
three times (or replace auth.acme-dns.io
with whatever acme-dns server you want to use)..acme.sh/1.cbu.edu.tr/1.cbu.edu.tr.conf
(replace 1.cbu.edu.tr
with your domain if it differs).some-example.org
) and replace -
and .
like so: some_HYPHEN_example_DOT_org
.ACMEDNS_USERNAME=...
use ACMEDNS_USERNAME_1_DOT_cbu_DOT_edu_DOT_tr=...
(or whatever came out of step 3).ACMEDNS_PASSWORD=
and ACMEDNS_SUBDOMAIN=
, too..acme.sh/dns_acmednsmulti.sh
as below.acme.sh --issue --dns dns_acmednsmulti -d ...
uses the three accounts you defined.#!/usr/bin/env sh
dns_acmednsmulti_add() {
domain="${1#_acme-challenge.}"
# Change foo-bar.example.org to foo_HYPHEN_bar_DOT_example_DOT_org
key="$(echo "$domain" | sed "s/\-/_HYPHEN_/g" | sed "s/\./_DOT_/g")"
# Load values.
ACMEDNS_BASE_URL="${ACMEDNS_BASE_URL:-$(_readdomainconf "ACMEDNS_BASE_URL_$key")}"
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readdomainconf "ACMEDNS_USERNAME_$key")}"
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readdomainconf "ACMEDNS_PASSWORD_$key")}"
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readdomainconf "ACMEDNS_SUBDOMAIN_$key")}"
if [ -z "$(_readdomainconf "ACMEDNS_USERNAME_$key")" ]; then
_info "To save domain-specific credentials for '$domain':"
_info "Add 'ACMEDNS_USERNAME_$key' (etc) to the domain configuration file."
else
_info "Using domain-specific credentials for '$domain'".
fi
# like issue(), find the dnsapi file for dns_acmedns and then source it with "."
# This will load dns_acmedns_add().
d_api="$(_findHook "$_dns_root_d" "$_SUB_FOLDER_DNSAPI" "dns_acmedns")"
. "$d_api"
dns_acmedns_add "$1" "$2"
}
dns_acmednsmulti_rm() {
# like issue(), find the dnsapi file for dns_acmedns and then source it with "."
# This will load dns_acmedns_rm().
d_api="$(_findHook "$_dns_root_d" "$_SUB_FOLDER_DNSAPI" "dns_acmedns")"
. "$d_api"
dns_acmedns_rm "$1" "$2"
}
It's mostly a copy-paste of what already exists (the fallback code to _readaccountconf_mutable
) + adding a value in the variable names like in the linked example.
Thank you for this complete answer. I will be inform you as soon as possible.
I did as you explain and I got the certifate without problem. Thank you very much.
The process still has manual steps and I think an acme-dns api (eg acmednsmulti as you named it) is required for multiple domains. So I'll leave this issue open for now. If you don't have such thoughts, I will fork the project and try to do it myself.
I just made it a separate file so that the changes wouldn't be overwritten by an upgrade of acme.sh. I'm sure people would appreciate an enhanced version of dns_acmedns.sh
. :-)
The example listed above is already backwards compatible(*) with existing credentials so it should totally be doable.
() this version will overwrite `ACMEDNS_variables with the last used domain-specific values when it runs, if any exist. That's no problem if either _none_ or _all_ domains in the certificate use
ACMEDNS*
I think that @Spekpannenkoek analysis is correct, but at the top of that the current dns_acmedns.sh
script destroys the account information on the first run and, especially if you run self-hosted acme-dns
server, all subsequent runs are creating and using newly created accounts on every run.
One of the indications of such a problem is the line:
[Thu 04 Aug 2022 10:35:29 AM +03] Press enter to continue...
in the debug output.
It comes down to the code in the script:
dns_acmedns_add() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug "fulldomain $fulldomain"
_debug "txtvalue $txtvalue"
#for compatiblity from account conf
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
_clearaccountconf_mutable ACMEDNS_USERNAME
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
_clearaccountconf_mutable ACMEDNS_PASSWORD
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
_clearaccountconf_mutable ACMEDNS_SUBDOMAIN
ACMEDNS_BASE_URL="${ACMEDNS_BASE_URL:-$(_readdomainconf ACMEDNS_BASE_URL)}"
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readdomainconf ACMEDNS_USERNAME)}"
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readdomainconf ACMEDNS_PASSWORD)}"
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readdomainconf ACMEDNS_SUBDOMAIN)}"
if [ "$ACMEDNS_BASE_URL" = "" ]; then
ACMEDNS_BASE_URL="https://auth.acme-dns.io"
fi
So what happens here is the removal of the acme-dns
account info from the $ACME_HOME/account.conf
file and transition of it to the domain config file $CERT_HOME/domain/domain.conf
for the first domain you happen to add/renew after the upgrade. All subsequent runs won't have that info and will start to create new accounts on the default https://auth.acme-dns.io server.
The cure is also given in the top comments of the script:
# Usage:
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
#
# You can optionally define an already existing account:
#
# export ACMEDNS_USERNAME="<username>"
# export ACMEDNS_PASSWORD="<password>"
# export ACMEDNS_SUBDOMAIN="<subdomain>"
Also, for existing domains you can add those lines to the $domain.conf
file:
...
Le_API='https://acme-v02.api.letsencrypt.org/directory'
Le_Keylength='2048'
Le_DNSSleep='15'
Le_CertCreateTime='1659950296'
Le_CertCreateTimeStr='Mon Aug 8 09:18:17 UTC 2022'
Le_NextRenewTimeStr='Fri Oct 7 09:18:16 UTC 2022'
Le_NextRenewTime='1665047896'
ACMEDNS_BASE_URL="https://auth.acme-dns.io"
ACMEDNS_USERNAME="<username>"
ACMEDNS_PASSWORD="<password>"
ACMEDNS_SUBDOMAIN="<subdomain>"
@Spekpannenkoek It's nice to see that someone actually reads my code; even, if it is from a merge request that's stuck in Lalaland (which I assumed was not world readable).
I want to provide an update confirming that the multi-domain code is working without issue; since, originally submitting it as a merge request. The code is a byproduct of needing a workaround for a feature in acme.sh; before, its time. It's nice to see that the code might be helpful toward a more permanent solution.
Now, I'm faced with a new Issue #4683 that appears to be the result of ZeroSSL changing their External Account Binding parameters; causing, my Wildcard, SAN Certs to fail renewal. Any assistance in troubleshooting/resolving this separate issue is much appreciated.
Hi everybody, just started using acme.sh with acme-dns. I will also have a look for a good and complete solution and will create a pull request. Additionally I want support for custom register and update URL pathes. I will get back to this issue soon.
P.S. The code of dns_acmedns.sh
differs between acmesh-official
and dampfklon
Ok, here are my two cents for a solution.
There are 2 parts to consider for creating a solution for DNS API auth services set up with or similar to acme-dns:
Instead of using lots of variables to pass multiple accounts for multiple domains on a single dns provider, I would suggest to extend acme.sh to store more challenge information via normal parameters. Again there are 2 possibilities for this, where I actually prefer the 2nd option:
--challenge-alias
to allow typical credential URLs --challenge-alias "https://<user>:<password>@<challenge domain>.<auth domain>.<auth tld>[:<port>]/update
"
<user>
<pw>
<challenge domain>.<auth domain>.<auth tld>
https://<auth domain>.<auth tld>[:<port>]/update
--challenge-user "<user>"
, --challenge-pw "<pw>"
, --challenge-api1 "https://<auth domain>.<auth tld>[:<port>]/update"
, --challenge-api2 "https://<auth domain>.<auth tld>[:<port>]/register"
, etc.
--challenge-api
is numbered and not named, so that the meanings can differ per DNS API service/script, but still can be handled in a generic way within acme.sh--challenge-api1
to --challenge-api9
should provide enough flexibility for DNS API scripts, otherwise go for double digits 01-09 to allow much more in the future (up to 99; from my pov this is overkill)For both options acme.sh has to be checked (at least I would have to) how it stores multiple values as a list, how these are assigned to the final certificate SAN domains, and how to process them correctly within a DNS API script.
Spekpannenkoek's solution with creating additional config files for each challenge alias is better than using lots of env vars, but I still prefer to have a more generic solution that may help in more situations.
@Neilpang:
Direct contact possible via my homepage or outsource discusssion to a discussion thread.
Thanks for reading Maddes
I wrote my own acme-dns-client that works with acme.sh and certbot with multiple domains in a single certificate. The script uses Python, so it does not fully fit the acme.sh approach of "shell only". Please have a look here: https://github.com/maddes-b/acme-dns-client-2 Feedback welcome.
Hello,
Acme dns works fine for a subdomain but fails when multiple subdomains are requested.
Steps to reproduce
Just try issue with more than 1 subdomain. Interactively acme.sh prompts me to enter a CNAME record. I add the CNAME record to my DNS Server and then press Enter. It continues to work after I press enter but it does not prompt me to enter CNAME records for other subdomains. I guess that's why the subdomain validation step fails.
Command Output
Debug Log