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: Improve auto HTTP->HTTPS redirects, fix edge cases
See https://caddy.community/t/v2-issues-with-multiple-server-blocks-in-caddyfile-style-config/6206/13?u=matt Also print pid when using `caddy start`
Matthew Holt committed
Sep 18, 2019 at 18:01 UTC
40e05e5a01d50b381fa7a7a472ea38f44518f02c
3 files changed
+86
-74
cmd/commands.go
+1
-1
@@ -130,7 +130,7 @@ func cmdStart() (int, error) {
130
// when one of the goroutines unblocks, we're done and can exit
131
select {
132
case <-success:
133
- fmt.Println("Successfully started Caddy")
133
+ fmt.Printf("Successfully started Caddy (pid=%d)\n", cmd.Process.Pid)
134
case err := <-exit:
135
return caddy.ExitCodeFailedStartup,
136
fmt.Errorf("caddy process exited with error: %v", err)
modules/caddyhttp/caddyhttp.go
+66
-63
@@ -183,12 +183,8 @@ func (app *App) Start() error {
183
}
184
185
// enable TLS
186
- httpPort := app.HTTPPort
187
- if httpPort == 0 {
188
- httpPort = DefaultHTTPPort
189
- }
186
_, port, _ := net.SplitHostPort(addr)
191
- if len(srv.TLSConnPolicies) > 0 && port != strconv.Itoa(httpPort) {
187
+ if len(srv.TLSConnPolicies) > 0 && port != strconv.Itoa(app.httpPort()) {
188
tlsCfg, err := srv.TLSConnPolicies.TLSConfig(app.ctx)
189
if err != nil {
190
return fmt.Errorf("%s/%s: making TLS configuration: %v", network, addr, err)
@@ -273,8 +269,9 @@ func (app *App) automaticHTTPS() error {
269
}
270
tlsApp := tlsAppIface.(*caddytls.TLS)
271
276
- lnAddrMap := make(map[string]struct{})
277
- var redirRoutes RouteList
272
+ // this map will store associations of HTTP listener
273
+ // addresses to the routes that do HTTP->HTTPS redirects
274
+ lnAddrRedirRoutes := make(map[string]Route)
275
276
for srvName, srv := range app.Servers {
277
srv.tlsApp = tlsApp
@@ -284,9 +281,9 @@ func (app *App) automaticHTTPS() error {
281
}
282
283
// skip if all listeners use the HTTP port
287
- if !srv.listenersUseAnyPortOtherThan(app.HTTPPort) {
288
- log.Printf("[INFO] Server %v is only listening on the HTTP port %d, so no automatic HTTPS will be applied to this server",
289
- srv.Listen, app.HTTPPort)
284
+ if !srv.listenersUseAnyPortOtherThan(app.httpPort()) {
285
+ log.Printf("[INFO] Server %s is only listening on the HTTP port %d, so no automatic HTTPS will be applied to this server",
286
+ srvName, app.httpPort())
287
continue
288
}
289
@@ -334,10 +331,10 @@ func (app *App) automaticHTTPS() error {
331
acmeManager := &caddytls.ACMEManagerMaker{
332
Challenges: caddytls.ChallengesConfig{
333
HTTP: caddytls.HTTPChallengeConfig{
337
- AlternatePort: app.HTTPPort,
334
+ AlternatePort: app.HTTPPort, // we specifically want the user-configured port, if any
335
},
336
TLSALPN: caddytls.TLSALPNChallengeConfig{
340
- AlternatePort: app.HTTPSPort,
337
+ AlternatePort: app.HTTPSPort, // we specifically want the user-configured port, if any
338
},
339
},
340
}
@@ -367,12 +364,6 @@ func (app *App) automaticHTTPS() error {
364
365
log.Printf("[INFO] Enabling automatic HTTP->HTTPS redirects for %v", domains)
366
370
- // notify user if their config might override the HTTP->HTTPS redirects
371
- if srv.listenersIncludePort(app.HTTPPort) {
372
- log.Printf("[WARNING] Server %v is listening on HTTP port %d, so automatic HTTP->HTTPS redirects may be overridden by your own configuration",
373
- srv.Listen, app.HTTPPort)
374
- }
375
-
367
// create HTTP->HTTPS redirects
368
for _, addr := range srv.Listen {
369
netw, host, port, err := caddy.SplitNetworkAddress(addr)
@@ -380,28 +371,22 @@ func (app *App) automaticHTTPS() error {
371
return fmt.Errorf("%s: invalid listener address: %v", srvName, addr)
372
}
373
383
- httpPort := app.HTTPPort
384
- if httpPort == 0 {
385
- httpPort = DefaultHTTPPort
386
- }
387
- httpRedirLnAddr := caddy.JoinNetworkAddress(netw, host, strconv.Itoa(httpPort))
388
- lnAddrMap[httpRedirLnAddr] = struct{}{}
389
-
374
if parts := strings.SplitN(port, "-", 2); len(parts) == 2 {
375
port = parts[0]
376
}
377
redirTo := "https://{http.request.host}"
378
395
- httpsPort := app.HTTPSPort
396
- if httpsPort == 0 {
397
- httpsPort = DefaultHTTPSPort
398
- }
399
- if port != strconv.Itoa(httpsPort) {
379
+ if port != strconv.Itoa(app.httpsPort()) {
380
redirTo += ":" + port
381
}
382
redirTo += "{http.request.uri}"
383
404
- redirRoutes = append(redirRoutes, Route{
384
+ // build the plaintext HTTP variant of this address
385
+ httpRedirLnAddr := caddy.JoinNetworkAddress(netw, host, strconv.Itoa(app.httpPort()))
386
+
387
+ // create the route that does the redirect and associate
388
+ // it with the listener address it will be served from
389
+ lnAddrRedirRoutes[httpRedirLnAddr] = Route{
390
MatcherSets: []MatcherSet{
391
{
392
MatchProtocol("http"),
@@ -418,52 +403,70 @@ func (app *App) automaticHTTPS() error {
403
Close: true,
404
},
405
},
421
- })
406
+ }
407
+
408
}
409
}
410
}
411
426
- if len(lnAddrMap) > 0 {
427
- var lnAddrs []string
428
- mapLoop:
429
- for addr := range lnAddrMap {
430
- netw, addrs, err := caddy.ParseNetworkAddress(addr)
431
- if err != nil {
432
- continue
433
- }
434
- for _, a := range addrs {
435
- if app.listenerTaken(netw, a) {
436
- continue mapLoop
412
+ // if there are HTTP->HTTPS redirects to add, do so now
413
+ if len(lnAddrRedirRoutes) > 0 {
414
+ var redirServerAddrs []string
415
+ var redirRoutes []Route
416
+
417
+ // for each redirect listener, see if there's already a
418
+ // server configured to listen on that exact address; if
419
+ // so, simply the redirect route to the end of its route
420
+ // list; otherwise, we'll create a new server for all the
421
+ // listener addresses that are unused and serve the
422
+ // remaining redirects from it
423
+ redirRoutesLoop:
424
+ for addr, redirRoute := range lnAddrRedirRoutes {
425
+ for srvName, srv := range app.Servers {
426
+ if srv.hasListenerAddress(addr) {
427
+ // user has configured a server for the same address
428
+ // that the redirect runs from; simply append our
429
+ // redirect route to the existing routes, with a
430
+ // caveat that their config might override ours
431
+ log.Printf("[WARNING] Server %s is listening on %s, so automatic HTTP->HTTPS redirects might be overridden by your own configuration",
432
+ srvName, addr)
433
+ srv.Routes = append(srv.Routes, redirRoute)
434
+ continue redirRoutesLoop
435
}
436
}
439
- lnAddrs = append(lnAddrs, addr)
437
+ // no server with this listener address exists;
438
+ // save this address and route for custom server
439
+ redirServerAddrs = append(redirServerAddrs, addr)
440
+ redirRoutes = append(redirRoutes, redirRoute)
441
}
441
- app.Servers["auto_https_redirects"] = &Server{
442
- Listen: lnAddrs,
443
- Routes: redirRoutes,
444
- AutoHTTPS: &AutoHTTPSConfig{Disabled: true},
445
- tlsApp: tlsApp, // required to solve HTTP challenge
442
+
443
+ // if there are routes remaining which do not belong
444
+ // in any existing server, make our own to serve the
445
+ // rest of the redirects
446
+ if len(redirServerAddrs) > 0 {
447
+ app.Servers["remaining_auto_https_redirects"] = &Server{
448
+ Listen: redirServerAddrs,
449
+ Routes: redirRoutes,
450
+ tlsApp: tlsApp, // required to solve HTTP challenge
451
+ }
452
}
453
}
454
455
return nil
456
}
457
452
-func (app *App) listenerTaken(network, address string) bool {
453
- for _, srv := range app.Servers {
454
- for _, addr := range srv.Listen {
455
- netw, addrs, err := caddy.ParseNetworkAddress(addr)
456
- if err != nil || netw != network {
457
- continue
458
- }
459
- for _, a := range addrs {
460
- if a == address {
461
- return true
462
- }
463
- }
464
- }
458
+func (app *App) httpPort() int {
459
+ if app.HTTPPort == 0 {
460
+ return DefaultHTTPPort
461
}
466
- return false
462
+ return app.HTTPPort
463
+}
464
+
465
+func (app *App) httpsPort() int {
466
+ if app.HTTPSPort == 0 {
467
+ return DefaultHTTPSPort
468
+ }
469
+ return app.HTTPSPort
470
}
471
472
var defaultALPN = []string{"h2", "http/1.1"}
modules/caddyhttp/server.go
+19
-10
@@ -196,17 +196,26 @@ func (s *Server) listenersUseAnyPortOtherThan(otherPort int) bool {
196
return false
197
}
198
199
-// listenersIncludePort returns true if there are any
200
-// listeners in s that use otherPort.
201
-func (s *Server) listenersIncludePort(otherPort int) bool {
199
+func (s *Server) hasListenerAddress(fullAddr string) bool {
200
+ netw, addrs, err := caddy.ParseNetworkAddress(fullAddr)
201
+ if err != nil {
202
+ return false
203
+ }
204
+ if len(addrs) != 1 {
205
+ return false
206
+ }
207
+ addr := addrs[0]
208
for _, lnAddr := range s.Listen {
203
- _, addrs, err := caddy.ParseNetworkAddress(lnAddr)
204
- if err == nil {
205
- for _, a := range addrs {
206
- _, port, err := net.SplitHostPort(a)
207
- if err == nil && port == strconv.Itoa(otherPort) {
208
- return true
209
- }
209
+ thisNetw, thisAddrs, err := caddy.ParseNetworkAddress(lnAddr)
210
+ if err != nil {
211
+ continue
212
+ }
213
+ if thisNetw != netw {
214
+ continue
215
+ }
216
+ for _, a := range thisAddrs {
217
+ if a == addr {
218
+ return true
219
}
220
}
221
}