@marcel91200 / caddy Mirror · read-only / commits / 441d5eb0
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 11, 12:15 UTC

caddyhttp: prefer port 443 in auto-HTTPS and add tests (#7666)

Matt Holt committed Apr 23, 2026 at 01:29 UTC 441d5eb0628c4a9fbe74c13eca6ab255056e3e57
3 files changed +97 -7
caddytest/integration/autohttps_test.go
+22
@@ -55,6 +55,28 @@ func TestAutoHTTPtoHTTPSRedirectsExplicitPortDifferentFromHTTPSPort(t *testing.T
55 tester.AssertRedirect("http://localhost:9080/", "https://localhost:1234/", http.StatusPermanentRedirect)
56 }
57
58 +func TestAutoHTTPtoHTTPSRedirectsPreferHTTPSPortOverAlternatePort(t *testing.T) {
59 + tester := caddytest.NewTester(t)
60 + tester.InitServer(`
61 + {
62 + skip_install_trust
63 + admin localhost:2999
64 + http_port 9080
65 + https_port 9443
66 + local_certs
67 + }
68 + localhost {
69 + respond "Canonical"
70 + }
71 +
72 + localhost:10443 {
73 + respond "Alternate"
74 + }
75 + `, "caddyfile")
76 +
77 + tester.AssertRedirect("http://localhost:9080/", "https://localhost/", http.StatusPermanentRedirect)
78 +}
79 +
80 func TestAutoHTTPRedirectsWithHTTPListenerFirstInAddresses(t *testing.T) {
81 tester := caddytest.NewTester(t)
82 tester.InitServer(`
modules/caddyhttp/autohttps.go
+31 -7
@@ -258,18 +258,13 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er
258 // an empty string to indicate a catch-all, which we have to
259 // treat special later
260 if len(serverDomainSet) == 0 {
261 - redirDomains[""] = append(redirDomains[""], addr)
261 + app.recordAutoHTTPSRedirectAddress(redirDomains, "", addr)
262 continue
263 }
264
265 // ...and associate it with each domain in this server
266 for d := range serverDomainSet {
267 - // if this domain is used on more than one HTTPS-enabled
268 - // port, we'll have to choose one, so prefer the HTTPS port
269 - if _, ok := redirDomains[d]; !ok ||
270 - addr.StartPort == uint(app.httpsPort()) {
271 - redirDomains[d] = append(redirDomains[d], addr)
272 - }
267 + app.recordAutoHTTPSRedirectAddress(redirDomains, d, addr)
268 }
269 }
270 }
@@ -517,6 +512,35 @@ redirServersLoop:
512 return nil
513 }
514
515 +// recordAutoHTTPSRedirectAddress stores redirect destinations for one domain
516 +// using a single winning port while keeping all bind addresses on that port.
517 +//
518 +// This is needed to avoid two opposite regressions in auto-HTTPS redirects:
519 +// preserve all listener addresses when a site binds multiple addresses on the
520 +// same HTTPS port, but do not mix in alternate HTTPS ports when the canonical
521 +// app HTTPS port is also available.
522 +func (app *App) recordAutoHTTPSRedirectAddress(redirDomains map[string][]caddy.NetworkAddress, domain string, addr caddy.NetworkAddress) {
523 + existing := redirDomains[domain]
524 + if len(existing) == 0 {
525 + redirDomains[domain] = []caddy.NetworkAddress{addr}
526 + return
527 + }
528 +
529 + existingPort := existing[0].StartPort
530 + if addr.StartPort != existingPort {
531 + if addr.StartPort == uint(app.httpsPort()) && existingPort != uint(app.httpsPort()) {
532 + redirDomains[domain] = []caddy.NetworkAddress{addr}
533 + }
534 + return
535 + }
536 +
537 + if slices.Contains(existing, addr) {
538 + return
539 + }
540 +
541 + redirDomains[domain] = append(existing, addr)
542 +}
543 +
544 func (app *App) makeRedirRoute(redirToPort uint, matcherSet MatcherSet) Route {
545 redirTo := "https://{http.request.host}"
546
modules/caddyhttp/autohttps_test.go new
+44
@@ -0,0 +1,44 @@
1 +package caddyhttp
2 +
3 +import (
4 + "testing"
5 +
6 + "github.com/caddyserver/caddy/v2"
7 +)
8 +
9 +func TestRecordAutoHTTPSRedirectAddressPrefersHTTPSPort(t *testing.T) {
10 + app := &App{HTTPSPort: 443}
11 + redirDomains := make(map[string][]caddy.NetworkAddress)
12 +
13 + app.recordAutoHTTPSRedirectAddress(redirDomains, "example.com", caddy.NetworkAddress{Network: "tcp", StartPort: 2345, EndPort: 2345})
14 + app.recordAutoHTTPSRedirectAddress(redirDomains, "example.com", caddy.NetworkAddress{Network: "tcp", StartPort: 443, EndPort: 443})
15 + app.recordAutoHTTPSRedirectAddress(redirDomains, "example.com", caddy.NetworkAddress{Network: "tcp", StartPort: 8443, EndPort: 8443})
16 +
17 + got := redirDomains["example.com"]
18 + if len(got) != 1 {
19 + t.Fatalf("expected 1 redirect address, got %d: %#v", len(got), got)
20 + }
21 + if got[0].StartPort != 443 {
22 + t.Fatalf("expected redirect to prefer HTTPS port 443, got %#v", got[0])
23 + }
24 +}
25 +
26 +func TestRecordAutoHTTPSRedirectAddressKeepsAllBindAddressesOnWinningPort(t *testing.T) {
27 + app := &App{HTTPSPort: 443}
28 + redirDomains := make(map[string][]caddy.NetworkAddress)
29 +
30 + app.recordAutoHTTPSRedirectAddress(redirDomains, "example.com", caddy.NetworkAddress{Network: "tcp", Host: "10.0.0.189", StartPort: 8443, EndPort: 8443})
31 + app.recordAutoHTTPSRedirectAddress(redirDomains, "example.com", caddy.NetworkAddress{Network: "tcp", Host: "10.0.0.189", StartPort: 443, EndPort: 443})
32 + app.recordAutoHTTPSRedirectAddress(redirDomains, "example.com", caddy.NetworkAddress{Network: "tcp", Host: "2603:c024:8002:9500:9eb:e5d3:3975:d056", StartPort: 443, EndPort: 443})
33 +
34 + got := redirDomains["example.com"]
35 + if len(got) != 2 {
36 + t.Fatalf("expected 2 redirect addresses for both bind addresses on the winning port, got %d: %#v", len(got), got)
37 + }
38 + if got[0].StartPort != 443 || got[1].StartPort != 443 {
39 + t.Fatalf("expected both redirect addresses to stay on HTTPS port 443, got %#v", got)
40 + }
41 + if got[0].Host != "10.0.0.189" || got[1].Host != "2603:c024:8002:9500:9eb:e5d3:3975:d056" {
42 + t.Fatalf("expected both bind addresses to be preserved, got %#v", got)
43 + }
44 +}