mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
Merge pull request #1500 from mholt/customports
httpserver: Flags to customize HTTP and HTTPS ports (including for ACME challenges)
This commit is contained in:
commit
df9d062a8f
6 changed files with 84 additions and 44 deletions
|
@ -134,7 +134,7 @@ func (c Context) Port() (string, error) {
|
|||
if err != nil {
|
||||
if !strings.Contains(c.Req.Host, ":") {
|
||||
// common with sites served on the default port 80
|
||||
return "80", nil
|
||||
return HTTPPort, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ func enableAutoHTTPS(configs []*SiteConfig, loadCertificates bool) error {
|
|||
cfg.TLS.Enabled &&
|
||||
(!cfg.TLS.Manual || cfg.TLS.OnDemand) &&
|
||||
cfg.Addr.Host != "localhost" {
|
||||
cfg.Addr.Port = "443"
|
||||
cfg.Addr.Port = HTTPSPort
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -108,8 +108,8 @@ func enableAutoHTTPS(configs []*SiteConfig, loadCertificates bool) error {
|
|||
func makePlaintextRedirects(allConfigs []*SiteConfig) []*SiteConfig {
|
||||
for i, cfg := range allConfigs {
|
||||
if cfg.TLS.Managed &&
|
||||
!hostHasOtherPort(allConfigs, i, "80") &&
|
||||
(cfg.Addr.Port == "443" || !hostHasOtherPort(allConfigs, i, "443")) {
|
||||
!hostHasOtherPort(allConfigs, i, HTTPPort) &&
|
||||
(cfg.Addr.Port == HTTPSPort || !hostHasOtherPort(allConfigs, i, HTTPSPort)) {
|
||||
allConfigs = append(allConfigs, redirPlaintextHost(cfg))
|
||||
}
|
||||
}
|
||||
|
@ -135,18 +135,19 @@ func hostHasOtherPort(allConfigs []*SiteConfig, thisConfigIdx int, otherPort str
|
|||
// redirPlaintextHost returns a new plaintext HTTP configuration for
|
||||
// a virtualHost that simply redirects to cfg, which is assumed to
|
||||
// be the HTTPS configuration. The returned configuration is set
|
||||
// to listen on port 80. The TLS field of cfg must not be nil.
|
||||
// to listen on HTTPPort. The TLS field of cfg must not be nil.
|
||||
func redirPlaintextHost(cfg *SiteConfig) *SiteConfig {
|
||||
redirPort := cfg.Addr.Port
|
||||
if redirPort == "443" {
|
||||
// default port is redundant
|
||||
redirPort = ""
|
||||
if redirPort == DefaultHTTPSPort {
|
||||
redirPort = "" // default port is redundant
|
||||
}
|
||||
redirMiddleware := func(next Handler) Handler {
|
||||
return HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
toURL := "https://" + r.Host
|
||||
if redirPort != "" {
|
||||
toURL += ":" + redirPort
|
||||
toURL := "https://"
|
||||
if redirPort == "" {
|
||||
toURL += cfg.Addr.Host // don't use r.Host as it may have a port included
|
||||
} else {
|
||||
toURL += net.JoinHostPort(cfg.Addr.Host, redirPort)
|
||||
}
|
||||
toURL += r.URL.RequestURI()
|
||||
w.Header().Set("Connection", "close")
|
||||
|
@ -155,12 +156,13 @@ func redirPlaintextHost(cfg *SiteConfig) *SiteConfig {
|
|||
})
|
||||
}
|
||||
host := cfg.Addr.Host
|
||||
port := "80"
|
||||
port := HTTPPort
|
||||
addr := net.JoinHostPort(host, port)
|
||||
return &SiteConfig{
|
||||
Addr: Address{Original: addr, Host: host, Port: port},
|
||||
ListenHost: cfg.ListenHost,
|
||||
middleware: []Middleware{redirMiddleware},
|
||||
TLS: &caddytls.Config{AltHTTPPort: cfg.TLS.AltHTTPPort},
|
||||
TLS: &caddytls.Config{AltHTTPPort: cfg.TLS.AltHTTPPort, AltTLSSNIPort: cfg.TLS.AltTLSSNIPort},
|
||||
Timeouts: cfg.Timeouts,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
func TestRedirPlaintextHost(t *testing.T) {
|
||||
cfg := redirPlaintextHost(&SiteConfig{
|
||||
Addr: Address{
|
||||
Host: "example.com",
|
||||
Host: "foohost",
|
||||
Port: "1234",
|
||||
},
|
||||
ListenHost: "93.184.216.34",
|
||||
|
@ -19,7 +19,7 @@ func TestRedirPlaintextHost(t *testing.T) {
|
|||
})
|
||||
|
||||
// Check host and port
|
||||
if actual, expected := cfg.Addr.Host, "example.com"; actual != expected {
|
||||
if actual, expected := cfg.Addr.Host, "foohost"; actual != expected {
|
||||
t.Errorf("Expected redir config to have host %s but got %s", expected, actual)
|
||||
}
|
||||
if actual, expected := cfg.ListenHost, "93.184.216.34"; actual != expected {
|
||||
|
@ -38,7 +38,7 @@ func TestRedirPlaintextHost(t *testing.T) {
|
|||
|
||||
// Check redirect for correctness
|
||||
rec := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://foo/bar?q=1", nil)
|
||||
req, err := http.NewRequest("GET", "http://foohost/bar?q=1", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -52,17 +52,17 @@ func TestRedirPlaintextHost(t *testing.T) {
|
|||
if rec.Code != http.StatusMovedPermanently {
|
||||
t.Errorf("Expected status %d but got %d", http.StatusMovedPermanently, rec.Code)
|
||||
}
|
||||
if got, want := rec.Header().Get("Location"), "https://foo:1234/bar?q=1"; got != want {
|
||||
if got, want := rec.Header().Get("Location"), "https://foohost:1234/bar?q=1"; got != want {
|
||||
t.Errorf("Expected Location: '%s' but got '%s'", want, got)
|
||||
}
|
||||
|
||||
// browsers can infer a default port from scheme, so make sure the port
|
||||
// doesn't get added in explicitly for default ports like 443 for https.
|
||||
cfg = redirPlaintextHost(&SiteConfig{Addr: Address{Host: "example.com", Port: "443"}, TLS: new(caddytls.Config)})
|
||||
cfg = redirPlaintextHost(&SiteConfig{Addr: Address{Host: "foohost", Port: "443"}, TLS: new(caddytls.Config)})
|
||||
handler = cfg.middleware[0](nil)
|
||||
|
||||
rec = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "http://foo/bar?q=1", nil)
|
||||
req, err = http.NewRequest("GET", "http://foohost/bar?q=1", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func TestRedirPlaintextHost(t *testing.T) {
|
|||
if rec.Code != http.StatusMovedPermanently {
|
||||
t.Errorf("Expected status %d but got %d", http.StatusMovedPermanently, rec.Code)
|
||||
}
|
||||
if got, want := rec.Header().Get("Location"), "https://foo/bar?q=1"; got != want {
|
||||
if got, want := rec.Header().Get("Location"), "https://foohost/bar?q=1"; got != want {
|
||||
t.Errorf("Expected Location: '%s' but got '%s'", want, got)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ import (
|
|||
const serverType = "http"
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&HTTPPort, "http-port", HTTPPort, "Default port to use for HTTP")
|
||||
flag.StringVar(&HTTPSPort, "https-port", HTTPSPort, "Default port to use for HTTPS")
|
||||
flag.StringVar(&Host, "host", DefaultHost, "Default host")
|
||||
flag.StringVar(&Port, "port", DefaultPort, "Default port")
|
||||
flag.StringVar(&Root, "root", DefaultRoot, "Root path of default site")
|
||||
|
@ -119,11 +121,25 @@ func (h *httpContext) InspectServerBlocks(sourceFile string, serverBlocks []cadd
|
|||
addr.Port = Port
|
||||
}
|
||||
|
||||
// If default HTTP or HTTPS ports have been customized,
|
||||
// make sure the ACME challenge ports match
|
||||
var altHTTPPort, altTLSSNIPort string
|
||||
if HTTPPort != DefaultHTTPPort {
|
||||
altHTTPPort = HTTPPort
|
||||
}
|
||||
if HTTPSPort != DefaultHTTPSPort {
|
||||
altTLSSNIPort = HTTPSPort
|
||||
}
|
||||
|
||||
// Save the config to our master list, and key it for lookups
|
||||
cfg := &SiteConfig{
|
||||
Addr: addr,
|
||||
Root: Root,
|
||||
TLS: &caddytls.Config{Hostname: addr.Host},
|
||||
Addr: addr,
|
||||
Root: Root,
|
||||
TLS: &caddytls.Config{
|
||||
Hostname: addr.Host,
|
||||
AltHTTPPort: altHTTPPort,
|
||||
AltTLSSNIPort: altTLSSNIPort,
|
||||
},
|
||||
originCaddyfile: sourceFile,
|
||||
}
|
||||
h.saveConfig(key, cfg)
|
||||
|
@ -154,7 +170,7 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
|
|||
if !cfg.TLS.Enabled {
|
||||
continue
|
||||
}
|
||||
if cfg.Addr.Port == "80" || cfg.Addr.Scheme == "http" {
|
||||
if cfg.Addr.Port == HTTPPort || cfg.Addr.Scheme == "http" {
|
||||
cfg.TLS.Enabled = false
|
||||
log.Printf("[WARNING] TLS disabled for %s", cfg.Addr)
|
||||
} else if cfg.Addr.Scheme == "" {
|
||||
|
@ -169,7 +185,7 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
|
|||
// this is vital, otherwise the function call below that
|
||||
// sets the listener address will use the default port
|
||||
// instead of 443 because it doesn't know about TLS.
|
||||
cfg.Addr.Port = "443"
|
||||
cfg.Addr.Port = HTTPSPort
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +286,7 @@ func (a Address) String() string {
|
|||
}
|
||||
scheme := a.Scheme
|
||||
if scheme == "" {
|
||||
if a.Port == "443" {
|
||||
if a.Port == HTTPSPort {
|
||||
scheme = "https"
|
||||
} else {
|
||||
scheme = "http"
|
||||
|
@ -282,8 +298,8 @@ func (a Address) String() string {
|
|||
}
|
||||
s += a.Host
|
||||
if a.Port != "" &&
|
||||
((scheme == "https" && a.Port != "443") ||
|
||||
(scheme == "http" && a.Port != "80")) {
|
||||
((scheme == "https" && a.Port != DefaultHTTPSPort) ||
|
||||
(scheme == "http" && a.Port != DefaultHTTPPort)) {
|
||||
s += ":" + a.Port
|
||||
}
|
||||
if a.Path != "" {
|
||||
|
@ -327,9 +343,9 @@ func standardizeAddress(str string) (Address, error) {
|
|||
// see if we can set port based off scheme
|
||||
if port == "" {
|
||||
if u.Scheme == "http" {
|
||||
port = "80"
|
||||
port = HTTPPort
|
||||
} else if u.Scheme == "https" {
|
||||
port = "443"
|
||||
port = HTTPSPort
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,17 +355,17 @@ func standardizeAddress(str string) (Address, error) {
|
|||
}
|
||||
|
||||
// error if scheme and port combination violate convention
|
||||
if (u.Scheme == "http" && port == "443") || (u.Scheme == "https" && port == "80") {
|
||||
if (u.Scheme == "http" && port == HTTPSPort) || (u.Scheme == "https" && port == HTTPPort) {
|
||||
return Address{}, fmt.Errorf("[%s] scheme and port violate convention", input)
|
||||
}
|
||||
|
||||
// standardize http and https ports to their respective port numbers
|
||||
if port == "http" {
|
||||
u.Scheme = "http"
|
||||
port = "80"
|
||||
port = HTTPPort
|
||||
} else if port == "https" {
|
||||
u.Scheme = "https"
|
||||
port = "443"
|
||||
port = HTTPSPort
|
||||
}
|
||||
|
||||
return Address{Original: input, Scheme: u.Scheme, Host: host, Port: port, Path: u.Path}, err
|
||||
|
@ -477,6 +493,10 @@ const (
|
|||
DefaultPort = "2015"
|
||||
// DefaultRoot is the default root folder.
|
||||
DefaultRoot = "."
|
||||
// DefaultHTTPPort is the default port for HTTP.
|
||||
DefaultHTTPPort = "80"
|
||||
// DefaultHTTPSPort is the default port for HTTPS.
|
||||
DefaultHTTPSPort = "443"
|
||||
)
|
||||
|
||||
// These "soft defaults" are configurable by
|
||||
|
@ -499,4 +519,10 @@ var (
|
|||
|
||||
// QUIC indicates whether QUIC is enabled or not.
|
||||
QUIC bool
|
||||
|
||||
// HTTPPort is the port to use for HTTP.
|
||||
HTTPPort = DefaultHTTPPort
|
||||
|
||||
// HTTPSPort is the port to use for HTTPS.
|
||||
HTTPSPort = DefaultHTTPSPort
|
||||
)
|
||||
|
|
|
@ -112,33 +112,39 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
|
|||
// Use HTTP and TLS-SNI challenges by default
|
||||
|
||||
// See if HTTP challenge needs to be proxied
|
||||
useHTTPPort := "" // empty port value will use challenge default
|
||||
if caddy.HasListenerWithAddress(net.JoinHostPort(config.ListenHost, HTTPChallengePort)) {
|
||||
useHTTPPort := HTTPChallengePort
|
||||
if config.AltHTTPPort != "" {
|
||||
useHTTPPort = config.AltHTTPPort
|
||||
if useHTTPPort == "" {
|
||||
useHTTPPort = DefaultHTTPAlternatePort
|
||||
}
|
||||
}
|
||||
if caddy.HasListenerWithAddress(net.JoinHostPort(config.ListenHost, useHTTPPort)) {
|
||||
useHTTPPort = DefaultHTTPAlternatePort
|
||||
}
|
||||
|
||||
// See which port TLS-SNI challenges will be accomplished on
|
||||
useTLSSNIPort := TLSSNIChallengePort
|
||||
if config.AltTLSSNIPort != "" {
|
||||
useTLSSNIPort = config.AltTLSSNIPort
|
||||
}
|
||||
|
||||
// Always respect user's bind preferences by using config.ListenHost.
|
||||
// NOTE(Sep'16): At time of writing, SetHTTPAddress() and SetTLSaddress()
|
||||
// NOTE(Sep'16): At time of writing, SetHTTPAddress() and SetTLSAddress()
|
||||
// must be called before SetChallengeProvider(), since they reset the
|
||||
// challenge provider back to the default one!
|
||||
err := c.acmeClient.SetHTTPAddress(net.JoinHostPort(config.ListenHost, useHTTPPort))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.acmeClient.SetTLSAddress(net.JoinHostPort(config.ListenHost, ""))
|
||||
err = c.acmeClient.SetTLSAddress(net.JoinHostPort(config.ListenHost, useTLSSNIPort))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// See if TLS challenge needs to be handled by our own facilities
|
||||
if caddy.HasListenerWithAddress(net.JoinHostPort(config.ListenHost, TLSSNIChallengePort)) {
|
||||
if caddy.HasListenerWithAddress(net.JoinHostPort(config.ListenHost, useTLSSNIPort)) {
|
||||
c.acmeClient.SetChallengeProvider(acme.TLSSNI01, tlsSniSolver{})
|
||||
}
|
||||
} else {
|
||||
// Otherwise, DNS challenge it is
|
||||
// Otherwise, use DNS challenge exclusively
|
||||
|
||||
// Load provider constructor function
|
||||
provFn, ok := dnsProviders[config.DNSProvider]
|
||||
|
|
|
@ -84,6 +84,12 @@ type Config struct {
|
|||
// coming in on port 80 to this alternate port
|
||||
AltHTTPPort string
|
||||
|
||||
// The alternate port (ONLY port, not host)
|
||||
// to use for the ACME TLS-SNI challenge.
|
||||
// The system must forward the standard port
|
||||
// for the TLS-SNI challenge to this port.
|
||||
AltTLSSNIPort string
|
||||
|
||||
// The string identifier of the DNS provider
|
||||
// to use when solving the ACME DNS challenge
|
||||
DNSProvider string
|
||||
|
@ -479,11 +485,11 @@ var defaultCurves = []tls.CurveID{
|
|||
|
||||
const (
|
||||
// HTTPChallengePort is the officially designated port for
|
||||
// the HTTP challenge.
|
||||
// the HTTP challenge according to the ACME spec.
|
||||
HTTPChallengePort = "80"
|
||||
|
||||
// TLSSNIChallengePort is the officially designated port for
|
||||
// the TLS-SNI challenge.
|
||||
// the TLS-SNI challenge according to the ACME spec.
|
||||
TLSSNIChallengePort = "443"
|
||||
|
||||
// DefaultHTTPAlternatePort is the port on which the ACME
|
||||
|
|
Loading…
Reference in a new issue