···235 # https://github.com/NixOS/nixpkgs/pull/81371#issuecomment-605526099
236 wantedBy = optionals (!config.boot.isContainer) [ "multi-user.target" ];
237238- path = with pkgs; [ lego coreutils diffutils ];
239240 serviceConfig = commonServiceConfig // {
241 Group = data.group;
···274 script = ''
275 set -euxo pipefail
2760000000000000000000000000000277 ${optionalString (data.webroot != null) ''
278 # Ensure the webroot exists
279 mkdir -p '${data.webroot}/.well-known/acme-challenge'
···288 # When domains are updated, there's no need to do a full
289 # Lego run, but it's likely renew won't work if days is too low.
290 if [ -e certificates/domainhash.txt ] && cmp -s domainhash.txt certificates/domainhash.txt; then
291- lego ${renewOpts} --days ${toString cfg.validMinDays}
00000292 else
0293 # Any number > 90 works, but this one is over 9000 ;-)
294 lego ${renewOpts} --days 9001
295 fi
···235 # https://github.com/NixOS/nixpkgs/pull/81371#issuecomment-605526099
236 wantedBy = optionals (!config.boot.isContainer) [ "multi-user.target" ];
237238+ path = with pkgs; [ lego coreutils diffutils openssl ];
239240 serviceConfig = commonServiceConfig // {
241 Group = data.group;
···274 script = ''
275 set -euxo pipefail
276277+ # This reimplements the expiration date check, but without querying
278+ # the acme server first. By doing this offline, we avoid errors
279+ # when the network or DNS are unavailable, which can happen during
280+ # nixos-rebuild switch.
281+ is_expiration_skippable() {
282+ pem=$1
283+284+ # This function relies on set -e to exit early if any of the
285+ # conditions or programs fail.
286+287+ [[ -e $pem ]]
288+289+ expiration_line="$(
290+ set -euxo pipefail
291+ openssl x509 -noout -enddate <$pem \
292+ | grep notAfter \
293+ | sed -e 's/^notAfter=//'
294+ )"
295+ [[ -n "$expiration_line" ]]
296+297+ expiration_date="$(date -d "$expiration_line" +%s)"
298+ now="$(date +%s)"
299+ expiration_s=$[expiration_date - now]
300+ expiration_days=$[expiration_s / (3600 * 24)] # rounds down
301+302+ [[ $expiration_days -gt ${toString cfg.validMinDays} ]]
303+ }
304+305 ${optionalString (data.webroot != null) ''
306 # Ensure the webroot exists
307 mkdir -p '${data.webroot}/.well-known/acme-challenge'
···316 # When domains are updated, there's no need to do a full
317 # Lego run, but it's likely renew won't work if days is too low.
318 if [ -e certificates/domainhash.txt ] && cmp -s domainhash.txt certificates/domainhash.txt; then
319+ if is_expiration_skippable out/full.pem; then
320+ echo 1>&2 "nixos-acme: skipping renewal because expiration isn't within the coming ${toString cfg.validMinDays} days"
321+ else
322+ echo 1>&2 "nixos-acme: renewing now, because certificate expires within the configured ${toString cfg.validMinDays} days"
323+ lego ${renewOpts} --days ${toString cfg.validMinDays}
324+ fi
325 else
326+ echo 1>&2 "certificate domain(s) have changed; will renew now"
327 # Any number > 90 works, but this one is over 9000 ;-)
328 lego ${renewOpts} --days 9001
329 fi