Page 1 of 1

Auto-Renew Lets Encrypt Certificate Problem

Posted: Thu Jul 04, 2024 2:08 am
by ColinSlater
Hi,
Got a really odd problem. I have 2x RB4011 (one at my home, one at the scout campsite) both of which have the same script on them to automatically renew the Let's Encrypt SSL Certificate that is used for SSTP VPN. I say they're the same, on the campsite we have a hotspot wifi system, so there's part of the script here that sets the new certificate for the hotspot, but that's the only difference.

Here's the script (with the DNS name commented out as [xxx] for privacy of course):
:log info "Script - Certificate renewal start"

:local commName "[xxx]"

/ip service set disabled=no [find where name="www"]
/ip firewall filter enable [find where comment="LetsEncrypt"]

#Delete old certificate, create new certificate
/certificate remove [find where common-name=$commName]
/certificate enable-ssl-certificate dns=$commName

#Delay to allow certificate to be requested and downloaded
:delay 60s

/certificate
:local certName [get [find where common-name=$commName] name]

#Set new certificate in SSTP Profile
/interface sstp-server server set certificate=$certName

#Set new certificate in Hotspot profile
/ip hotspot profile set ssl-certificate=$certName [find where name="Hotspot"]

/ip service set disabled=yes [find where name="www"]
/ip firewall filter disable [find where comment="LetsEncrypt"]
Here's the scheduler config:
/system scheduler add interval=10w5d name=letsencrypt-renew on-event=letsencrypt-renew policy=read,write start-date=2023-08-28 start-time=09:00:00
Both boxes are running ROS 7.14 at the moment.
--> so, I don't think it's the ROS version (otherwise, I would have expected that it wouldn't work anywhere)

My RB4011 at home, everything just runs fine - the certificate renews every 75 days and the new certificate is applied.
The other box, doesn't seem to work, but when I run the script manually, works as expected.
--> so I don't think it's the script, otherwise I would have expected that it doesn't work when I run manually.

My thought at the moment is something to do with scheduler... but the scheduler config on both boxes are identical (apart from the start date when the scheduler was setup).

Is there any logging or anything like this that we could apply so that we can maybe see some errors here? I've got "Script" as a topic in my logging enabled, but I can't see anything that looks like Scheduler in there to add this in to the logging.

Anyone got any ideas to any of this at all?

Thanks very much.

Colin

Re: Auto-Renew Lets Encrypt Certificate Problem

Posted: Fri Aug 02, 2024 5:03 pm
by itallko2010
Hi Collin,

For automatic LetsEncrypt certificate on RouterOS you can use this script in scheduler for run daily. I also use this free certificate service for SSTP VPN, HotSpot and www-ssl access to my home router.

****** SCRIPT BELLOW ******
######## LETSENCRYPT AUTOUPDATE SCRIPT v1.5  by L Hajek 08/2024 ###########

##############################################
######## ENV VARIABLES EXPLAIN ########
#
# DAYS - Type out days for renewall before certificate expire
# MAILTO - Email recipient about status of renewall
# ERRSUBJECT - Renewall failure email subject
# OKSUBJECT - Renewall success email subject
# DNSNAME - Certificate DNS names
# COMMONNAME - Certificate Common Name
# CERTNAME, NEWVALUE - Certificate name on RouterOS (required for find certificate !)
# LOGNAME - Log purposes prefix
# SVCALLOW - WWW service allowed from
#
# For success renewall must be port 80 open from anywhere
# internet (ex. I use rule with name LETSENCRYPT for temporary
# usage in renewall process. Also I use restricted service www
# and this will be also temporary open from anywhere when is 
# renewall script running)
##############################################

### VARIABLES
:local days 20d;
:local mailto "recipient@domain.com";
:local errsubject "LE Certificate Renewall FAILED";
:local oksubject "LE Certificate Renewall SUCCESS";
:local dnsName "mainhost.domain.tld,host1.domain.tld,host2.domain.tld"
:local commonName "mainhost.domain.tld"
:local certname "letsencrypt-cert"
:local logname "LETSENCRYPT"
:local svcallow "192.168.64.0/21,127.0.0.1"

### CHECK
/certificate
:foreach item in=[find where common-name=mainhost.domain.tld] do={
    :if (([get $item expires-after] < $days) and ![get $item expired]) do={
		:log info "$logname - Opening Ports Firewall"
		/ip firewall/filter/enable [find comment=LETSENCRYPT]
		/ip service/set www address=""
		:delay 5s
		:log info "$logname - Starting Certificate Renewall"
		:set $newvalue [/certificate enable-ssl-certificate dns-name=$dnsName as-value]
		:delay 40s
		:log info "$logname - Stop Certificate Update Process"
		:log info "$logname - Certificate Update Status: $[:tostr $newvalue]"
		/ip service/set www address="$svcallow"
		/ip firewall/filter/disable [find comment=LETSENCRYPT]
	:if ([:typeof [:find [:tostr $newvalue] "[error]"]]="nil") do={
#		/certificate/remove [find where name~"letsencry*"]
		/certificate/remove [find where name="$certname"]
		:delay 2s
		/certificate/set [find where name~"autogen*"] name=$certname
		:delay 2s
		/interface/sstp-server/server/set certificate=$certname
		/ip/hotspot/profile/set hsprof1 ssl-certificate=$certname
		/ip service/set api-ssl certificate=$certname
		/ip service/set www-ssl certificate=$certname
		:delay 2s
		:log info "$logname - Certificate Renewall SUCCESS"
		/tool e-mail send to="$mailto" subject=([/system identity get name]. ".   $oksubject. ") body=$newvalue;
	} else={
		:log error "$logname - Certificate Renewall FAIL"
		/tool e-mail send to="$mailto" subject=([/system identity get name]. ".   $errsubject. ") body=$newvalue;
			}
	} else={
		:log info "$logname - Certificate Valid - NOTHING TO DO"
		}
}
		:log info "$logname - Certificate Renewall End"


***************
EXPLAIN:

LE service requirements:
- common name and aditional DNS names in certificate request must be resolvable by DNS and must by pointed to router public IP address where the request initiated from
- TCP 80 access to router from internet in renewall process
- other policyes, eg failed requests (5 per hour), DNS names in certificate request, certificate requests per week/month - read on LE web site policy page

SCRIPT requieremets explained in top section of script.

SCRIPT how it work:
After starting, the script will check how many days are left on the LE certificate (variable newvalue - the name of the certificate in the RouterOS/Mikrotik certificate store) until the certificate expires (variable DAYS). If there is more left until the expiration than is set in the DAYS variable, nothing is done and the script only writes in the log that nothing is needed. If the expiration is less than the value of DAYS, the recovery process is started, which in both cases (SUCCESS/FAIL) reports the status in the log and at the same time sends information to an email with the result in the subject of the email. The FAIL message is written in red in the log. In the event of a successful certificate renewal, temporarily permitted access to TCP80 will be disabled for the purpose of renewal and the permitted source ip will be set on the WWW service (can be modified as desired, or excluded from the script and solved only by rules in the firewall). During generation, the certificate is written with the content of the phrase "autogen", because there is also a time stamp and I want the name to always be the same, so the script deletes the old LE certificate and names the new one with the name of the old one, plus in my case it sets it to the necessary services (for me, hotspot , sstp vpn and www-ssl). I hope I can help.

regards
Ladislav