From 4563c2c1b79622f4ea6db0c07d4008f1e9dd8317 Mon Sep 17 00:00:00 2001 From: Harsh Satyajit Thakur Date: Thu, 23 Jul 2026 04:03:42 +1000 Subject: [PATCH] fix: keep serving valid ACME cert when renewal fails at startup (#38554) Fix #38519 When `ENABLE_ACME` renew fails during startup (e.g. CA unreachable), `ManageSync` currently aborts even if a still-valid certificate is on disk, so HTTPS never comes up. If `CacheManagedCertificate` finds a non-expired cert, log the manage error, continue with that cert, and kick `ManageAsync` for background retries. First-time install / expired-or-missing cert still fails closed. --------- Signed-off-by: wxiaoguang Co-authored-by: wxiaoguang --- cmd/web_acme.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 512a990e02..68fd5d00d8 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -6,6 +6,7 @@ package cmd import ( "crypto/x509" "encoding/pem" + "errors" "fmt" "net" "net/http" @@ -93,10 +94,21 @@ func runACME(listenAddr string, m http.Handler) error { myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME) magic.Issuers = []certmagic.Issuer{myACME} - // this obtains certificates or renews them if necessary - err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{setting.Domain}) + // Obtain certificates or renew them if necessary. ManageSync fails closed on + // renewal errors even when a still-valid certificate is already on disk, which + // takes HTTPS down on restart (https://github.com/go-gitea/gitea/issues/38519). + // Prefer keeping the existing cert and retrying renewals asynchronously. + ctx := graceful.GetManager().ShutdownContext() + err := magic.ManageSync(ctx, []string{setting.Domain}) if err != nil { - return err + cert, cacheErr := magic.CacheManagedCertificate(ctx, setting.Domain) + if cacheErr != nil || cert.Expired() { + return errors.Join(err, cacheErr) + } + log.Error("ACME certificate manage failed; continuing with existing certificate: %v", err) + if err := magic.ManageAsync(ctx, []string{setting.Domain}); err != nil { + log.Error("Failed to start async ACME management: %v", err) + } } tlsConfig := magic.TLSConfig()