@marcel91200 / caddy Mirror · read-only / commits / d935a695
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 14:45 UTC

autohttps: Ensure CertMagic config is recreated after autohttps runs (#7510)

Francis Lavoie committed Mar 3, 2026 at 16:44 UTC d935a6956c16902623b8e8f6d1aafec4f6124f46
2 files changed +77 -6
modules/caddyhttp/autohttps.go
+21
@@ -614,6 +614,27 @@ func (app *App) createAutomationPolicies(ctx caddy.Context, internalNames, tails
614 }
615 }
616
617 + // Ensure automation policies' CertMagic configs are rebuilt when
618 + // ACME issuer templates may have been modified above (for example,
619 + // alternate ports filled in by the HTTP app). If a policy is already
620 + // provisioned, perform a lightweight rebuild of the CertMagic config
621 + // so issuers receive SetConfig with the updated templates; otherwise
622 + // run a normal Provision to initialize the policy.
623 + for i, ap := range app.tlsApp.Automation.Policies {
624 + // If the policy is already provisioned, rebuild only the CertMagic
625 + // config so issuers get SetConfig with updated templates. Otherwise
626 + // provision the policy normally (which may load modules).
627 + if ap.IsProvisioned() {
628 + if err := ap.RebuildCertMagic(app.tlsApp); err != nil {
629 + return fmt.Errorf("rebuilding certmagic config for automation policy %d: %v", i, err)
630 + }
631 + } else {
632 + if err := ap.Provision(app.tlsApp); err != nil {
633 + return fmt.Errorf("provisioning automation policy %d after auto-HTTPS defaults: %v", i, err)
634 + }
635 + }
636 + }
637 +
638 if basePolicy == nil {
639 // no base policy found; we will make one
640 basePolicy = new(caddytls.AutomationPolicy)
modules/caddytls/automation.go
+56 -6
@@ -243,22 +243,49 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
243 }
244 }
245
246 + // build certmagic.Config and attach it to the policy
247 + storage := ap.storage
248 + if storage == nil {
249 + storage = tlsApp.ctx.Storage()
250 + }
251 + cfg, err := ap.makeCertMagicConfig(tlsApp, issuers, storage)
252 + if err != nil {
253 + return err
254 + }
255 + certCacheMu.RLock()
256 + ap.magic = certmagic.New(certCache, cfg)
257 + certCacheMu.RUnlock()
258 +
259 + // give issuers a chance to see the config pointer
260 + for _, issuer := range ap.magic.Issuers {
261 + if annoying, ok := issuer.(ConfigSetter); ok {
262 + annoying.SetConfig(ap.magic)
263 + }
264 + }
265 +
266 + return nil
267 +}
268 +
269 +// makeCertMagicConfig constructs a certmagic.Config for this policy using the
270 +// provided issuers and storage. It encapsulates common logic shared between
271 +// Provision and RebuildCertMagic so we don't duplicate code.
272 +func (ap *AutomationPolicy) makeCertMagicConfig(tlsApp *TLS, issuers []certmagic.Issuer, storage certmagic.Storage) (certmagic.Config, error) {
273 + // key source
274 keyType := ap.KeyType
275 if keyType != "" {
276 var err error
277 keyType, err = caddy.NewReplacer().ReplaceOrErr(ap.KeyType, true, true)
278 if err != nil {
251 - return fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
279 + return certmagic.Config{}, fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
280 }
281 if _, ok := supportedCertKeyTypes[keyType]; !ok {
254 - return fmt.Errorf("unrecognized key type: %s", keyType)
282 + return certmagic.Config{}, fmt.Errorf("unrecognized key type: %s", keyType)
283 }
284 }
285 keySource := certmagic.StandardKeyGenerator{
286 KeyType: supportedCertKeyTypes[keyType],
287 }
288
261 - storage := ap.storage
289 if storage == nil {
290 storage = tlsApp.ctx.Storage()
291 }
@@ -277,7 +304,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
304 if noProtections {
305 if !ap.hadExplicitManagers {
306 // no managers, no explicitly-configured permission module, this is a config error
280 - return fmt.Errorf("on-demand TLS cannot be enabled without a permission module to prevent abuse; please refer to documentation for details")
307 + return certmagic.Config{}, fmt.Errorf("on-demand TLS cannot be enabled without a permission module to prevent abuse; please refer to documentation for details")
308 }
309 // allow on-demand to be enabled but only for the purpose of the Managers; issuance won't be allowed from Issuers
310 tlsApp.logger.Warn("on-demand TLS can only get certificates from the configured external manager(s) because no ask endpoint / permission module is specified")
@@ -334,7 +361,7 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
361 }
362 }
363
337 - template := certmagic.Config{
364 + cfg := certmagic.Config{
365 MustStaple: ap.MustStaple,
366 RenewalWindowRatio: ap.RenewalWindowRatio,
367 KeySource: keySource,
@@ -349,8 +376,31 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
376 Issuers: issuers,
377 Logger: tlsApp.logger,
378 }
379 +
380 + return cfg, nil
381 +}
382 +
383 +// IsProvisioned reports whether the automation policy has been
384 +// provisioned. A provisioned policy has an initialized CertMagic
385 +// instance (i.e. ap.magic != nil).
386 +func (ap *AutomationPolicy) IsProvisioned() bool { return ap.magic != nil }
387 +
388 +// RebuildCertMagic rebuilds the policy's CertMagic configuration from the
389 +// policy's already-populated fields (Issuers, Managers, storage, etc.) and
390 +// replaces the internal CertMagic instance. This is a lightweight
391 +// alternative to calling Provision because it does not re-provision
392 +// modules or re-run module Provision; instead, it constructs a new
393 +// certmagic.Config and calls SetConfig on issuers so they receive updated
394 +// templates (for example, alternate HTTP/TLS ports supplied by the HTTP
395 +// app). RebuildCertMagic should only be called when the policy's required
396 +// fields are already populated.
397 +func (ap *AutomationPolicy) RebuildCertMagic(tlsApp *TLS) error {
398 + cfg, err := ap.makeCertMagicConfig(tlsApp, ap.Issuers, ap.storage)
399 + if err != nil {
400 + return err
401 + }
402 certCacheMu.RLock()
353 - ap.magic = certmagic.New(certCache, template)
403 + ap.magic = certmagic.New(certCache, cfg)
404 certCacheMu.RUnlock()
405
406 // sometimes issuers may need the parent certmagic.Config in