diff --git a/caddy/caddy.go b/caddy/caddy.go index 8500d7945..e88876322 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -83,7 +83,7 @@ var ( const ( // DefaultHost is the default host. - DefaultHost = "0.0.0.0" + DefaultHost = "" // DefaultPort is the default port. DefaultPort = "2015" // DefaultRoot is the default root folder. diff --git a/caddy/config.go b/caddy/config.go index dacd57248..5819fea88 100644 --- a/caddy/config.go +++ b/caddy/config.go @@ -331,22 +331,18 @@ func validDirective(d string) bool { return false } -// NewDefault makes a default configuration, which -// is empty except for root, host, and port, -// which are essentials for serving the cwd. -func NewDefault() server.Config { - return server.Config{ - Root: Root, - Host: Host, - Port: Port, - } -} - // DefaultInput returns the default Caddyfile input // to use when it is otherwise empty or missing. +// It uses the default host and port (depends on +// host, e.g. localhost is 2015, otherwise https) and +// root. func DefaultInput() CaddyfileInput { + port := Port + if letsencrypt.HostQualifies(Host) { + port = "https" + } return CaddyfileInput{ - Contents: []byte(fmt.Sprintf("%s:%s\nroot %s", Host, Port, Root)), + Contents: []byte(fmt.Sprintf("%s:%s\nroot %s", Host, port, Root)), } } diff --git a/caddy/config_test.go b/caddy/config_test.go index 3df0b5cc9..3e70a9311 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -8,17 +8,26 @@ import ( "github.com/mholt/caddy/server" ) -func TestNewDefault(t *testing.T) { - config := NewDefault() +func TestDefaultInput(t *testing.T) { + if actual, expected := string(DefaultInput().Body()), ":2015\nroot ."; actual != expected { + t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual) + } - if actual, expected := config.Root, DefaultRoot; actual != expected { - t.Errorf("Root was %s but expected %s", actual, expected) + // next few tests simulate user providing -host flag + + Host = "not-localhost.com" + if actual, expected := string(DefaultInput().Body()), "not-localhost.com:https\nroot ."; actual != expected { + t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual) } - if actual, expected := config.Host, DefaultHost; actual != expected { - t.Errorf("Host was %s but expected %s", actual, expected) + + Host = "[::1]" + if actual, expected := string(DefaultInput().Body()), "[::1]:2015\nroot ."; actual != expected { + t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual) } - if actual, expected := config.Port, DefaultPort; actual != expected { - t.Errorf("Port was %s but expected %s", actual, expected) + + Host = "127.0.1.1" + if actual, expected := string(DefaultInput().Body()), "127.0.1.1:2015\nroot ."; actual != expected { + t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual) } } diff --git a/caddy/letsencrypt/letsencrypt.go b/caddy/letsencrypt/letsencrypt.go index 27c084b57..f3f9fde7a 100644 --- a/caddy/letsencrypt/letsencrypt.go +++ b/caddy/letsencrypt/letsencrypt.go @@ -166,17 +166,29 @@ func configQualifies(allConfigs []server.Config, cfgIndex int) bool { cfg.TLS.LetsEncryptEmail != "off" && // obviously we get can't certs for loopback or internal hosts - cfg.Host != "localhost" && - cfg.Host != "" && - cfg.Host != "0.0.0.0" && - cfg.Host != "::1" && - !strings.HasPrefix(cfg.Host, "127.") && // to use boulder on your own machine, add fake domain to hosts file - // not excluding 10.* and 192.168.* hosts for possibility of running internal Boulder instance + HostQualifies(cfg.Host) && // make sure another HTTPS version of this config doesn't exist in the list already !otherHostHasScheme(allConfigs, cfgIndex, "https") } +// HostQualifies returns true if the hostname alone +// appears eligible for automatic HTTPS. For example, +// localhost, empty hostname, and wildcard hosts are +// not eligible because we cannot obtain certificates +// for those names. +func HostQualifies(hostname string) bool { + return hostname != "localhost" && + strings.TrimSpace(hostname) != "" && + hostname != "0.0.0.0" && + hostname != "[::]" && // before parsing + hostname != "::" && // after parsing + hostname != "[::1]" && // before parsing + hostname != "::1" && // after parsing + !strings.HasPrefix(hostname, "127.") // to use boulder on your own machine, add fake domain to hosts file + // not excluding 10.* and 192.168.* hosts for possibility of running internal Boulder instance +} + // groupConfigsByEmail groups configs by user email address. The returned map is // a map of email address to the configs that are serviced under that account. // If an email address is not available for an eligible config, the user will be @@ -273,12 +285,10 @@ func newClientPort(leEmail, port string) (*acme.Client, error) { // obtainCertificates obtains certificates from the CA server for // the configurations in serverConfigs using client. func obtainCertificates(client *acme.Client, serverConfigs []server.Config) ([]acme.CertificateResource, map[string]error) { - // collect all the hostnames into one slice var hosts []string for _, cfg := range serverConfigs { hosts = append(hosts, cfg.Host) } - return client.ObtainCertificates(hosts, true) } diff --git a/caddy/letsencrypt/letsencrypt_test.go b/caddy/letsencrypt/letsencrypt_test.go index 841ec54bc..dd243c0be 100644 --- a/caddy/letsencrypt/letsencrypt_test.go +++ b/caddy/letsencrypt/letsencrypt_test.go @@ -8,6 +8,34 @@ import ( "github.com/mholt/caddy/server" ) +func TestHostQualifies(t *testing.T) { + for i, test := range []struct { + host string + expect bool + }{ + {"localhost", false}, + {"127.0.0.1", false}, + {"127.0.1.5", false}, + {"::1", false}, + {"[::1]", false}, + {"[::]", false}, + {"::", false}, + {"", false}, + {" ", false}, + {"0.0.0.0", false}, + {"192.168.1.3", true}, + {"10.0.2.1", true}, + {"foobar.com", true}, + } { + if HostQualifies(test.host) && !test.expect { + t.Errorf("Test %d: Expected '%s' to NOT qualify, but it did", i, test.host) + } + if !HostQualifies(test.host) && test.expect { + t.Errorf("Test %d: Expected '%s' to qualify, but it did NOT", i, test.host) + } + } +} + func TestRedirPlaintextHost(t *testing.T) { cfg := redirPlaintextHost(server.Config{ Host: "example.com",