@marcel91200 / caddy Mirror · read-only / commits / 5c7ca7d9
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 14, 05:15 UTC

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.

Matthew Holt committed Feb 5, 2020 at 17:34 UTC 5c7ca7d96e2d4ee2d3044475ce03e46589445b51
4 files changed +39 -24
go.mod
+1 -2
@@ -7,7 +7,6 @@ require (
7 github.com/alecthomas/chroma v0.7.0
8 github.com/andybalholm/brotli v0.0.0-20190821151343-b60f0d972eeb
9 github.com/cenkalti/backoff/v3 v3.1.1 // indirect
10 - github.com/decker502/dnspod-go v0.2.0 // indirect
10 github.com/dustin/go-humanize v1.0.0
11 github.com/go-acme/lego/v3 v3.3.0
12 github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc
@@ -18,7 +17,7 @@ require (
17 github.com/klauspost/cpuid v1.2.2
18 github.com/kylelemons/godebug v1.1.0 // indirect
19 github.com/lucas-clemente/quic-go v0.14.1
21 - github.com/mholt/certmagic v0.9.1
20 + github.com/mholt/certmagic v0.9.2
21 github.com/miekg/dns v1.1.25 // indirect
22 github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190906142622-1265e9b150c6
23 github.com/naoina/go-stringutil v0.1.0 // indirect
go.sum
+4 -9
@@ -86,7 +86,6 @@ github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9
86 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
87 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
88 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
89 -github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
89 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
90 github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
91 github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
@@ -103,9 +102,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
102 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
103 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
104 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
106 -github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
107 -github.com/go-acme/lego/v3 v3.2.0 h1:z0zvNlL1niv/1qA06V5X1BRC5PeLoGKAlVaWthXQz9c=
108 -github.com/go-acme/lego/v3 v3.2.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
105 github.com/go-acme/lego/v3 v3.3.0 h1:6BePZsOiYA4/w+M7QDytxQtMfCipMPGnWAHs9pWks98=
106 github.com/go-acme/lego/v3 v3.3.0/go.mod h1:iGSY2vQrvQs3WezicSB/oVbO2eCrD88dpWPwb1qLqu0=
107 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
@@ -126,6 +122,7 @@ github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc/go.mod h1:cIg4er
122 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
123 github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
124 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
125 +github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
126 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
127 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
128 github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
@@ -228,10 +225,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
225 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
226 github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
227 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
231 -github.com/mholt/certmagic v0.9.0 h1:dYh9sZPDBTcIiPhYM/Qtv3V623/zFH34FmpbrQTpMAc=
232 -github.com/mholt/certmagic v0.9.0/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
233 -github.com/mholt/certmagic v0.9.1 h1:wPzyouOyE+30NIQETJuhTB5ZQWz+0Hy038vaR5WWQDE=
234 -github.com/mholt/certmagic v0.9.1/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
228 +github.com/mholt/certmagic v0.9.2 h1:m+l8jZADOwL2zBVWhaprTnJaRVmRwG4FzR1A8nHwrLw=
229 +github.com/mholt/certmagic v0.9.2/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
230 github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI=
231 github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
232 github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
@@ -362,7 +357,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
357 golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
358 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
359 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
365 -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
360 golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
361 golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
362 golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
@@ -420,6 +414,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
414 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
415 golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
416 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
417 +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
418 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
419 golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
420 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
modules/caddyhttp/autohttps.go
+23 -10
@@ -62,7 +62,7 @@ func (ahc AutoHTTPSConfig) Skipped(name string, skipSlice []string) bool {
62 // HTTPS, and sets up HTTP->HTTPS redirects. This phase must occur
63 // at the beginning of provisioning, because it may add routes and
64 // even servers to the app, which still need to be set up with the
65 -// rest of them.
65 +// rest of them during provisioning.
66 func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) error {
67 // this map will store associations of HTTP listener
68 // addresses to the routes that do HTTP->HTTPS redirects
@@ -259,10 +259,9 @@ redirRoutesLoop:
259 }
260
261 // automaticHTTPSPhase2 attaches a TLS app pointer to each
262 -// server and begins certificate management for all names
263 -// in the qualifying domain set for each server. This phase
264 -// must occur after provisioning, and at the beginning of
265 -// the app start, before starting each of the servers.
262 +// server. This phase must occur after provisioning, and
263 +// at the beginning of the app start, before starting each
264 +// of the servers.
265 func (app *App) automaticHTTPSPhase2() error {
266 tlsAppIface, err := app.ctx.App("tls")
267 if err != nil {
@@ -277,6 +276,20 @@ func (app *App) automaticHTTPSPhase2() error {
276 srv.tlsApp = tlsApp
277 }
278
279 + return nil
280 +}
281 +
282 +// automaticHTTPSPhase3 begins certificate management for
283 +// all names in the qualifying domain set for each server.
284 +// This phase must occur after provisioning and at the end
285 +// of app start, after all the servers have been started.
286 +// Doing this last ensures that there won't be any race
287 +// for listeners on the HTTP or HTTPS ports when management
288 +// is async (if CertMagic's solvers bind to those ports
289 +// first, then our servers would fail to bind to them,
290 +// which would be bad, since CertMagic's bindings are
291 +// temporary and don't serve the user's sites!).
292 +func (app *App) automaticHTTPSPhase3() error {
293 // begin managing certificates for enabled servers
294 for srvName, srv := range app.Servers {
295 if srv.AutoHTTPS == nil ||
@@ -294,7 +307,7 @@ func (app *App) automaticHTTPSPhase2() error {
307 // don't obtain another one for it, unless we are
308 // supposed to ignore loaded certificates
309 if !srv.AutoHTTPS.IgnoreLoadedCerts &&
297 - len(tlsApp.AllMatchingCertificates(d)) > 0 {
310 + len(srv.tlsApp.AllMatchingCertificates(d)) > 0 {
311 app.logger.Info("skipping automatic certificate management because one or more matching certificates are already loaded",
312 zap.String("domain", d),
313 zap.String("server_name", srvName),
@@ -321,10 +334,10 @@ func (app *App) automaticHTTPSPhase2() error {
334 },
335 },
336 }
324 - if tlsApp.Automation == nil {
325 - tlsApp.Automation = new(caddytls.AutomationConfig)
337 + if srv.tlsApp.Automation == nil {
338 + srv.tlsApp.Automation = new(caddytls.AutomationConfig)
339 }
327 - tlsApp.Automation.Policies = append(tlsApp.Automation.Policies,
340 + srv.tlsApp.Automation.Policies = append(srv.tlsApp.Automation.Policies,
341 caddytls.AutomationPolicy{
342 Hosts: domainsForCerts,
343 Management: acmeManager,
@@ -334,7 +347,7 @@ func (app *App) automaticHTTPSPhase2() error {
347 app.logger.Info("enabling automatic TLS certificate management",
348 zap.Strings("domains", domainsForCerts),
349 )
337 - err := tlsApp.Manage(domainsForCerts)
350 + err := srv.tlsApp.Manage(domainsForCerts)
351 if err != nil {
352 return fmt.Errorf("%s: managing certificate for %s: %s", srvName, domains, err)
353 }
modules/caddyhttp/caddyhttp.go
+11 -3
@@ -220,11 +220,12 @@ func (app *App) Validate() error {
220 // Start runs the app. It finishes automatic HTTPS if enabled,
221 // including management of certificates.
222 func (app *App) Start() error {
223 - // finish setting up automatic HTTPS and manage certs;
224 - // this must happen before each server is started
223 + // give each server a pointer to the TLS app;
224 + // this is required before they are started so
225 + // they can solve ACME challenges
226 err := app.automaticHTTPSPhase2()
227 if err != nil {
227 - return fmt.Errorf("enabling automatic HTTPS: %v", err)
228 + return fmt.Errorf("enabling automatic HTTPS, phase 2: %v", err)
229 }
230
231 for srvName, srv := range app.Servers {
@@ -297,6 +298,13 @@ func (app *App) Start() error {
298 }
299 }
300
301 + // finish automatic HTTPS by finally beginning
302 + // certificate management
303 + err = app.automaticHTTPSPhase3()
304 + if err != nil {
305 + return fmt.Errorf("finalizing automatic HTTPS: %v", err)
306 + }
307 +
308 return nil
309 }
310