summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/autohttps.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-02-05 17:34:28 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2020-02-05 17:34:28 -0700
commit5c7ca7d96e2d4ee2d3044475ce03e46589445b51 (patch)
treedfc3b615e8d288878f7a68dd18da76783fc66f91 /modules/caddyhttp/autohttps.go
parentec56c257089f42ef88ec3a5ec818965c0fa5d57f (diff)
http: Split 2-phase auto-HTTPS into 3 phases
This is necessary to avoid a race for sockets. Both the HTTP servers and CertMagic solvers will try to bind the HTTP/HTTPS ports, but we need to make sure that our HTTP servers bind first. This is kind of a new thing now that management is async in Caddy 2. Also update to CertMagic 0.9.2, which fixes some async use cases at scale.
Diffstat (limited to 'modules/caddyhttp/autohttps.go')
-rw-r--r--modules/caddyhttp/autohttps.go33
1 files changed, 23 insertions, 10 deletions
diff --git a/modules/caddyhttp/autohttps.go b/modules/caddyhttp/autohttps.go
index 69e3318..d60e955 100644
--- a/modules/caddyhttp/autohttps.go
+++ b/modules/caddyhttp/autohttps.go
@@ -62,7 +62,7 @@ func (ahc AutoHTTPSConfig) Skipped(name string, skipSlice []string) bool {
// HTTPS, and sets up HTTP->HTTPS redirects. This phase must occur
// at the beginning of provisioning, because it may add routes and
// even servers to the app, which still need to be set up with the
-// rest of them.
+// rest of them during provisioning.
func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) error {
// this map will store associations of HTTP listener
// addresses to the routes that do HTTP->HTTPS redirects
@@ -259,10 +259,9 @@ redirRoutesLoop:
}
// automaticHTTPSPhase2 attaches a TLS app pointer to each
-// server and begins certificate management for all names
-// in the qualifying domain set for each server. This phase
-// must occur after provisioning, and at the beginning of
-// the app start, before starting each of the servers.
+// server. This phase must occur after provisioning, and
+// at the beginning of the app start, before starting each
+// of the servers.
func (app *App) automaticHTTPSPhase2() error {
tlsAppIface, err := app.ctx.App("tls")
if err != nil {
@@ -277,6 +276,20 @@ func (app *App) automaticHTTPSPhase2() error {
srv.tlsApp = tlsApp
}
+ return nil
+}
+
+// automaticHTTPSPhase3 begins certificate management for
+// all names in the qualifying domain set for each server.
+// This phase must occur after provisioning and at the end
+// of app start, after all the servers have been started.
+// Doing this last ensures that there won't be any race
+// for listeners on the HTTP or HTTPS ports when management
+// is async (if CertMagic's solvers bind to those ports
+// first, then our servers would fail to bind to them,
+// which would be bad, since CertMagic's bindings are
+// temporary and don't serve the user's sites!).
+func (app *App) automaticHTTPSPhase3() error {
// begin managing certificates for enabled servers
for srvName, srv := range app.Servers {
if srv.AutoHTTPS == nil ||
@@ -294,7 +307,7 @@ func (app *App) automaticHTTPSPhase2() error {
// don't obtain another one for it, unless we are
// supposed to ignore loaded certificates
if !srv.AutoHTTPS.IgnoreLoadedCerts &&
- len(tlsApp.AllMatchingCertificates(d)) > 0 {
+ len(srv.tlsApp.AllMatchingCertificates(d)) > 0 {
app.logger.Info("skipping automatic certificate management because one or more matching certificates are already loaded",
zap.String("domain", d),
zap.String("server_name", srvName),
@@ -321,10 +334,10 @@ func (app *App) automaticHTTPSPhase2() error {
},
},
}
- if tlsApp.Automation == nil {
- tlsApp.Automation = new(caddytls.AutomationConfig)
+ if srv.tlsApp.Automation == nil {
+ srv.tlsApp.Automation = new(caddytls.AutomationConfig)
}
- tlsApp.Automation.Policies = append(tlsApp.Automation.Policies,
+ srv.tlsApp.Automation.Policies = append(srv.tlsApp.Automation.Policies,
caddytls.AutomationPolicy{
Hosts: domainsForCerts,
Management: acmeManager,
@@ -334,7 +347,7 @@ func (app *App) automaticHTTPSPhase2() error {
app.logger.Info("enabling automatic TLS certificate management",
zap.Strings("domains", domainsForCerts),
)
- err := tlsApp.Manage(domainsForCerts)
+ err := srv.tlsApp.Manage(domainsForCerts)
if err != nil {
return fmt.Errorf("%s: managing certificate for %s: %s", srvName, domains, err)
}