@@ -90,6 +90,10 @@ def certificate_exists(domain: str) -> bool:
9090 return os .path .isfile (crt ) and os .path .isfile (key )
9191
9292
93+ def _renewed_marker (domain : str ) -> str :
94+ return os .path .join (LEGO_PATH , f".renewed-{ domain } " )
95+
96+
9397def _common_flags (email : str ) -> List [str ]:
9498 return [
9599 "--path" ,
@@ -153,32 +157,44 @@ def run_cert(domain: str, email: str) -> int:
153157 )
154158 return EXIT_ERROR
155159
156- existed = certificate_exists (domain )
160+ # Let lego decide whether a renewal is due: it consults the CA's ARI
161+ # endpoint (RFC 9773) as well as the local window, and the CA can ask for
162+ # early renewal during an incident. Deciding here from notAfter would
163+ # override that.
164+ #
165+ # We only need to know whether it acted, and lego says so itself:
166+ # --deploy-hook runs "in cases where a certificate is successfully
167+ # created/renewed" and stays silent otherwise. That beats inferring it --
168+ # matching log text is not stable (4.x wrote "no renewal", 5.x writes
169+ # "Skip renewal"), and the exit code is 0 either way.
170+ marker = _renewed_marker (domain )
171+ if os .path .exists (marker ):
172+ os .remove (marker )
173+
157174 cmd = (
158175 [LEGO_BIN , "run" ]
159176 + _common_flags (email )
160177 + ["--domains" , domain ]
161178 + _challenge_flags ()
179+ + ["--deploy-hook" , f"touch { marker } " ]
162180 )
163181 renew_days = os .environ .get ("RENEW_DAYS_BEFORE" , "" )
164182 if renew_days :
165183 cmd += ["--renew-days" , renew_days ]
166184
167- print (f"{ 'Renewing' if existed else 'Obtaining' } certificate for { domain } via tls-alpn-01" )
168- code , output = _run (cmd )
185+ print (f"{ 'Renewing' if certificate_exists ( domain ) else 'Obtaining' } certificate for { domain } via tls-alpn-01" )
186+ code , _ = _run (cmd )
169187 if code != 0 :
170188 print (f"✗ lego failed for { domain } (exit code { code } )" , file = sys .stderr )
171189 return EXIT_ERROR
172190 if not certificate_exists (domain ):
173191 print (f"✗ lego reported success but no certificate for { domain } " , file = sys .stderr )
174192 return EXIT_ERROR
175193
176- # lego exits 0 whether or not it actually replaced anything, so the log line
177- # is the only signal that a renewal was skipped.
178- lowered = output .lower ()
179- if existed and ("no renewal" in lowered or "not yet due for renewal" in lowered ):
180- print ("No certificates need renewal" )
194+ if not os .path .exists (marker ):
195+ print (f"Certificate for { domain } is still current; nothing to do" )
181196 return EXIT_UNCHANGED
197+ os .remove (marker )
182198
183199 print (f"✓ Certificate ready for { domain } " )
184200 return EXIT_CHANGED
0 commit comments