This is the script that I needed to quickly adapt for add-acme (as previously my script used enable-ssl-certificate) once I've found out that the upgrade to 7.22 tried to "upgrade" the old certificate and failed every time, although the old cert is still valid for 1.5 months (I had a few posts about that in the 7.22rc thread).
While the add-acme process is ongoing, the field acme-status of the certificate quickly goes through a bunch of "steps". I tried to catch all of them to classify them as part of the "pending" state but probably missed many, so now my waiting loop breaks on some words that appears in success or error message only, as well as a hard wait limit of 100 seconds.
:local domainName "xxx.yyy.zzz";
:local fwComment "allow Let's Encrypt";
:local updateWWW true;
:local updateAPI true;
:local updateSSTP true;
:local updateUM true;
:local exportCertPath "docker/config/unbound/acme-exp";
:local exportCertPass "abcd1234";
:local leCertName ($domainName . "@" . [:tonum [:timestamp]]);
:local directoryUrl "https://acme-v02.api.letsencrypt.org/directory";
:local successStatus "next update at";
:log info "Requesting LE certificate renewal for $domainName..."
# temporarily open port 80 on the firewall and enable WWW service
/ipv6 firewall filter enable [find where comment=$fwComment];
/ip service enable [find name="www" !dynamic];
/certificate add-acme domain-names=$domainName name=$leCertName directory-url=$directoryUrl as-value;
:local leCertId [/certificate find name=$leCertName];
:local loopCount 0;
:do {
:delay 5;
:local currentStatus [/certificate get $leCertId acme-status];
if ($currentStatus ~ $successStatus) do={ :break; };
if ([:find $currentStatus "failed"] >= 0) do={ :break; };
if ([:find $currentStatus "error"] >= 0) do={ :break; };
if ([:find $currentStatus "too many"] >= 0) do={ :break; };
:log info $currentStatus;
:set loopCount ($loopCount + 1);
} while ($loopCount <= 20);
# close port 80 on the firewall and disable WWW service
/ip service disable [find name="www" !dynamic];
/ipv6 firewall filter disable [find where comment=$fwComment];
:if ([/certificate get $leCertId acme-status] ~ $successStatus) do={
:log warning "LE certificate renewed for $domainName as $leCertName!";
:local certFingerprint [/certificate get $leCertId fingerprint];
:if ($updateWWW) do={
:log info "Updating WWW-SSL to use \"$leCertName\"...";
/ip service set [find name="www-ssl" !dynamic] certificate=none;
/ip service set [find name="www-ssl" !dynamic] certificate=$leCertName;
};
:if ($updateAPI) do={
:log info "Updating API-SSL to use \"$leCertName\"...";
/ip service set [find name="api-ssl" !dynamic] certificate=none;
/ip service set [find name="api-ssl" !dynamic] certificate=$leCertName;
};
:if ($updateSSTP) do={
:log info "Updating SSTP to use \"$leCertName\"...";
/interface sstp-server server set certificate=none;
/interface sstp-server server set certificate=$leCertName;
};
:if ($updateUM) do={
:log info "Updating User Manager to use \"$leCertName\"...";
/user-manager set certificate=none;
/user-manager set certificate=$leCertName;
};
:if ($exportCertPath != "") do={
:log info "Exporting certificate to \"$exportCertPath\"...";
/certificate export-certificate $leCertName type=pem export-passphrase=$exportCertPass file-name=$exportCertPath;
};
# find old certificates to remove
:foreach leOldCert in=[/certificate find acme-managed name!=$leCertName fingerprint!=$certFingerprint domain-names=$domainName] do={
:local leOldCertName [/certificate get $leOldCert name];
:local eaf [/certificate get $leOldCert expires-after];
:log warning "Removing old certificate $leOldCertName with EA $eaf...";
/certificate remove $leOldCert;
};
} else={
:log warning "LE certificate for $domainName NOT renewed!";
};
My firewall rule that opens the port 80 has the comment set to the one in the 2nd variable. Also, my script only opens the IPv6 firewall port, not the IPv4 firewall.