From 93dc22a71f62e28b28788974f5474c6331e9fb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=20=7C=20Anton=20R=C3=B6hm?= <18481195+AnTheMaker@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:57:10 +0200 Subject: [PATCH 1/8] Support Nanelo DNS Team- & Workspace-specific API keys Nanelo Team- and Workspace-specific API keys require the "domain" parameter to be set containing the DNS zone name (unlike the Domain-specific API keys). So I've added a function to detect the root DNS zone and set the required parameter as described here: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide#3-detect-which-part-is-your-root-zone --- dnsapi/dns_nanelo.sh | 62 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nanelo.sh b/dnsapi/dns_nanelo.sh index 1ab47a89..cc3573a0 100644 --- a/dnsapi/dns_nanelo.sh +++ b/dnsapi/dns_nanelo.sh @@ -27,8 +27,16 @@ dns_nanelo_add() { fi _saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _info "Adding TXT record to ${fulldomain}" - response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")" + response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?domain=${_domain}&type=TXT&ttl=60&name=${_sub_domain}&value=${txtvalue}")" if _contains "${response}" 'success'; then return 0 fi @@ -51,8 +59,16 @@ dns_nanelo_rm() { fi _saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _info "Deleting resource record $fulldomain" - response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")" + response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?domain=${_domain}&type=TXT&ttl=60&name=${_sub_domain}&value=${txtvalue}")" if _contains "${response}" 'success'; then return 0 fi @@ -60,3 +76,45 @@ dns_nanelo_rm() { _err "${response}" return 1 } + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com + +_get_root() { + fulldomain=$1 + + # Fetch all zones from Nanelo + response="$(_get "$NANELO_API$NANELO_TOKEN/dns/getzones")" || return 1 + + # Extract "zones" array into space-separated list + zones=$(echo "$response" \ + | tr -d ' \n' \ + | sed -n 's/.*"zones":\[\([^]]*\)\].*/\1/p' \ + | tr -d '"' \ + | tr , ' ') + _debug zones "$zones" + + bestzone="" + for z in $zones; do + case "$fulldomain" in + *.$z|$z) + if [ ${#z} -gt ${#bestzone} ]; then + bestzone=$z + fi + ;; + esac + done + + if [ -z "$bestzone" ]; then + _err "No matching zone found for $fulldomain" + return 1 + fi + + _domain="$bestzone" + _sub_domain=$(printf "%s" "$fulldomain" | sed "s/\\.$_domain\$//") + + return 0 +} From 31d72645838a1781dc5e38c0b1291e94b30ad0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=20=7C=20Anton=20R=C3=B6hm?= <18481195+AnTheMaker@users.noreply.github.com> Date: Sun, 7 Sep 2025 17:14:06 +0200 Subject: [PATCH 2/8] Fix pattern matching for best zone selection --- dnsapi/dns_nanelo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nanelo.sh b/dnsapi/dns_nanelo.sh index cc3573a0..abf3cf47 100644 --- a/dnsapi/dns_nanelo.sh +++ b/dnsapi/dns_nanelo.sh @@ -100,7 +100,7 @@ _get_root() { bestzone="" for z in $zones; do case "$fulldomain" in - *.$z|$z) + *."$z"|"$z") if [ ${#z} -gt ${#bestzone} ]; then bestzone=$z fi From 5aa964cde997a091b47af6a0b355f236d8631391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=20=7C=20Anton=20R=C3=B6hm?= <18481195+AnTheMaker@users.noreply.github.com> Date: Sun, 7 Sep 2025 17:14:40 +0200 Subject: [PATCH 3/8] Formatting using shfmt to format the code --- dnsapi/dns_nanelo.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_nanelo.sh b/dnsapi/dns_nanelo.sh index abf3cf47..8bb95136 100644 --- a/dnsapi/dns_nanelo.sh +++ b/dnsapi/dns_nanelo.sh @@ -90,21 +90,21 @@ _get_root() { response="$(_get "$NANELO_API$NANELO_TOKEN/dns/getzones")" || return 1 # Extract "zones" array into space-separated list - zones=$(echo "$response" \ - | tr -d ' \n' \ - | sed -n 's/.*"zones":\[\([^]]*\)\].*/\1/p' \ - | tr -d '"' \ - | tr , ' ') + zones=$(echo "$response" | + tr -d ' \n' | + sed -n 's/.*"zones":\[\([^]]*\)\].*/\1/p' | + tr -d '"' | + tr , ' ') _debug zones "$zones" bestzone="" for z in $zones; do case "$fulldomain" in - *."$z"|"$z") - if [ ${#z} -gt ${#bestzone} ]; then - bestzone=$z - fi - ;; + *."$z" | "$z") + if [ ${#z} -gt ${#bestzone} ]; then + bestzone=$z + fi + ;; esac done From d8a92a2e658d4ea120dd71d41928e55dc713deb9 Mon Sep 17 00:00:00 2001 From: An <18481195+AnTheMaker@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:27:57 +0200 Subject: [PATCH 4/8] switch nanelo api to post requests --- dnsapi/dns_nanelo.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nanelo.sh b/dnsapi/dns_nanelo.sh index 8bb95136..23f306a7 100644 --- a/dnsapi/dns_nanelo.sh +++ b/dnsapi/dns_nanelo.sh @@ -36,7 +36,7 @@ dns_nanelo_add() { _debug _domain "$_domain" _info "Adding TXT record to ${fulldomain}" - response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?domain=${_domain}&type=TXT&ttl=60&name=${_sub_domain}&value=${txtvalue}")" + response="$(_post "" "$NANELO_API$NANELO_TOKEN/dns/addrecord?domain=${_domain}&type=TXT&ttl=60&name=${_sub_domain}&value=${txtvalue}" "" "" "")" if _contains "${response}" 'success'; then return 0 fi @@ -68,7 +68,7 @@ dns_nanelo_rm() { _debug _domain "$_domain" _info "Deleting resource record $fulldomain" - response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?domain=${_domain}&type=TXT&ttl=60&name=${_sub_domain}&value=${txtvalue}")" + response="$(_post "" "$NANELO_API$NANELO_TOKEN/dns/deleterecord?domain=${_domain}&type=TXT&ttl=60&name=${_sub_domain}&value=${txtvalue}" "" "" "")" if _contains "${response}" 'success'; then return 0 fi From 65bd3d67b41d975019f194bdf3cb9e01680ba771 Mon Sep 17 00:00:00 2001 From: An <18481195+AnTheMaker@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:51:28 +0200 Subject: [PATCH 5/8] nanelo dns: minor log improvements --- dnsapi/dns_nanelo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nanelo.sh b/dnsapi/dns_nanelo.sh index 23f306a7..0c42989b 100644 --- a/dnsapi/dns_nanelo.sh +++ b/dnsapi/dns_nanelo.sh @@ -59,7 +59,7 @@ dns_nanelo_rm() { fi _saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN" - _debug "First detect the root zone" + _debug "First, let's detect the root zone:" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 From 48c48cb344d9f748dbc3c0dab1d7b1a62e5de7ba Mon Sep 17 00:00:00 2001 From: Roy Orbitson Date: Mon, 27 Oct 2025 16:02:33 +1030 Subject: [PATCH 6/8] Choose an IP address family for outgoing requests Useful where remote endpoints filter requests by IP address, but one's Internet connection has a stable IP for only one address family, e.g.: a dynamic IPv6 prefix and a static IPv4 address; or a static IPv6 prefix and CGNAT IPv4. --- acme.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/acme.sh b/acme.sh index 7caec290..98b827e8 100755 --- a/acme.sh +++ b/acme.sh @@ -1897,6 +1897,11 @@ _inithttp() { if [ -z "$_ACME_CURL" ] && _exists "curl"; then _ACME_CURL="curl --silent --dump-header $HTTP_HEADER " + if [ "$ACME_USE_IPV6_REQUESTS" ]; then + _ACME_CURL="$_ACME_CURL --ipv6 " + elif [ "$ACME_USE_IPV4_REQUESTS" ]; then + _ACME_CURL="$_ACME_CURL --ipv4 " + fi if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then _ACME_CURL="$_ACME_CURL -L " fi @@ -1924,6 +1929,11 @@ _inithttp() { if [ -z "$_ACME_WGET" ] && _exists "wget"; then _ACME_WGET="wget -q" + if [ "$ACME_USE_IPV6_REQUESTS" ]; then + _ACME_WGET="$_ACME_WGET --inet6-only " + elif [ "$ACME_USE_IPV4_REQUESTS" ]; then + _ACME_WGET="$_ACME_WGET --inet4-only " + fi if [ "$ACME_HTTP_NO_REDIRECTS" ]; then _ACME_WGET="$_ACME_WGET --max-redirect 0 " fi @@ -7076,6 +7086,8 @@ Parameters: --alpn Use standalone alpn mode. --stateless Use stateless mode. See: $_STATELESS_WIKI + --request-v4 Force client requests to use ipv4. + --request-v6 Force client requests to use ipv6. --apache Use Apache mode. --dns [dns_hook] Use dns manual mode or dns api. Defaults to manual mode when argument is omitted. @@ -7255,6 +7267,20 @@ _processAccountConf() { _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" fi + if [ "$_request_v6" ]; then + _saveaccountconf "ACME_USE_IPV6_REQUESTS" "$_request_v6" + _clearaccountconf "ACME_USE_IPV4_REQUESTS" + elif [ "$ACME_USE_IPV6_REQUESTS" ]; then + _saveaccountconf "ACME_USE_IPV6_REQUESTS" "$ACME_USE_IPV6_REQUESTS" + _clearaccountconf "ACME_USE_IPV4_REQUESTS" + elif [ "$_request_v4" ]; then + _saveaccountconf "ACME_USE_IPV4_REQUESTS" "$_request_v4" + _clearaccountconf "ACME_USE_IPV6_REQUESTS" + elif [ "$ACME_USE_IPV4_REQUESTS" ]; then + _saveaccountconf "ACME_USE_IPV4_REQUESTS" "$ACME_USE_IPV4_REQUESTS" + _clearaccountconf "ACME_USE_IPV6_REQUESTS" + fi + } _checkSudo() { @@ -7420,6 +7446,8 @@ _process() { _local_address="" _log_level="" _auto_upgrade="" + _request_v4="" + _request_v6="" _listen_v4="" _listen_v6="" _openssl_bin="" @@ -7885,6 +7913,18 @@ _process() { fi AUTO_UPGRADE="$_auto_upgrade" ;; + --request-v4) + _request_v4="1" + ACME_USE_IPV4_REQUESTS="1" + _request_v6="" + ACME_USE_IPV6_REQUESTS="" + ;; + --request-v6) + _request_v6="1" + ACME_USE_IPV6_REQUESTS="1" + _request_v4="" + ACME_USE_IPV4_REQUESTS="" + ;; --listen-v4) _listen_v4="1" Le_Listen_V4="$_listen_v4" From 57f8221bab028429b0a699464d7f4bf40c61701b Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 9 Nov 2025 19:58:25 +0100 Subject: [PATCH 7/8] fix --request-v4/6 https://github.com/acmesh-official/acme.sh/pull/6582 --- acme.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 98b827e8..8ac9b366 100755 --- a/acme.sh +++ b/acme.sh @@ -7086,8 +7086,6 @@ Parameters: --alpn Use standalone alpn mode. --stateless Use stateless mode. See: $_STATELESS_WIKI - --request-v4 Force client requests to use ipv4. - --request-v6 Force client requests to use ipv6. --apache Use Apache mode. --dns [dns_hook] Use dns manual mode or dns api. Defaults to manual mode when argument is omitted. @@ -7149,6 +7147,8 @@ Parameters: --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. Defaults to 1 if argument is omitted. --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. + --request-v4 Force client requests to use ipv4 to connect to the CA server. + --request-v6 Force client requests to use ipv6 to connect to the CA server. --openssl-bin Specifies a custom openssl bin location. --use-wget Force to use wget, if you have both curl and wget installed. --yes-I-know-dns-manual-mode-enough-go-ahead-please Force use of dns manual mode. @@ -7270,15 +7270,19 @@ _processAccountConf() { if [ "$_request_v6" ]; then _saveaccountconf "ACME_USE_IPV6_REQUESTS" "$_request_v6" _clearaccountconf "ACME_USE_IPV4_REQUESTS" - elif [ "$ACME_USE_IPV6_REQUESTS" ]; then - _saveaccountconf "ACME_USE_IPV6_REQUESTS" "$ACME_USE_IPV6_REQUESTS" - _clearaccountconf "ACME_USE_IPV4_REQUESTS" + ACME_USE_IPV4_REQUESTS= elif [ "$_request_v4" ]; then _saveaccountconf "ACME_USE_IPV4_REQUESTS" "$_request_v4" _clearaccountconf "ACME_USE_IPV6_REQUESTS" + ACME_USE_IPV6_REQUESTS= + elif [ "$ACME_USE_IPV6_REQUESTS" ]; then + _saveaccountconf "ACME_USE_IPV6_REQUESTS" "$ACME_USE_IPV6_REQUESTS" + _clearaccountconf "ACME_USE_IPV4_REQUESTS" + ACME_USE_IPV4_REQUESTS= elif [ "$ACME_USE_IPV4_REQUESTS" ]; then _saveaccountconf "ACME_USE_IPV4_REQUESTS" "$ACME_USE_IPV4_REQUESTS" _clearaccountconf "ACME_USE_IPV6_REQUESTS" + ACME_USE_IPV6_REQUESTS= fi } From 4a7f35dea7f8a91545976245e89730bc3f3ffeb1 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 15 Nov 2025 11:12:00 +0100 Subject: [PATCH 8/8] remove clientauth https://github.com/acmesh-official/acme.sh/issues/6610 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 8ac9b366..95337cc8 100755 --- a/acme.sh +++ b/acme.sh @@ -1271,7 +1271,7 @@ _createcsr() { _savedomainconf Le_ExtKeyUse "$Le_ExtKeyUse" printf "\nextendedKeyUsage=$Le_ExtKeyUse\n" >>"$csrconf" else - printf "\nextendedKeyUsage=serverAuth,clientAuth\n" >>"$csrconf" + printf "\nextendedKeyUsage=serverAuth\n" >>"$csrconf" fi if [ "$acmeValidationv1" ]; then