func (t *TLS) Manage(names []string) error {
	policyToNames := make(map[*AutomationPolicy][]string)
	for _, name := range names {
		ap := t.getAutomationPolicyForName(name)
		policyToNames[ap] = append(policyToNames[ap], name)
	}
	for ap, names := range policyToNames {
		err := ap.magic.ManageAsync(t.ctx.Context, names)
		if err != nil {
			return fmt.Errorf("automate: manage %v: %v", names, err)
		}
	}
	return nil
}
Manage immediately begins managing names according to the
matching automation policy.
package caddytls
import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"runtime/debug"
	"sync"
	"time"
	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/certmagic"
	"go.uber.org/zap"
)
func init() {
	caddy.RegisterModule(TLS{})
	caddy.RegisterModule(AutomateLoader{})
}
type TLS struct {
	CertificatesRaw caddy.ModuleMap `json:"certificates,omitempty" caddy:"namespace=tls.certificates"`
	Automation *AutomationConfig `json:"automation,omitempty"`
	SessionTickets *SessionTicketService `json:"session_tickets,omitempty"`
	Cache *CertCacheOptions `json:"cache,omitempty"`
	DisableOCSPStapling bool `json:"disable_ocsp_stapling,omitempty"`
	certificateLoaders []CertificateLoader
	automateNames      []string
	certCache          *certmagic.Cache
	ctx                caddy.Context
	storageCleanTicker *time.Ticker
	storageCleanStop   chan struct{}
	logger             *zap.Logger
}
func (TLS) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "tls",
		New: func() caddy.Module { return new(TLS) },
	}
}
func (t *TLS) Provision(ctx caddy.Context) error {
	t.ctx = ctx
	t.logger = ctx.Logger(t)
	repl := caddy.NewReplacer()
	cacheOpts := certmagic.CacheOptions{
		GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
			return t.getConfigForName(cert.Names[0]), nil
		},
		Logger: t.logger.Named("cache"),
	}
	if t.Automation != nil {
		cacheOpts.OCSPCheckInterval = time.Duration(t.Automation.OCSPCheckInterval)
		cacheOpts.RenewCheckInterval = time.Duration(t.Automation.RenewCheckInterval)
	}
	if t.Cache != nil {
		cacheOpts.Capacity = t.Cache.Capacity
	}
	if cacheOpts.Capacity <= 0 {
		cacheOpts.Capacity = 10000
	}
	t.certCache = certmagic.NewCache(cacheOpts)
	val, err := ctx.LoadModule(t, "CertificatesRaw")
	if err != nil {
		return fmt.Errorf("loading certificate loader modules: %s", err)
	}
	for modName, modIface := range val.(map[string]interface{}) {
		if modName == "automate" {
			if automateNames, ok := modIface.(*AutomateLoader); ok && automateNames != nil {
				t.automateNames = []string(*automateNames)
			} else {
				return fmt.Errorf("loading certificates with 'automate' requires array of strings, got: %T", modIface)
			}
			continue
		}
		t.certificateLoaders = append(t.certificateLoaders, modIface.(CertificateLoader))
	}
	if t.Automation == nil {
		t.Automation = new(AutomationConfig)
	}
	t.Automation.defaultPublicAutomationPolicy = new(AutomationPolicy)
	err = t.Automation.defaultPublicAutomationPolicy.Provision(t)
	if err != nil {
		return fmt.Errorf("provisioning default public automation policy: %v", err)
	}
	for _, n := range t.automateNames {
		if certmagic.SubjectQualifiesForPublicCert(n) {
			continue
		}
		t.Automation.defaultInternalAutomationPolicy = &AutomationPolicy{
			IssuersRaw: []json.RawMessage{json.RawMessage(`{"module":"internal"}`)},
		}
		err = t.Automation.defaultInternalAutomationPolicy.Provision(t)
		if err != nil {
			return fmt.Errorf("provisioning default internal automation policy: %v", err)
		}
		break
	}
	for i, ap := range t.Automation.Policies {
		err := ap.Provision(t)
		if err != nil {
			return fmt.Errorf("provisioning automation policy %d: %v", i, err)
		}
	}
	if t.SessionTickets != nil {
		err := t.SessionTickets.provision(ctx)
		if err != nil {
			return fmt.Errorf("provisioning session tickets configuration: %v", err)
		}
	}
	if t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.RateLimit != nil {
		onDemandRateLimiter.SetMaxEvents(t.Automation.OnDemand.RateLimit.Burst)
		onDemandRateLimiter.SetWindow(time.Duration(t.Automation.OnDemand.RateLimit.Interval))
	} else {
		onDemandRateLimiter.SetMaxEvents(0)
		onDemandRateLimiter.SetWindow(0)
	}
	if t.Automation != nil && t.Automation.OnDemand != nil && t.Automation.OnDemand.Ask != "" {
		t.Automation.OnDemand.Ask = repl.ReplaceAll(t.Automation.OnDemand.Ask, "")
	}
	magic := certmagic.New(t.certCache, certmagic.Config{
		Storage: ctx.Storage(),
		Logger:  t.logger,
		OCSP: certmagic.OCSPConfig{
			DisableStapling: t.DisableOCSPStapling,
		},
	})
	for _, loader := range t.certificateLoaders {
		certs, err := loader.LoadCertificates()
		if err != nil {
			return fmt.Errorf("loading certificates: %v", err)
		}
		for _, cert := range certs {
			err := magic.CacheUnmanagedTLSCertificate(cert.Certificate, cert.Tags)
			if err != nil {
				return fmt.Errorf("caching unmanaged certificate: %v", err)
			}
		}
	}
	return nil
}
func (t *TLS) Validate() error {
	if t.Automation != nil {
		var hasDefault bool
		hostSet := make(map[string]int)
		for i, ap := range t.Automation.Policies {
			if len(ap.Subjects) == 0 {
				if hasDefault {
					return fmt.Errorf("automation policy %d is the second policy that acts as default/catch-all, but will never be used", i)
				}
				hasDefault = true
			}
			for _, h := range ap.Subjects {
				if first, ok := hostSet[h]; ok {
					return fmt.Errorf("automation policy %d: cannot apply more than one automation policy to host: %s (first match in policy %d)", i, h, first)
				}
				hostSet[h] = i
			}
		}
	}
	if t.Cache != nil {
		if t.Cache.Capacity < 0 {
			return fmt.Errorf("cache capacity must be >= 0")
		}
	}
	return nil
}
func (t *TLS) Start() error {
	if t.Automation.OnDemand == nil ||
		(t.Automation.OnDemand.Ask == "" && t.Automation.OnDemand.RateLimit == nil) {
		for _, ap := range t.Automation.Policies {
			if ap.OnDemand {
				t.logger.Warn("YOUR SERVER MAY BE VULNERABLE TO ABUSE: on-demand TLS is enabled, but no protections are in place",
					zap.String("docs", "https://caddyserver.com/docs/automatic-https#on-demand-tls"))
				break
			}
		}
	}
	err := t.Manage(t.automateNames)
	if err != nil {
		return fmt.Errorf("automate: managing %v: %v", t.automateNames, err)
	}
	t.keepStorageClean()
	return nil
}
func (t *TLS) Stop() error {
	if t.storageCleanStop != nil {
		close(t.storageCleanStop)
	}
	if t.storageCleanTicker != nil {
		t.storageCleanTicker.Stop()
	}
	return nil
}
func (t *TLS) Cleanup() error {
	if t.certCache != nil {
		t.certCache.Stop()
	}
	if t.SessionTickets != nil {
		t.SessionTickets.stop()
	}
	return nil
}