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