What's new

[SOLUTION] asus-wrapper-acme.sh Adds --dns Support for Let's Encrypt Wildcard SAN Certs to Integrated Asus acme.sh Implementation

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

That's my gut feeling as well.

Looking at the originalconfig-webgui.sh script again, I noticed that the *.pem files get copied to /jffs/ssl only if the /jffs/ssl directory exists ( [ -d /jffs/ssl ] }

In that case, I am assuming that some Asus products put the keys in /jffs/ssl while others put them in /jffs/.cert (as the scripts tests for that directory before coping). In this way, the script casts a wide net over a bunch of Asus products.
 
@garycnew it's not said explicitly anywhere, but I take it that the acme.sh and dnsapi in /jffs/bin/ are copied down from the acme.sh repo?
@jorhett

Correct... The acme.sh and dnsapi are the latest versions of the scripts from the acme.sh website. The domains file is a plain text file you create. I actually ended up writing my own dnsapi for an in-house DNS service, which works quite well.

I hope this clarification helps.

Respectfully,


Gary
 
Last edited:
All:

For those of you whom use the integrated Asus acme.sh implementation with Let's Encrypt, you are familiar with its limitations in only issuing LE Certs with the --standalone method.

The following asus-wrapper-acme.sh script manipulates the default Asus acme.sh arguments to extend its use to include the --dns method, which enables issuing LE Wildcard SAN Certs:
Code:
# cat /jffs/sbin/asus-wrapper-acme.sh
#!/bin/sh

### asus-wrapper-acme.sh v.0.0.7 ###

# Default Asus acme.sh cli arguments
#/usr/sbin/acme.sh --home /tmp/.le --certhome /jffs/.le --accountkey /jffs/.le/account.key --accountconf /jffs/.le/account.conf --domain domain.tld --useragent asusrouter/0.2 --fullchain-file /jffs/.le/domain.tld/fullchain.pem --key-file /jffs/.le/domain.tld/domain.key --issue --standalone --httpport 51539
#/usr/sbin/acme.sh --home /tmp/.le --certhome /jffs/.le --accountkey /jffs/.le/account.key --accountconf /jffs/.le/account.conf --domain domain.tld --useragent asusrouter/0.2 --fullchain-file /jffs/.le/domain.tld/fullchain.pem --key-file /jffs/.le/domain.tld/domain.key --issue --standalone --httpport 39388 --staging
#/usr/sbin/acme.sh --home /tmp/.le --certhome /jffs/.le --accountkey /jffs/.le/account.key --accountconf /jffs/.le/account.conf --domain domain.tld --useragent asusrouter/0.2 --fullchain-file /jffs/.le/domain.tld/fullchain.pem --key-file /jffs/.le/domain.tld/domain.key --issue --standalone --httpport 27852 --force --staging
#/usr/sbin/acme.sh --home /tmp/.le --certhome /jffs/.le --accountkey /jffs/.le/account.key --accountconf /jffs/.le/account.conf --domain domain.tld --useragent asusrouter/0.2 --fullchain-file /jffs/.le/domain.tld/fullchain.pem --key-file /jffs/.le/domain.tld/domain.key --issue --standalone --httpport 44797 --debug 1 --staging
#/usr/sbin/acme.sh --home /tmp/.le --certhome /jffs/.le --accountkey /jffs/.le/account.key --accountconf /jffs/.le/account.conf --domain domain.tld --useragent asusrouter/0.2 --fullchain-file /jffs/.le/domain.tld/fullchain.pem --key-file /jffs/.le/domain.tld/domain.key --revoke --debug 1 --force --staging

# Asus acme.sh NVRAM variables
# nvram show | grep -i acme
#le_acme_force=0
#le_acme_auth=http
#le_acme_debug=0
#le_acme_renew_force=0
#le_acme_stage=0
#le_acme_logpath=
# nvram set le_acme_force=[0|1]
# nvram set le_acme_auth=[http|????]
# nvram set le_acme_debug=[0|1|2]
# nvram set le_acme_renew_force=[0|1]
# nvram set le_acme_stage=[0|1]
# nvram set le_acme_logpath=[/tmp/acme.log] (overrides syslog)

# If domains file does not exist, use default Asus DDNS domain
domains="/jffs/.le/domains"

# Make sure the base domain (cert directory name) is last in each entry
# cat /jffs/.le/domains
# www.domain.tld|domain.tld
# *.domain.tld|domain.tld
# *.example.tld|example.tld|*.domain.tld|domain.tld
# *.example.tld|example.tld|*.sample.tld|sample.tld|*.domain.tld|domain.tld
# www.example.tld|example.tld|www.sample.tld|sample.tld|www.domain.tld|domain.tld

# Mount bind caches asus-wrapper-acme.sh. Remount after any script edits.
# cat /jffs/scripts/post-mount
# Check Whether dns_ispman.sh File Exist
#if [ ! -f "/usr/sbin/dnsapi/dns_ispman.sh" ]; then
#   /bin/mount -o bind /jffs/sbin/dnsapi /usr/sbin/dnsapi
#   /bin/mount -o bind /jffs/sbin/asus-wrapper-acme.sh /usr/sbin/acme.sh
#fi

# service restart_letsencrypt

domarg="--domain"
domain="${10}"
dnsarg="--dns"
dnsapi="dns_ispman"

#logger -t acme "$*"

if [ -f "$domains" ]; then
   while read entry; do

   #logger -t acme "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}" "${15}" "${16}" "${17}" "${18}" "${19}" "${20}" "${21}" "${22}" "${23}" "${24}" "${25}"
   #echo BEFORE "1:$1" "2:$2" "3:$3" "4:$4" "5:$5" "6:$6" "7:$7" "8:$8" "9:$9" "10:${10}" "11:${11}" "12:${12}" "13:${13}" "14:${14}" "15:${15}" "16:${16}" "17:${17}" "18:${18}" "19:${19}" "20:${20}" "21:${21}" "22:${22}" "23:${23}" "24:${24}" "25:${25}"

   #echo "n: $n"

   if [ -z "$n" ]; then
      IFS=$'|'; for domain in $entry; do :; chainfile="$(echo ${14} | sed -E "s/\/jffs\/\.le\/(.+?)\/fullchain\.pem/\/jffs\/\.le\/$domain\/fullchain\.pem/g;")"; keyfile="$(echo ${16} | sed -E "s/\/jffs\/\.le\/(.+?)\/domain\.key/\/jffs\/\.le\/$domain\/domain\.key/g;")"; done
      #echo "chainfile: $chainfile"
      #echo "keyfile: $keyfile"
      if [ "${24}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "${22}" "${23}" "${24}" "$dnsarg" "$dnsapi"
      elif [ "${23}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "${22}" "${23}" "$dnsarg" "$dnsapi"
      elif [ "${22}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "${22}" "$dnsarg" "$dnsapi"
      elif [ "${21}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "$dnsarg" "$dnsapi"
      else
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "$dnsarg" "$dnsapi"
      fi
   else
      IFS=$'|'; for domain in $entry; do :; chainfile="$(echo ${12} | sed -E "s/\/jffs\/\.le\/(.+?)\/fullchain\.pem/\/jffs\/\.le\/$domain\/fullchain\.pem/g;")"; keyfile="$(echo ${14} | sed -E "s/\/jffs\/\.le\/(.+?)\/domain\.key/\/jffs\/\.le\/$domain\/domain\.key/g;")"; done
      #echo "chainfile: $chainfile"
      #echo "keyfile: $keyfile"
      if [ "${21}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$chainfile" "${13}" "$keyfile" "${15}" "${16}" "${17}" "${18}" "${19}" "${20}" "${21}"
      elif [ "${20}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$chainfile" "${13}" "$keyfile" "${15}" "${16}" "${17}" "${18}" "${19}" "${20}"
      elif [ "${19}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$chainfile" "${13}" "$keyfile" "${15}" "${16}" "${17}" "${18}" "${19}"
      elif [ "${18}" ]; then
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$chainfile" "${13}" "$keyfile" "${15}" "${16}" "${17}" "${18}"
      else
         set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "$chainfile" "${13}" "$keyfile" "${15}" "${16}" "${17}"
      fi
   fi

   n=0; IFS=$'|'; for domain in $entry; do :; set -- "$domarg" "$domain" "$@"; n=$((n + 2)); done

   #echo "n: $n"

   #echo AFTER "1:$1" "2:$2" "3:$3" "4:$4" "5:$5" "6:$6" "7:$7" "8:$8" "9:$9" "10:${10}" "11:${11}" "12:${12}" "13:${13}" "14:${14}" "15:${15}" "16:${16}" "17:${17}" "18:${18}" "19:${19}" "20:${20}" "21:${21}" "22:${22}" "23:${23}" "24:${24}" "25:${25}"
   #logger -t acme "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}" "${15}" "${16}" "${17}" "${18}" "${19}" "${20}" "${21}" "${22}" "${23}" "${24}" "${25}"

   /jffs/sbin/acme.sh "$@"
   #wait $!

   shift $n
   #unset n
   done <$domains
else
   #logger -t acme "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}" "${15}" "${16}" "${17}" "${18}" "${19}" "${20}" "${21}" "${22}" "${23}" "${24}" "${25}"
   #echo BEFORE "1:$1" "2:$2" "3:$3" "4:$4" "5:$5" "6:$6" "7:$7" "8:$8" "9:$9" "10:${10}" "11:${11}" "12:${12}" "13:${13}" "14:${14}" "15:${15}" "16:${16}" "17:${17}" "18:${18}" "19:${19}" "20:${20}" "21:${21}" "22:${22}" "23:${23}" "24:${24}" "25:${25}"

   chainfile="$(echo ${14} | sed -E "s/\/jffs\/\.le\/(.+?)\/fullchain\.pem/\/jffs\/\.le\/$domain\/fullchain\.pem/g;")"; keyfile="$(echo ${16} | sed -E "s/\/jffs\/\.le\/(.+?)\/domain\.key/\/jffs\/\.le\/$domain\/domain\.key/g;")";
   #echo "chainfile: $chainfile"
   #echo "keyfile: $keyfile"
   if [ "${24}" ]; then
      set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "${22}" "${23}" "${24}" "$dnsarg" "$dnsapi"
   elif [ "${23}" ]; then
      set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "${22}" "${23}" "$dnsarg" "$dnsapi"
   elif [ "${22}" ]; then
      set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "${22}" "$dnsarg" "$dnsapi"
   elif [ "${21}" ]; then
      set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "${21}" "$dnsarg" "$dnsapi"
   else
      set -- "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "${11}" "${12}" "${13}" "$chainfile" "${15}" "$keyfile" "${17}" "$dnsarg" "$dnsapi"
   fi

   set -- "$domarg" "$domain" "$@"

   #echo AFTER "1:$1" "2:$2" "3:$3" "4:$4" "5:$5" "6:$6" "7:$7" "8:$8" "9:$9" "10:${10}" "11:${11}" "12:${12}" "13:${13}" "14:${14}" "15:${15}" "16:${16}" "17:${17}" "18:${18}" "19:${19}" "20:${20}" "21:${21}" "22:${22}" "23:${23}" "24:${24}" "25:${25}"
   #logger -t acme "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" "${10}" "${11}" "${12}" "${13}" "${14}" "${15}" "${16}" "${17}" "${18}" "${19}" "${20}" "${21}" "${22}" "${23}" "${24}" "${25}"

   /jffs/sbin/acme.sh "$@"
fi

The acme.sh and dnsapi files are the latest versions available from the acme.sh website.

In addition, asus-wrapper-acme.sh accepts a "/jffs/.le/domains" file to automate the renewal of additional Let's Encrypt Certificates.

Presently, everything is working except the --revoke argument, which just needs to be added to the asus-wrapper-acme.sh script

Respectfully,


Gary

P.S. Props to @Dabombber for guiding me down the Asus acme.sh hole.
I knew I left it somewhere around here @Viktor Jaep
 
Hi @garycnew ,
I'm trying to run your wrapper script with a fresh copy of acme.sh (version 3.0.6) but I'm getting the following error:
Code:
[Tue Apr 25 11:55:11 CEST 2023] Unknown parameter :
The error is shown whether I add a command like --issue -d myhostname.example.com --server letsencrypt --dns or without. Am I missing something?
 
Hi @garycnew ,
I'm trying to run your wrapper script with a fresh copy of acme.sh (version 3.0.6) but I'm getting the following error:
Code:
[Tue Apr 25 11:55:11 CEST 2023] Unknown parameter :
The error is shown whether I add a command like --issue -d myhostname.example.com --server letsencrypt --dns or without. Am I missing something?

Are you trying to use a spicific DNS api (i.e. GoDaddy)? If so, you are missing the API name in your --dns option.

 
Hi everyone
I'm trying to make this working on my RT-AX88U Pro running latest Merlin.

I own a FQDN, and I'd like to obtain a wildcard certificate. The one I'm running is valid only for example.com domain, but not for www.example.com
DDNS provider is FreeDNS.

Could somebody please help me?
I'm missing something.

What I've done:
  1. Downloaded latest ACME following this WIKI. Latest files are being installed automatically into /root/.acme.sh/; I copied acme.sh and dnsapi directory into /jffs/sbin directory
  2. asus-wrapper-acme.sh copied in /jffs/sbin; changed only the following parameter: dnsapi="dns_freedns"
  3. note: /usr/sbin/dnsapi/dns_ispman.sh doesn't exist; in that directory I've just dns_asusapi.sh
  4. added mount lines to /jffs/scripts/post-mount
However, when I try to launch asus-acme-wrapper script, I get "Unknown parameter :" error.

Thanks for help
 
Last edited:
Hi everyone
I'm trying to make this working on my RT-AX88U Pro running latest Merlin.

I own a FQDN, and I'd like to obtain a wildcard certificate. The one I'm running is valid only for example.com domain, but not for www.example.com
DDNS provider is FreeDNS.

Could somebody please help me?
I'm missing something.

What I've done:
  1. Downloaded latest ACME following this WIKI. Latest files are being installed automatically into /root/.acme.sh/; I copied acme.sh and dnsapi directory into /jffs/sbin directory
  2. asus-wrapper-acme.sh copied in /jffs/sbin; changed only the following parameter: dnsapi="dns_freedns"
  3. note: /usr/sbin/dnsapi/dns_ispman.sh doesn't exist; in that directory I've just dns_asusapi.sh
  4. added mount lines to /jffs/scripts/post-mount
However, when I try to launch asus-acme-wrapper script, I get "Unknown parameter :" error.

Thanks for help

I have not looked at Gray's wrapper package in ages. That said, I went with my own approach. If you want, here is the script I used to issue my certificates on my AX88U and install the cert as the GUI cert. The script also saves the certificates as pem files so that I can use in other apps that I need them.

Since you are using freeDNS, you will need to alter this a bit using the DNS code from the wiki (https://github.com/acmesh-official/acme.sh/wiki/dnsapi#15-use-freedns)

You will also need to change the home directory and the key directory - as required.

Code:
#!/bin/sh

# Version: 1.00
# Date: February 21, 2022

KEYDIR="/opt/home/RT86Ukeys"
export GD_Key="Your Key"
export GD_Secret="Your Secret"
export MAX_RETRY_TIMES=100

mkdir -p "${KEYDIR}"

# ache.sh error codes
#    0: certificate request successful
#    1: certificate request failed
#    2: certificate still valid, request skipped
#        Valid only on --renew.  --cron will return 0 if current certificate is valid

/opt/home/acme/acme.sh --home /opt/home/acme \
    --dns dns_gd \
    --set-default-ca --server  zerossl \
    --issue \
    --domain name.domain.tld \
    --domain *.domain.tld \
    --domain *.ad.domain.tld \
    --keylength 2048 \
    --cert-file ${KEYDIR}/cert.pem \
    --key-file ${KEYDIR}/key.pem \
    --ca-file ${KEYDIR}/ca.pem \
    --fullchain-file ${KEYDIR}/fullchain.pem \
    --force

# le_enable = 0 > No SSL Certificate (none selected)
# le_enable = 1 > use certificate from Let's Encrypt
# le_enable = 2 > use your own uploaded certificate (imported)

RST=$(echo "$?")

if [ "$RST" = "0" ]; then

    chmod 644 ${KEYDIR}/cert.pem
    chmod 644 ${KEYDIR}/ca.pem
    chmod 644 ${KEYDIR}/fullchain.pem
    chmod 600 ${KEYDIR}/key.pem
    for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
        [ -d "$p" ] && \
            cp ${KEYDIR}/cert.pem ${p}/cert.pem && \
            cp ${KEYDIR}/key.pem ${p}/key.pem
    done
    nvram set le_enable=2
    nvram set https_crt_save=1
    nvram set https_crt_file=""
    service restart_httpd 1>&2 > /dev/null
    nvram commit
fi
 
Hi @Jeffrey Young ,
thanks for your script, it worked perfectly.

Btw, have you made a Cron script too for auto renewal after 90 days?
In case, would you be so kind to share it?

For other people who could be interested, this is the script working with FreeDNS.

Thank you

Code:
#!/bin/sh

# Version: 1.00
# Date: February 21, 2022

KEYDIR="/opt/home/RTAX88UPro_Keys"
export FREEDNS_User="my_FreeDNS_username"
export FREEDNS_Password="my_FreeDNS_password"
export MAX_RETRY_TIMES=100

mkdir -p "${KEYDIR}"

# acme.sh error codes
#    0: certificate request successful
#    1: certificate request failed
#    2: certificate still valid, request skipped
#        Valid only on --renew.  --cron will return 0 if current certificate is valid

/opt/home/acme/acme.sh --home /opt/home/acme \
    --dns dns_freedns \
    --set-default-ca --server  zerossl \
    --issue \
    --domain mydomain.com \
    --domain *.mydomain.com \
    --keylength 2048 \
    --cert-file ${KEYDIR}/cert.pem \
    --key-file ${KEYDIR}/key.pem \
    --ca-file ${KEYDIR}/ca.pem \
    --fullchain-file ${KEYDIR}/fullchain.pem \
    --force

# le_enable = 0 > No SSL Certificate (none selected)
# le_enable = 1 > use certificate from Let's Encrypt
# le_enable = 2 > use your own uploaded certificate (imported)

RST=$(echo "$?")

if [ "$RST" = "0" ]; then

    chmod 644 ${KEYDIR}/cert.pem
    chmod 644 ${KEYDIR}/ca.pem
    chmod 644 ${KEYDIR}/fullchain.pem
    chmod 600 ${KEYDIR}/key.pem
    for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
        [ -d "$p" ] && \
            cp ${KEYDIR}/cert.pem ${p}/cert.pem && \
            cp ${KEYDIR}/key.pem ${p}/key.pem
    done
    nvram set le_enable=2
    nvram set https_crt_save=1
    nvram set https_crt_file=""
    service restart_httpd 1>&2 > /dev/null
    nvram commit
fi
 
Hi @Jeffrey Young ,
thanks for your script, it worked perfectly.

Btw, have you made a Cron script too for auto renewal after 90 days?
In case, would you be so kind to share it?

For other people who could be interested, this is the script working with FreeDNS.

Thank you

Code:
#!/bin/sh

# Version: 1.00
# Date: February 21, 2022

KEYDIR="/opt/home/RTAX88UPro_Keys"
export FREEDNS_User="my_FreeDNS_username"
export FREEDNS_Password="my_FreeDNS_password"
export MAX_RETRY_TIMES=100

mkdir -p "${KEYDIR}"

# acme.sh error codes
#    0: certificate request successful
#    1: certificate request failed
#    2: certificate still valid, request skipped
#        Valid only on --renew.  --cron will return 0 if current certificate is valid

/opt/home/acme/acme.sh --home /opt/home/acme \
    --dns dns_freedns \
    --set-default-ca --server  zerossl \
    --issue \
    --domain mydomain.com \
    --domain *.mydomain.com \
    --keylength 2048 \
    --cert-file ${KEYDIR}/cert.pem \
    --key-file ${KEYDIR}/key.pem \
    --ca-file ${KEYDIR}/ca.pem \
    --fullchain-file ${KEYDIR}/fullchain.pem \
    --force

# le_enable = 0 > No SSL Certificate (none selected)
# le_enable = 1 > use certificate from Let's Encrypt
# le_enable = 2 > use your own uploaded certificate (imported)

RST=$(echo "$?")

if [ "$RST" = "0" ]; then

    chmod 644 ${KEYDIR}/cert.pem
    chmod 644 ${KEYDIR}/ca.pem
    chmod 644 ${KEYDIR}/fullchain.pem
    chmod 600 ${KEYDIR}/key.pem
    for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
        [ -d "$p" ] && \
            cp ${KEYDIR}/cert.pem ${p}/cert.pem && \
            cp ${KEYDIR}/key.pem ${p}/key.pem
    done
    nvram set le_enable=2
    nvram set https_crt_save=1
    nvram set https_crt_file=""
    service restart_httpd 1>&2 > /dev/null
    nvram commit
fi

You can use the same script, just replace the acme.sh command with something like;

Code:
/opt/home/acme/acme.sh --home /opt/home/acme --renew ${FORCE} \
        --domain ${DOMAIN} \
        --log ${ACMELOG} \
        --server zerossl # --debug

If you specified mutiple domains (such as a domain and a wildcard) when you created the certificates, you only need to specify the first domain you used in the install/create script. Acme.sh will already have a record of the other domains needed in the renewal.

You can further test the return value ($RST) to see if it equals "2". If it does, you know the renewal request succeeded, but nothing needed to be done.

I have a cron job set up to check to see if a renewal is required twice a day. Acme.sh will renew on the 61st day by default. My script goes one step further and emails me when a renewal happens.
 
Last edited:
You can use the same script, just replace the acme.sh command with something like;

Code:
/opt/home/acme/acme.sh --home /opt/home/acme --renew ${FORCE} \
        --domain ${DOMAIN} \
        --log ${ACMELOG} \
        --server zerossl # --debug

If you specified mutiple domains (such as a domain and a wildcard) when you created the certificates, you only need to specify the first domain you used in the install/create script. Acme.sh will already have a record of the other domains needed in the renewal.

You can further test the return value ($RST) to see if it equals "2". If it does, you know the renewal request succeeded, but nothing needed to be done.

I have a cron job set up to check to see if a renewal is required twice a day. Acme.sh will renew on the 61st day by default. My script goes one step further and emails me when a renewal happens.
My script has gotten... a little more complex because I started using dnsapi scripts along side acme.sh
 
My script has gotten... a little more complex because I started using dnsapi scripts along side acme.sh

Lol. Yeah, my actual script is a bit more hairy as I distribute my certs around to other resources on renewal as well as email me status. I figure start out small, then grow.

Love to see you work sometime though.
 
Hi All!

Apologies for not seeing/responding to the recent comments to this post. The asus-wrapper-acme.sh script was working well, until my renewals failed on 1 July 2023, which I only recently noticed and brought me back to this post.

In the troubleshooting process, I too received the 'Unknown parameter : error'. Believing it might be related to an old acme-3.0.1.sh script that I was using, I upgraded to the lated acme-3.0.6.sh implementation. However, I continued to receive the same error. I finally narrowed this down to user error on my part by failing to specify an appropriate connection method (i.e., standalone, dns, etc).

After resolving the previous error, I then began to receive a "Register account Error: {"type":"urn:ietf:params:acme:error:malformed","status":400,"detail":"[External Account Binding] Invalid MAC on JWS request"}" error" that was ultimately the core issue and a result of ZeroSSL no longer offering FREE Wildcard SAN Certs.

EDIT: It seems something has changed at ZeroSSL initiating this failure with acme.sh, but the cause and resolution are still under investigation.

In short...

- Acme-3.0.6.sh and older scripts work with asus-wrapper-acme.sh.
- ZeroSSL no longer offers FREE Wildcard SAN Certs.
- EDIT: ZeroSSL still offers FREE Wildcard SAN Certs via acme.sh, but does not offer them manually through the web interface.
- Switch back to using Let's Encrypt for Wildcard SAN Certs.

Respectfully,


Gary

P.S. I noticed that someone thought enough of the asus-wrapper-acme.sh script to share it on GitHub providing reference to the original work. Much Appreciated!
 
Last edited:
Hi All!

Apologies for not seeing/responding to the recent comments to this post. The asus-wrapper-acme.sh script was working well, until my renewals failed on 1 July 2023, which I only recently noticed and brought me back to this post.

In the troubleshooting process, I too received the 'Unknown parameter : error'. Believing it might be related to an old acme-3.0.1.sh script that I was using, I upgraded to the lated acme-3.0.6.sh implementation. However, I continued to receive the same error. I finally narrowed this down to user error on my part by failing to specify an appropriate acme.sh connection method (i.e., standalone, dns, etc).

After resolving the previous error, I then began to receive a "Register account Error: {"type":"urn:ietf:params:acme:error:malformed","status":400,"detail":"[External Account Binding] Invalid MAC on JWS request"}" error" that was ultimately the core issue and a result of ZeroSSL no longer offering FREE Wildcard SAN Certs.

In short...

- Acme-3.0.6.sh and older scripts work with asus-wrapper-acme.sh.
- ZeroSSL no longer offers FREE Wildcard SAN Certs.
- Switch back to using Let's Encrypt for Wildcard SAN Certs.

Respectfully,


Gary

P.S. I noticed that someone thought enough of the asus-wrapper-acme.sh script to share it on GitHub providing reference to the original work. Much Appreciated!
Gary, that is interesting what you say about the wildcard certificates. My system renewed my wildcard certificate just two days ago using acme.sh. using zeroSSL. I'll have to look into this further.

EDIT: Nevermind. Brain fart. I'm using subdomain wildcard certs. Not multi domain. I'll be ok. Long day
 
Last edited:
Hi All!

Apologies for not seeing/responding to the recent comments to this post. The asus-wrapper-acme.sh script was working well, until my renewals failed on 1 July 2023, which I only recently noticed and brought me back to this post.

In the troubleshooting process, I too received the 'Unknown parameter : error'. Believing it might be related to an old acme-3.0.1.sh script that I was using, I upgraded to the lated acme-3.0.6.sh implementation. However, I continued to receive the same error. I finally narrowed this down to user error on my part by failing to specify an appropriate connection method (i.e., standalone, dns, etc).

After resolving the previous error, I then began to receive a "Register account Error: {"type":"urn:ietf:params:acme:error:malformed","status":400,"detail":"[External Account Binding] Invalid MAC on JWS request"}" error" that was ultimately the core issue and a result of ZeroSSL no longer offering FREE Wildcard SAN Certs.

In short...

- Acme-3.0.6.sh and older scripts work with asus-wrapper-acme.sh.
- ZeroSSL no longer offers FREE Wildcard SAN Certs.
- Switch back to using Let's Encrypt for Wildcard SAN Certs.

Respectfully,


Gary

P.S. I noticed that someone thought enough of the asus-wrapper-acme.sh script to share it on GitHub providing reference to the original work. Much Appreciated!
I ran into this issue as well. What I did was write a dnsapi script for each of different domain. I now renew using dnsapi script because something definitely broke.
 
I ran into this issue as well. What I did was write a dnsapi script for each of different domain. I now renew using dnsapi script because something definitely broke

You jogged my memory on this one. I do now remember trying to use standalone mode once with ZeroSSL and was not able to have a multi-subdomain wildcard certificate issued. I went back to using the DNSapi (GoDaddy) and no problem.

I've only ever had one issue using the DNSapi mode. Once, the TXT record that acme.sh creates on domain provider was not deleted on cleanup after the verification process. On next renewal, the renewal failed. For three days I tore what little hair I have left trying to figure out why the renewal was not working. I finally noticed the rouge TXT record in my GoDaddy account. Deleted the TXT record and low and behold, the renewal worked. Don't know what happened, but thought I would mention it just in case someone else runs into it.
 
I ran into this issue as well. What I did was write a dnsapi script for each of different domain. I now renew using dnsapi script because something definitely broke.

As part of my troubleshooting efforts, I logged in to ZeroSSL and attempted to manually renew expired certificates. In that process, ZeroSSL's available plans showed that the Free 3-domain option no longer supported wildcard, multi-domain certificates. It suggested that I would need to upgrade to their $50/mnth plan.

EDIT: ZeroSSL still offers FREE Wildcard SAN Certs via acme.sh, but does not offer them manually through the web interface.

I have a ticket "Register account Error: {"type":"urn:ietf:params:acme:error:malformed","status":400,"detail":"[External Account Binding] Invalid MAC on JWS request"}" open with Neil Pang (acme.sh developer) to try and further understand the issue.

@SomeWhereOverTheRainBow I have used a custom dnsapi that I wrote back when I wrote the asus-wrapper-acme.sh script, which had been working without issue (until 1 July 2023).

Would you mind describing in more detail your work around with your dnsapi?

Thank you for your time and assistance.

Kind Regards,


Gary

P.S. This issue is specific to acme.sh using ZeroSSL as the CA. The process works perfectly using acme.sh with Let's Encrypt as the CA.
 
Last edited:
Hey @garycnew

You had me worried there as I was sure my ZeroSSL certificates renewed after July 1, 2023 and I use wildcard subdomain certificates, so I just did a force renew to see if everything is OK with wildcard certificates. I use the DNSapi for GoDaddy.

For me, my initial certificate request command line looks like this;
Code:
#!/bin/sh

# Version: 1.00
# Date: February 21, 2022

KEYDIR="/opt/home/RT86Ukeys"
export GD_Key="Go daddy Key"
export GD_Secret="Go daddy Secret"
export MAX_RETRY_TIMES=100

mkdir -p "${KEYDIR}"

# ache.sh error codes
#    0: certificate request successful
#    1: certificate request failed
#    2: certificate still valid, request skipped
#        Valid only on --renew.  --cron will return 0 if current certificate is valid

/opt/home/acme/acme.sh --home /opt/home/acme \
    --dns dns_gd \
    --set-default-ca --server  zerossl \
    --issue \
    --domain rtax88u.youngind.ca \
    --domain *.youngind.ca \
    --domain *.young.youngind.ca \
    --useragent "YoungIndustries" \
    --keylength 2048 \
    --cert-file ${KEYDIR}/cert.pem \
    --key-file ${KEYDIR}/key.pem \
    --ca-file ${KEYDIR}/ca.pem \
    --fullchain-file ${KEYDIR}/fullchain.pem \
    --force

To do a renew, I use the code;

Code:
#!/bin/sh
# Date last revised: May 3, 2023
# Command line variables
#
#    $1 = force - will force certificate renewals

export GD_Key="Go Daddy Key"
export GD_Secret="Go daddy Secret"
export MAX_RETRY_TIMES=100

SCRIPTNAME="ACME Renew"
DOMAIN="rtax88u.youngind.ca"
LOGDIR="/opt/var/log/acme.log"
KEYDIR="/opt/home/RT86Ukeys"
ACMELOG="/opt/var/log/acme-renew-log.txt"

# ache.sh error codes
#    0: certificate request successful
#    1: certificate request failed
#    2: certificate still valid, request skipped
#        Valid only on --renew.  --cron will return 0 if current certificate is valid

[ "$1" = "force" ] && FORCE="--force" || FORCE=""

if [ -e "/tmp/cert-renewal.txt" ]; then
    rm /tmp/cert-renewal.txt
fi

logger -c -t ACME.SH "Checking RTAC86U certificate to see if it needs renewing"
/opt/home/acme/acme.sh --home /opt/home/acme --renew ${FORCE} \
    --domain ${DOMAIN} \
    --log ${ACMELOG} \
    --server zerossl # --debug

I don't know if this helps you or not. There are dozens of DNSapi for acme.sh. You need to look at their wiki for the API that matches the domain provider. In my case, my provider is Go Daddy, so the the command line option is --dns dns_gd with the key and secret provided by Go Daddy as an exported variable.

Wildcards work OK for me with the DNSapi. They don't in standalone mode. Tried.
 
I'm thinking that as far as using a DNS API, the issuing of wildcard certificates will depend on rather ort not the specific DNS provider supports them. As you point out, ZeroSSL does not, unless you pay for them, so standalone mode fails to issue the wildcard cert. Where as Let's Encrypt does.
 
I'm thinking that as far as using a DNS API, the issuing of wildcard certificates will depend on rather ort not the specific DNS provider supports them. As you point out, ZeroSSL does not, unless you pay for them, so standalone mode fails to issue the wildcard cert. Where as Let's Encrypt does.
ZeroSSL was issuing Wildcard, SAN Certs for the past year and a half with dnsapi.
 
Last edited:

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top