I tend to automate what I can, because my local biological memory gets jumbled without clear weekly instructions.
I also tend to get more and more stubborn - or, as I prefer to call it, persistent - when a problem seems particularly hard to solve.
It usually ends in unreasonably deep dives. At some point, I stop calling it a deep dive and start calling it scuba diving.
Yet, reasonably often, the scuba diving ends with me solving my own problems through some form of automation - most likely in ways the original programmers never intended. My problem is solved, though, and I can sleep again.
This is merely the latest of such pro... no - issues I have dealt with. The solution is highly controversial, clearly not what anyone intended - but my problem is solved.
Ugly_Reload is a Synology DSM acme.sh ReloadCmd for replacing existing certificates without restarting WebStation after every deployment.
My DSM currently has four certificates, and I force-renew all four once a week. That schedule reliably exposed the problem.
A WebStation restart takes roughly two minutes from start to finish. All four certificates, on the other hand, complete their forced renewal cycle in about 1 minute and 46 seconds.
That means the entire certificate batch can finish before the first WebStation restart has even completed.
The normal synology_dsm path therefore starts subsequent certificate deployments while an earlier WebStation restart may still be in progress.
In my present configuration I could actually live with that behaviour. The certificate itself is still deployed successfully even if the following WebStation restart fails, and the deployment is still treated as successful.
The certificates also happen to become active.
But that is timing, not design.
With my current four-certificate batch, the following certificates happen to be installed before the WebStation restart already in progress reaches the point where it loads the updated configuration.
Change the timing, the number of certificates or the duration of the restart, and that convenient accident can disappear.
Ugly_Reload avoids creating the race condition in the first place.
It replaces the existing DSM certificate through the certificate API with:
restart_httpd=false
The certificate gets replaced. WebStation gets left alone.
The ugly part is not really what it does.
The ugly part is what it has to do to get there.
Ugly_Reload is deliberately not a replacement for the normal synology_dsm deploy hook.
The normal hook is still used to establish the initial Synology context. Ugly_Reload only takes over once that working context exists.
Copy ugly_reload.sh to a location that will remain available to acme.sh and make it executable.
For each certificate that should use Ugly_Reload, the normal operator flow is:
acme.sh --install-cert -d example.com --ecc \
--reloadcmd '/path/to/ugly_reload.sh'
acme.sh --deploy -d example.com --ecc \
--deploy-hook synology_dsm
acme.sh --renew -d example.com --force --eccThe first command persists Ugly_Reload as the certificate's ReloadCmd.
The second command performs a normal synology_dsm deployment and establishes the Synology context Ugly_Reload needs.
On the first forced renewal, Ugly_Reload finds that context, removes only synology_dsm from the persisted Le_DeployHook for future renewals and returns success without importing the certificate itself.
The currently running acme.sh process will still dispatch the deploy hook, because that configuration was already loaded before ReloadCmd ran. That is intentional.
From the next invocation onward, the certificate uses Ugly_Reload without the normal synology_dsm deploy hook.
In my current setup, the first three certificates in the weekly batch use Ugly_Reload.
The final certificate still uses the normal synology_dsm deploy hook.
That leaves exactly one WebStation restart per batch - or, functionally in this context, one configuration reload - after the preceding certificates have already been installed.
Once the initial Synology context has been established, that configuration reload is effectively the only meaningful extra operation the normal synology_dsm path performs compared with Ugly_Reload.
The first three certificates are already in place without restarting WebStation. The final certificate then goes through the normal hook and triggers the single WebStation restart that reloads the completed configuration.
Instead of relying on favourable timing between several overlapping WebStation restarts, the batch now has one deliberate restart at the end.
The race condition is simply never created.
The only real prerequisite for this to work reliably is that the expensive operation comes last in the batch.
In my case, that means Ugly_Reload handles the first three certificates, while the final certificate retains the normal synology_dsm path.
The current implementation was written for my setup.
When the Synology context exists and synology_dsm is still persisted, Ugly_Reload removes only synology_dsm from the persisted Le_DeployHook entry and returns control to acme.sh.
Le_DeployHook can contain more than one deploy hook.
Ugly_Reload now selectively removes only synology_dsm and preserves any other configured deploy hooks.
If your certificate uses additional deploy hooks, they remain configured for future invocations.
The SYNO_* configuration consumed by Ugly_Reload belongs specifically to the existing synology_dsm deployment context. It is not a generic acme.sh interface.
Ugly_Reload is written for Synology DSM and its BusyBox environment.
The conservative POSIX-style shell code is intentional.
It expects the DSM acme.sh installation under:
/usr/local/share/acme.sh
This is working code from my own DSM environment.
Read it before using it.
Especially read the part that modifies Le_DeployHook.
This used to deserve the name Ugly_Reload. At this point, the name is probably a misnomer.