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!

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
@Jeffrey Young

Excellent to hear you've implemented a solution that meets your needs!

Hopefully, @Dabombber, @SomeWhereOverTheRainBow, and my previous adventures down the Asuswrt-Merlin acme.sh rabbit-hole have assisted you on your subsequent adventure.

I encourage you to contribute by documenting your own success with a post in the Asuswrt-Merlin forum and link to it in this post.

Great Work!

Respectfully,


Gary

P.S. I'm curious to hear how your cert transition goes with the Domain Controller. I am using Nginx on my Asuswrt-Merlin router as a loadbalancer with zerossl certs. Perhaps that better gives you an idea why I chose to have my Asuswrt-Merlin router manage my certs. Best Wishes!
 
Thanks @garycnew. Once I have some scripts more or less finalized, I will more than happy to post. The only big difference between stock acme.sh and my self is that I built my own script for the cron job (as opposed to using acme.sh --cron) as --cron only responds with 0 or 1 for exits codes whereas --renew add 2 (certs still valid, no nothing needs to be done). That makes it easier to handle the Router GUI SSL certs as they need to be copied to two locations.

The script below was also very useful is showing where the router GUI certs needed to be copied once issued.


I did get the certs issued for the DC last night after some glitchy behavior with ZeroSSL (curl for a while could not resolve url address for ZeroSSL). Once ZeroSSL got their side figured out, the certs installed and imported into the Samba DC with no issues. I used a separate install on the DC for the certs, but I do want to move the management of both certs to the router eventually.

I never did get --standalone to work as I am behind a CGNAT (my ISP has been fabulous - they are port forwarding a group of five ports from their public facing address to my CGNAT address). However, GoDaddy has an api hook in acme.sh, so I was able to use --dns mode to get the certs.
 
Thanks @garycnew. Once I have some scripts more or less finalized, I will more than happy to post. The only big difference between stock acme.sh and my self is that I built my own script for the cron job (as opposed to using acme.sh --cron) as --cron only responds with 0 or 1 for exits codes whereas --renew add 2 (certs still valid, no nothing needs to be done). That makes it easier to handle the Router GUI SSL certs as they need to be copied to two locations.
Sounds Great! I look forward to seeing your work. When you say, "the Router GUI SSL certs...need to be copied to two locations." I briefly reviewed the config-webgui.sh script and it looks like it's copying cert.pem and key.pem to /etc. Isn't /etc in memory and reset after each reboot? Are the /jffs bks copied back to /etc following each reboot? Thank you for referencing the config-webgui.sh script. It's the first time I'm seeing it.
I did get the certs issued for the DC last night after some glitchy behavior with ZeroSSL (curl for a while could not resolve url address for ZeroSSL). Once ZeroSSL got their side figured out, the certs installed and imported into the Samba DC with no issues. I used a separate install on the DC for the certs, but I do want to move the management of both certs to the router eventually.
Great Work! I'm glad you were able to sort out a zerossl cert for your domain controller. I'm sure it will be nice not having to deal with a self-signed cert moving forward. Let me know how centralizing your DC cert with your cert management goes in the future.
I never did get --standalone to work as I am behind a CGNAT (my ISP has been fabulous - they are port forwarding a group of five ports from their public facing address to my CGNAT address). However, GoDaddy has an api hook in acme.sh, so I was able to use --dns mode to get the certs.
It's probably just as well that you skipped --standalone mode in favor of --dns mode. Now, you'll be able to have SAN/Wildcard certs issues to you. I actually wrote my own acme.sh api module to interface with my local DNS implementation. It took some effort, but I like the end result.

I'm glad you were able to devise a solution that meets your needs.

Nice Work!

Respectfully,


Gary
 
Sounds Great! I look forward to seeing your work. When you say, "the Router GUI SSL certs...need to be copied to two locations." I briefly reviewed the config-webgui.sh script and it looks like it's copying cert.pem and key.pem to /etc. Isn't /etc in memory and reset after each reboot? Are the /jffs bks copied back to /etc following each reboot? Thank you for referencing the config-webgui.sh script. It's the first time I'm seeing it.

Great Work! I'm glad you were able to sort out a zerossl cert for your domain controller. I'm sure it will be nice not having to deal with a self-signed cert moving forward. Let me know how centralizing your DC cert with your cert management goes in the future.

It's probably just as well that you skipped --standalone mode in favor of --dns mode. Now, you'll be able to have SAN/Wildcard certs issues to you. I actually wrote my own acme.sh api module to interface with my local DNS implementation. It took some effort, but I like the end result.

I'm glad you were able to devise a solution that meets your needs.

Nice Work!

Respectfully,


Gary

When I was first reviewing the script, I was puzzled about how the /etc/cert.pem and /etc/key.pem play into the equation as you are right - /etc is tempfs filesystem. I came to the conclusion that Asus, during bootup, copies the cert/key into the /etc from somewhere.

In the end, I only used this code to copy the ZeroSSL cert and key into the required location to use https for the GUI;

Code:
            if [ "${d}" = "RTAC86U" ]; then
                for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
                    [ -d "$p" ] && \
                        cp /opt/home/keys/cert.pem ${p}/cert.pem && \
                        cp /opt/home/keys/key.pem ${p}/key.pem
                done
                nvram set le_enable=2    # Sets DDNS SSL Certificate in WAN/DDNS to "Import"
                nvram set https_crt_save=1
                nvram set https_crt_file=""
                service restart_httpd 1>&2 > /dev/null
                nvram commit
                echo "Finished updating Router GUI certificate stores" >> "${LOGDIR}"
            fi

Which copies the cert/key files into /jffs/ssl and /jffs/.cert as well as /etc. So, I am assuming that on bootup, the keys are copied from either /jffs/ssl or /jffs/.cert into /etc.

I don't know the difference between /jffs/ssl and /jffs/.cert. I assume one if for the GUI SSL and the other is for DDNS?? As it is only an assumption, I played it safe and copied to both. I don't use DDNS due to my CGNAT issue, so it does not hurt anything for me to copy to both.

Here is my final cert renewal script that runs at 0020 hours daily




Code:
#!/bin/sh
# Command line variables
#
#    $1 = force - will force certificate renewals


SCRIPTNAME="ACME Renew"
LOGDIR="/opt/var/log/acme.log"

# 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=""

rm /tmp/cert-renewal.txt

for d in "RTAC86U.YOUNGIND.CA" "YOUNGIND.CA"; do

    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 ${d} >> /tmp/cert-renewal.txt

    RST="$?"

    echo "$(date) - Acme.sh Return code is ${RST}"

    case "${RST}" in
        0)
            logger -t "${SCRIPTNAME}" "Certificate ${d} Renewed .... Restarting httpd"
            echo "$(date) - ACHE.SH" "Certificate ${d} Renewed .... Restarting httpd" >> "${LOGDIR}"
            if [ "${d}" = "RTAC86U" ]; then
                for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
                    [ -d "$p" ] && \
                        cp /opt/home/keys/cert.pem ${p}/cert.pem && \
                        cp /opt/home/keys/key.pem ${p}/key.pem
                done
                nvram set le_enable=2    # Sets DDNS SSL Certificate in WAN/DDNS to "Import"
                nvram set https_crt_save=1
                nvram set https_crt_file=""
                service restart_httpd 1>&2 > /dev/null
                nvram commit
                echo "Finished updating Router GUI certificate stores" >> "${LOGDIR}"
            fi
            echo  "$(date) - ${d} SSL Certificate has been renewed" >> "${LOGDIR}"
       
            echo "$(date)" > /tmp/certmail.txt
            echo "" >> /tmp/certmail
            echo "Acme SSL Security Certificate Renewal System Message" >> /tmp/certmail.txt
            echo "INFORMATION - Certificate ${d} has been renewed" >> /tmp/certmail.txt
            /jffs/addons/young/smail.sh "/tmp/certmail.txt" "INFO - SSL Cert ${d} has been renewed"      
        ;;
        1)
            logger -t "${SCRIPTNAME}" "${d} Certificate Renewal Failed"
            echo "$(date) - Certificate Renewal Failed for certificate ${d}" >> "${LOGDIR}"
       
            echo "$(date)" > /tmp/certmail.txt
            echo "" >> /tmp/certmail
            echo "Acme SSL Security Certificate Renewal System Message" >> /tmp/certmail.txt
            echo "WARNING - Failed to renew the SSL Certificate ${d}" >> /tmp/certmail.txt
            /jffs/addons/young/smail.sh "/tmp/certmail.txt" "WARNING - Router SSL Cert ${d} Renewal Failed"
        ;;
        2)
            logger -t "${SCRIPTNAME}" "Certificate ${d} is still valid, nothing done"
            echo "$(date) - Certificate Renewal request done - certificate ${d} still valied, nothing done" >> "${LOGDIR}"
        ;;
    esac
done
 
The script I use to issue the certificate for the router (ACRT86U.YOUNGIND.CA). I have my own domain from GoDaddy;

Code:
#!/bin/sh

# Version: 1.00
# Date: January 11, 2022

KEYDIR="/opt/home/keys"
export GD_Key="GoDaddy API Key"
export GD_Secret="GoDaddy API Secret"

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 \
    --issue \
    --domain RTAC86U.YOUNGIND.CA \
    --useragent "YoungIndustries" \
    --cert-file ${KEYDIR}/cert.pem \
    --key-file ${KEYDIR}/key.pem \
    --ca-file ${KEYDIR}/ca.pem \
    --fullchain-file ${KEYDIR}/fullchain.pem \   
    --dns dns_gd


# 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)

if [ $? = 0 ]; then   
    for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
        [ -d "$p" ] && \
            cp /opt/home/keys/cert.pem ${p}/cert.pem && \
            cp /opt/home/keys/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
 
When I was first reviewing the script, I was puzzled about how the /etc/cert.pem and /etc/key.pem play into the equation as you are right - /etc is tempfs filesystem. I came to the conclusion that Asus, during bootup, copies the cert/key into the /etc from somewhere.

In the end, I only used this code to copy the ZeroSSL cert and key into the required location to use https for the GUI;

Code:
            if [ "${d}" = "RTAC86U" ]; then
                for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
                    [ -d "$p" ] && \
                        cp /opt/home/keys/cert.pem ${p}/cert.pem && \
                        cp /opt/home/keys/key.pem ${p}/key.pem
                done
                nvram set le_enable=2    # Sets DDNS SSL Certificate in WAN/DDNS to "Import"
                nvram set https_crt_save=1
                nvram set https_crt_file=""
                service restart_httpd 1>&2 > /dev/null
                nvram commit
                echo "Finished updating Router GUI certificate stores" >> "${LOGDIR}"
            fi

Which copies the cert/key files into /jffs/ssl and /jffs/.cert as well as /etc. So, I am assuming that on bootup, the keys are copied from either /jffs/ssl or /jffs/.cert into /etc.

I don't know the difference between /jffs/ssl and /jffs/.cert. I assume one if for the GUI SSL and the other is for DDNS?? As it is only an assumption, I played it safe and copied to both. I don't use DDNS due to my CGNAT issue, so it does not hurt anything for me to copy to both.

Here is my final cert renewal script that runs at 0020 hours daily




Code:
#!/bin/sh
# Command line variables
#
#    $1 = force - will force certificate renewals


SCRIPTNAME="ACME Renew"
LOGDIR="/opt/var/log/acme.log"

# 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=""

rm /tmp/cert-renewal.txt

for d in "RTAC86U.YOUNGIND.CA" "YOUNGIND.CA"; do

    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 ${d} >> /tmp/cert-renewal.txt

    RST="$?"

    echo "$(date) - Acme.sh Return code is ${RST}"

    case "${RST}" in
        0)
            logger -t "${SCRIPTNAME}" "Certificate ${d} Renewed .... Restarting httpd"
            echo "$(date) - ACHE.SH" "Certificate ${d} Renewed .... Restarting httpd" >> "${LOGDIR}"
            if [ "${d}" = "RTAC86U" ]; then
                for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
                    [ -d "$p" ] && \
                        cp /opt/home/keys/cert.pem ${p}/cert.pem && \
                        cp /opt/home/keys/key.pem ${p}/key.pem
                done
                nvram set le_enable=2    # Sets DDNS SSL Certificate in WAN/DDNS to "Import"
                nvram set https_crt_save=1
                nvram set https_crt_file=""
                service restart_httpd 1>&2 > /dev/null
                nvram commit
                echo "Finished updating Router GUI certificate stores" >> "${LOGDIR}"
            fi
            echo  "$(date) - ${d} SSL Certificate has been renewed" >> "${LOGDIR}"
      
            echo "$(date)" > /tmp/certmail.txt
            echo "" >> /tmp/certmail
            echo "Acme SSL Security Certificate Renewal System Message" >> /tmp/certmail.txt
            echo "INFORMATION - Certificate ${d} has been renewed" >> /tmp/certmail.txt
            /jffs/addons/young/smail.sh "/tmp/certmail.txt" "INFO - SSL Cert ${d} has been renewed"     
        ;;
        1)
            logger -t "${SCRIPTNAME}" "${d} Certificate Renewal Failed"
            echo "$(date) - Certificate Renewal Failed for certificate ${d}" >> "${LOGDIR}"
      
            echo "$(date)" > /tmp/certmail.txt
            echo "" >> /tmp/certmail
            echo "Acme SSL Security Certificate Renewal System Message" >> /tmp/certmail.txt
            echo "WARNING - Failed to renew the SSL Certificate ${d}" >> /tmp/certmail.txt
            /jffs/addons/young/smail.sh "/tmp/certmail.txt" "WARNING - Router SSL Cert ${d} Renewal Failed"
        ;;
        2)
            logger -t "${SCRIPTNAME}" "Certificate ${d} is still valid, nothing done"
            echo "$(date) - Certificate Renewal request done - certificate ${d} still valied, nothing done" >> "${LOGDIR}"
        ;;
    esac
done
awesome!. Mine is a little more complex because I have several SANS incorporated and I also set two different types of certs as well.
 
The script I use to issue the certificate for the router (ACRT86U.YOUNGIND.CA). I have my own domain from GoDaddy;

Code:
#!/bin/sh

# Version: 1.00
# Date: January 11, 2022

KEYDIR="/opt/home/keys"
export GD_Key="GoDaddy API Key"
export GD_Secret="GoDaddy API Secret"

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 \
    --issue \
    --domain RTAC86U.YOUNGIND.CA \
    --useragent "YoungIndustries" \
    --cert-file ${KEYDIR}/cert.pem \
    --key-file ${KEYDIR}/key.pem \
    --ca-file ${KEYDIR}/ca.pem \
    --fullchain-file ${KEYDIR}/fullchain.pem \  
    --dns dns_gd


# 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)

if [ $? = 0 ]; then  
    for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
        [ -d "$p" ] && \
            cp /opt/home/keys/cert.pem ${p}/cert.pem && \
            cp /opt/home/keys/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
One question, What is your purpose for a directory "/jffs/ssl"
 
When I was first reviewing the script, I was puzzled about how the /etc/cert.pem and /etc/key.pem play into the equation as you are right - /etc is tempfs filesystem. I came to the conclusion that Asus, during bootup, copies the cert/key into the /etc from somewhere.
Most of the programmable variables are typically saved in nvram (including ssh keys). I'm surprised that the same isn't done with ssl certs.
In the end, I only used this code to copy the ZeroSSL cert and key into the required location to use https for the GUI;


Code:
            if [ "${d}" = "RTAC86U" ]; then
                for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
                    [ -d "$p" ] && \
                        cp /opt/home/keys/cert.pem ${p}/cert.pem && \
                        cp /opt/home/keys/key.pem ${p}/key.pem
                done
                nvram set le_enable=2    # Sets DDNS SSL Certificate in WAN/DDNS to "Import"
                nvram set https_crt_save=1
                nvram set https_crt_file=""
                service restart_httpd 1>&2 > /dev/null
                nvram commit
                echo "Finished updating Router GUI certificate stores" >> "${LOGDIR}"
            fi

Which copies the cert/key files into /jffs/ssl and /jffs/.cert as well as /etc. So, I am assuming that on bootup, the keys are copied from either /jffs/ssl or /jffs/.cert into /etc.
Excellent script! Setting of the nvram variables and restarting the httpd service is lacking in my script. I was more focused on having certs issues for my Nginx loadbalancer implementation on the router vs the router GUI itself. I'll have to include that functionality in my asus-wrapper-acme.sh script.
I don't know the difference between /jffs/ssl and /jffs/.cert. I assume one if for the GUI SSL and the other is for DDNS?? As it is only an assumption, I played it safe and copied to both. I don't use DDNS due to my CGNAT issue, so it does not hurt anything for me to copy to both.
I agree with your conclusion regarding the ssl and cert paths. However, it would be nice to understand the process better for completeness. Perhaps someone reading this post may know?

BTW... It sounds painful being stuck behind CGNAT. Fiber to the premises with a static or even a dynamic address is the only way to go.
Here is my final cert renewal script that runs at 0020 hours daily

Code:
#!/bin/sh
# Command line variables
#
#    $1 = force - will force certificate renewals

SCRIPTNAME="ACME Renew"
LOGDIR="/opt/var/log/acme.log"

# 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=""

rm /tmp/cert-renewal.txt

for d in "RTAC86U.YOUNGIND.CA" "YOUNGIND.CA"; do

    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 ${d} >> /tmp/cert-renewal.txt

    RST="$?"

    echo "$(date) - Acme.sh Return code is ${RST}"

    case "${RST}" in
        0)
            logger -t "${SCRIPTNAME}" "Certificate ${d} Renewed .... Restarting httpd"
            echo "$(date) - ACHE.SH" "Certificate ${d} Renewed .... Restarting httpd" >> "${LOGDIR}"
            if [ "${d}" = "RTAC86U" ]; then
                for p in "/jffs/ssl" "/jffs/.cert" "/etc"; do
                    [ -d "$p" ] && \
                        cp /opt/home/keys/cert.pem ${p}/cert.pem && \
                        cp /opt/home/keys/key.pem ${p}/key.pem
                done
                nvram set le_enable=2    # Sets DDNS SSL Certificate in WAN/DDNS to "Import"
                nvram set https_crt_save=1
                nvram set https_crt_file=""
                service restart_httpd 1>&2 > /dev/null
                nvram commit
                echo "Finished updating Router GUI certificate stores" >> "${LOGDIR}"
            fi
            echo  "$(date) - ${d} SSL Certificate has been renewed" >> "${LOGDIR}"
   
            echo "$(date)" > /tmp/certmail.txt
            echo "" >> /tmp/certmail
            echo "Acme SSL Security Certificate Renewal System Message" >> /tmp/certmail.txt
            echo "INFORMATION - Certificate ${d} has been renewed" >> /tmp/certmail.txt
            /jffs/addons/young/smail.sh "/tmp/certmail.txt" "INFO - SSL Cert ${d} has been renewed"  
        ;;
        1)
            logger -t "${SCRIPTNAME}" "${d} Certificate Renewal Failed"
            echo "$(date) - Certificate Renewal Failed for certificate ${d}" >> "${LOGDIR}"
   
            echo "$(date)" > /tmp/certmail.txt
            echo "" >> /tmp/certmail
            echo "Acme SSL Security Certificate Renewal System Message" >> /tmp/certmail.txt
            echo "WARNING - Failed to renew the SSL Certificate ${d}" >> /tmp/certmail.txt
            /jffs/addons/young/smail.sh "/tmp/certmail.txt" "WARNING - Router SSL Cert ${d} Renewal Failed"
        ;;
        2)
            logger -t "${SCRIPTNAME}" "Certificate ${d} is still valid, nothing done"
            echo "$(date) - Certificate Renewal request done - certificate ${d} still valied, nothing done" >> "${LOGDIR}"
        ;;
    esac
done
I like your added renewal check, logging, mail notification, and previously mentioned nvram functionality. Where our implementations start to diverge is your use of cron and my use of service restart_letsencrypt, which performs a cert check twice a day. Your deployment seems to focus on a single cert/key pair; while, mine necessitates the issuance and renewal of multiple cert/key pairs for several domains. However, they both get the job done.

I appreciate you sharing your knowledge and helping to improve my process.

Keep up the Great Work!

Respectfully,


Gary
 
awesome!. Mine is a little more complex because I have several SANS incorporated and I also set two different types of certs as well.
@SomeWhereOverTheRainBow

Why not just have SAN/Wildcard certs issued for SUBJECT: *.domain.tld SUBJECT ALTERNATIVE NAME: domain.tld and call it a day? It's my preferred cert management route of choice.

Respectfully,


Gary
 
One question, What is your purpose for a directory "/jffs/ssl"

I don't really know. The code section is from the original webgui-config script I quoted above. The script puts the pixelserv cert into the two locations. I never investigated way both locations. Perhaps one location is for the gui and one for ddns?? To stay on the safe side, I kept the snippet as is.
 
Most of the programmable variables are typically saved in nvram (including ssh keys). I'm surprised that the same isn't done with ssl certs.

Excellent script! Setting of the nvram variables and restarting the httpd service is lacking in my script. I was more focused on having certs issues for my Nginx loadbalancer implementation on the router vs the router GUI itself. I'll have to include that functionality in my asus-wrapper-acme.sh script.

I agree with your conclusion regarding the ssl and cert paths. However, it would be nice to understand the process better for completeness. Perhaps someone reading this post may know?

BTW... It sounds painful being stuck behind CGNAT. Fiber to the premises with a static or even a dynamic address is the only way to go.

I like your added renewal check, logging, mail notification, and previously mentioned nvram functionality. Where our implementations start to diverge is your use of cron and my use of service restart_letsencrypt, which performs a cert check twice a day. Your deployment seems to focus on a single cert/key pair; while, mine necessitates the issuance and renewal of multiple cert/key pairs for several domains. However, they both get the job done.

I appreciate you sharing your knowledge and helping to improve my process.

Keep up the Great Work!

Respectfully,


Gary

If you have multiple certs to check for renewal, change the --renew to --renew-all and don't specify a domain name. I actually have two certs on the router and was calling two renewal scripts until I realized the --renew-all option. I have since modified the script.

Keeping a certificate in nvram would use a lot of precious nvram space. I can see why jffs was used.
 
@SomeWhereOverTheRainBow

Why not just have SAN/Wildcard certs issued for SUBJECT: *.domain.tld SUBJECT ALTERNATIVE NAME: domain.tld and call it a day? It's my preferred cert management route of choice.

Respectfully,


Gary

I personally don't care for wildcard certs. In the right hands, they can be used against you by a hacker.
 
If you have multiple certs to check for renewal, change the --renew to --renew-all and don't specify a domain name. I actually have two certs on the router and was calling two renewal scripts until I realized the --renew-all option. I have since modified the script.
Good to know. I'll have to give it a try.
Keeping a certificate in nvram would use a lot of precious nvram space. I can see why jffs was used.
I agree with your logic, but then why are ssh keys kept in nvram? Another product of agile development?
 
I personally don't care for wildcard certs. In the right hands, they can be used against you by a hacker.
This is a classic case of security vs usability and precisely why many certificate authorities are adopting a shortened cert lifecycle. Each to their own.
 
I don't really know. The code section is from the original webgui-config script I quoted above. The script puts the pixelserv cert into the two locations. I never investigated way both locations. Perhaps one location is for the gui and one for ddns?? To stay on the safe side, I kept the snippet as is.
@Jeffrey Young & @SomeWhereOverTheRainBow

I performed a manual import of a zerossl san/wildcard cert.pem & key.pem pair through the Asuswrt-Merlin webgui; while, watching the previously mentioned relevant nvram variables. The imported cert.pem & key.pem were copied by the webgui to the /jffs/.cert directory and the nvram variables were modified to the expected values.

Additionally, I have ddns enabled using a custom address check script for a purchased domain. Only the /jffs/.cert directory has been modified.

I continue not to have a /jffs/ssl directory, which I'm starting to believe isn't used by Asuswrt-Merlin.

Next is to modify my script to automate that functionality. I still need to experiment with the acme.sh --renew-all option.

BTW... I had to add the commands to make zerossl the default certificate authority and generate a valid zerossl key to the top of my script to ensure they're set after a reboot of the router.
 
Last edited:
@Jeffrey Young & @SomeWhereOverTheRainBow

I performed a manual import of a zerossl san/wildcard cert.pem & key.pem pair through the Asuswrt-Merlin webgui; while, watching the previously mentioned relevant nvram variables. The imported cert.pem & key.pem were copied by the webgui to the /jffs/.cert directory and the nvram variables were modified to the expected values.

Additionally, I have ddns enabled using a custom address check script for a purchased domain. Only the /jffs/.cert directory has been modified.

I continue not to have a /jffs/ssl directory, which I'm starting to believe isn't used by Asuswrt-Merlin.
The only thing I could think it would be used for is if it is needed for a customary TLS application on the router. (something that was added that you have the option of enabling TLS for.) If that was the case though, I don't know why we wouldn't just use the ones in .cert directory then.
 
@Jeffrey Young & @SomeWhereOverTheRainBow

I performed a manual import of a zerossl san/wildcard cert.pem & key.pem pair through the Asuswrt-Merlin webgui; while, watching the previously mentioned relevant nvram variables. The imported cert.pem & key.pem were copied by the webgui to the /jffs/.cert directory and the nvram variables were modified to the expected values.

Additionally, I have ddns enabled using a custom address check script for a purchased domain. Only the /jffs/.cert directory has been modified.

I continue not to have a /jffs/ssl directory, which I'm starting to believe isn't used by Asuswrt-Merlin.

Super good info to know. This will let me drop the one directory path from the script and just copy the pem files to /jffs/.cert directory (and to the /etc directory to make the change immediate). I am wondering if the author was coping to the /jffs/ssl directory as a means of backup?? Just speculation.
 
Another pleasant surprise I found with acme.sh is that a any of the parameters that you specified when doing an initial --issue, such as --cert-file <file>, --key-file <file> , and --reloadcmd <command> are all stored in the account config file (./.acme/<domain>/<domain.conf> and is reused for each domain certificate issued when you use ./acme.sh --renew-all

My original script is getting shorter and shorter :)

EDIT: --install was meant to be --issue
 
Another pleasant surprise I found with acme.sh is that a any of the parameters that you specified when doing an initial --issue, such as --cert-file <file>, --key-file <file> , and --reloadcmd <command> are all stored in the account config file (./.acme/<domain>/<domain.conf> and is reused when you use ./acme.sh --renew-all

My original script is getting shorter and shorter :)

EDIT: --install was meant to be --issue
I like to be verbose with my command-line arguments, so when I revisit them in the future I still know what's going on. This post being a case in point. :)
 
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