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!

garycnew

Senior Member
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.
 
Last edited:
Thank you for this. I have recently started down the rabbit hole of trying to issue a LE cert for my router withour having to use asus's ddns. Rather, I want to use my own domain name.

This will help as a learning tool.

cheers
 
Thank you for this. I have recently started down the rabbit hole of trying to issue a LE cert for my router withour having to use asus's ddns. Rather, I want to use my own domain name.

This will help as a learning tool.

cheers
FWIW I run Linuxserver's SWAG docker container that handles Lets Encrypt certificate, and I have a custom script that SSH's to the router and copies the updated cert across
 
FWIW I run Linuxserver's SWAG docker container that handles Lets Encrypt certificate, and I have a custom script that SSH's to the router and copies the updated cert across

I have never looked at SWAG. Don't even know what it is. Homework time. I have Ubuntu Domain Controller that I could run a Docker on.

Sounds a ton easier than trying to do it half as**ed on the router.
 
Thank you for this. I have recently started down the rabbit hole of trying to issue a LE cert for my router withour having to use asus's ddns. Rather, I want to use my own domain name.

This will help as a learning tool.

cheers
Hi @Jeffrey Young

I should let you know that the acme.sh script supports let's encrypt and zerossl certs, now.

I have switched to using zerossl's free offering as their certificate authority covers more legacy devices than let's encrypt.

I'm glad you like this post and I hope it assists you in your end goal.

Respectfully,


Gary
 
Hi @Jeffrey Young

I should let you know that the acme.sh script supports let's encrypt and zerossl certs, now.

I have switched to using zerossl's free offering as their certificate authority covers more legacy devices than let's encrypt.

I'm glad you like this post and I hope it assists you in your end goal.

Respectfully,


Gary
Me too!. I mount the latest version of acme.sh on top of the routers version. I then run the commands to get a zerossl cert.
 
Me too!. I mount the latest version of acme.sh on top of the routers version. I then run the commands to get a zerossl cert.
My reason for switching to zerossl is purely pragmatic. If let's encrypt were to update their certificate authority with one that worked with legacy devices I'd switch back.
 
Last edited:
Thanks guys. Appreciate the feedback.

I am still in the learning curve on getting acne.sh to work, but this wrapper offers excellent examples to study from. The acme.sh home page was an excellent resource as well.

Of course, @Jack Yaz idea got me, like a squirrel, reading up for a couple of hours in another direction.
 
Does zerossl have trusted root CA's in windows and MACs? It would be nice not to have to import trusted CAs as with PixcelSrv.
 
Thanks guys. Appreciate the feedback.

I am still in the learning curve on getting acne.sh to work, but this wrapper offers excellent examples to study from. The acme.sh home page was an excellent resource as well.

Of course, @Jack Yaz idea got me, like a squirrel, reading up for a couple of hours in another direction.
@Jeffrey Young

Personally, I prefer for Asuswrt-Merlin to manage the cert process for me. I just wish Asuswrt provided a better interface for the acme.sh process.

There's more than one way to skin an acme.sh script. Isn't it nice to have multiple options for a given task?

I'm glad you're finding the asus-wrapper-acme.sh script a good reference.

Respectfully,


Gary
 
@Jeffrey Young

Personally, I prefer for Asuswrt-Merlin to manage the cert process for me. I just wish Asuswrt provided a better interface for the acme.sh process.

There's more than one way to skin an acme.sh script. Isn't it nice to have multiple options for a given task?

I'm glad you're finding the asus-wrapper-acme.sh script a good reference.

Respectfully,


Gary

It would be simpler, but I like the idea of having one central CA authority for the network.
 
Does zerossl have trusted root CA's in windows and MACs? It would be nice not to have to import trusted CAs as with PixcelSrv.
Yes... As I previously stated, zerossl's root CA covers more legacy devices/applications, so you avoid having to import certs. It's ultimately the reason I switched to zerossl. Enjoy!
 
Yes... As I previously stated, zerossl's root CA covers more legacy devices/applications, so you avoid having to import certs. It's ultimately the reason I switched to zerossl. Enjoy!

Well, then. Sold. Will take @SomeWhereOverTheRainBow advice and mount the up to date acme.sh version from github over the ASUS supplied version.
 
It would be simpler, but I like the idea of having one central CA authority for the network.
@Jeffrey Young

I agree. That's why I made my Asuswrt-Merlin router my certificate manager and why I ended up creating the asus-wrapper-acme.sh script.

Do whatever method best works for you.

Respectfully,


Gary
 
Last edited:
Well, then. Sold. Will take @SomeWhereOverTheRainBow advice and mount the up to date acme.sh version from github over the ASUS supplied version.
@Jeffrey Young

Full disclosure... @SomeWhereOverTheRainBow and I do quite a bit of knowledge sharing. It doesn't look like it's clear in the original post, but I've done the same as @SomeWhereOverTheRainBow by downloading the latest version of the acme.sh script and have mounted over the Asuswrt provided version.

Then, I take it one step further by mounting the acme.sh script over the asus-wrapper-acme.sh wrapper to manipulate the parameters Asuswrt-Merlin uses in its certificate management process. Then you can issue the command service start_letsencrypt.

I hope that's clearer.

Respectfully,


Gary
 
Thanks, I appreciate the clarification.

One more question. I have downloaded the current version of acme.sh, but it will not run on the router. I have changed the sheebang to /bin/sh, but still no luck. Perhaps I am getting from the wrong location (https://github.com/acmesh-official/acme.sh/blob/master/acme.sh)
 
Never mind. I don't believe I got caught by not running a dos2unix on the installed files!
 
@garycnew - Thanks, it is running now. I usually issue a dos2unix command right off the bat. Did not this time (sidetracked by daughter wanting to get a dog). Once I woke up as to the cause and did the conversion, all was well again.
 
Thanks to the both of you (@garycnew @SomeWhereOverTheRainBow )

Took some fiddling and some script writing, but I have a ZeroSSL cert now for the Router GUI. I have my own domain through GoDaddy. Cron job as well to run nightly to see if renewal is required, and install on router as required.

Now, to turn my attention to my DC, which I am using self signed 10 year cert for Kerberos TLS now.

Thanks again
 

Latest threads

Support SNBForums w/ Amazon

If you'd like to support SNBForums, just use this link and buy anything on Amazon. Thanks!

Sign Up For SNBForums Daily Digest

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

Members online

Top