diff --git a/caddy/letsencrypt/letsencrypt.go b/caddy/letsencrypt/letsencrypt.go index 92fa10a36..d6fb9cc37 100644 --- a/caddy/letsencrypt/letsencrypt.go +++ b/caddy/letsencrypt/letsencrypt.go @@ -131,7 +131,7 @@ func ObtainCerts(configs []server.Config, altPort string) error { } for _, cfg := range group { - if existingCertAndKey(cfg.Host) { + if cfg.Host == "" || existingCertAndKey(cfg.Host) { continue } @@ -170,8 +170,10 @@ func EnableTLS(configs []server.Config) { continue } configs[i].TLS.Enabled = true - configs[i].TLS.Certificate = storage.SiteCertFile(configs[i].Host) - configs[i].TLS.Key = storage.SiteKeyFile(configs[i].Host) + if configs[i].Host != "" { + configs[i].TLS.Certificate = storage.SiteCertFile(configs[i].Host) + configs[i].TLS.Key = storage.SiteKeyFile(configs[i].Host) + } setup.SetDefaultTLSParams(&configs[i]) } } @@ -257,13 +259,15 @@ func ConfigQualifies(cfg server.Config) bool { cfg.Port != "80" && cfg.TLS.LetsEncryptEmail != "off" && - // we get can't certs for some kinds of hostnames - HostQualifies(cfg.Host) + // we get can't certs for some kinds of hostnames, + // but we CAN get certs at request-time even if + // the hostname in the config is empty right now. + (cfg.Host == "" || HostQualifies(cfg.Host)) } // HostQualifies returns true if the hostname alone // appears eligible for automatic HTTPS. For example, -// localhost, empty hostname, and wildcard hosts are +// localhost, empty hostname, and IP addresses are // not eligible because we cannot obtain certificates // for those names. func HostQualifies(hostname string) bool { @@ -397,7 +401,7 @@ func saveCertResource(cert acme.CertificateResource) error { // be the HTTPS configuration. The returned configuration is set // to listen on port 80. func redirPlaintextHost(cfg server.Config) server.Config { - toURL := "https://" + cfg.Host + toURL := "https://{host}" // serve any host, since cfg.Host could be empty if cfg.Port != "443" && cfg.Port != "80" { toURL += ":" + cfg.Port } diff --git a/caddy/letsencrypt/letsencrypt_test.go b/caddy/letsencrypt/letsencrypt_test.go index 2cce94058..e3ac2212e 100644 --- a/caddy/letsencrypt/letsencrypt_test.go +++ b/caddy/letsencrypt/letsencrypt_test.go @@ -46,6 +46,7 @@ func TestConfigQualifies(t *testing.T) { cfg server.Config expect bool }{ + {server.Config{Host: ""}, true}, {server.Config{Host: "localhost"}, false}, {server.Config{Host: "example.com"}, true}, {server.Config{Host: "example.com", TLS: server.TLSConfig{Certificate: "cert.pem"}}, false}, @@ -105,18 +106,18 @@ func TestRedirPlaintextHost(t *testing.T) { if actual, expected := handler.Rules[0].FromPath, "/"; actual != expected { t.Errorf("Expected redirect rule to be for path '%s' but is actually for '%s'", expected, actual) } - if actual, expected := handler.Rules[0].To, "https://example.com:1234{uri}"; actual != expected { + if actual, expected := handler.Rules[0].To, "https://{host}:1234{uri}"; actual != expected { t.Errorf("Expected redirect rule to be to URL '%s' but is actually to '%s'", expected, actual) } if actual, expected := handler.Rules[0].Code, http.StatusMovedPermanently; actual != expected { t.Errorf("Expected redirect rule to have code %d but was %d", expected, actual) } - // browsers can interpret default ports with scheme, so make sure the port - // doesn't get added in explicitly for default ports. + // 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(server.Config{Host: "example.com", Port: "443"}) handler, ok = cfg.Middleware["/"][0](nil).(redirect.Redirect) - if actual, expected := handler.Rules[0].To, "https://example.com{uri}"; actual != expected { + if actual, expected := handler.Rules[0].To, "https://{host}{uri}"; actual != expected { t.Errorf("(Default Port) Expected redirect rule to be to URL '%s' but is actually to '%s'", expected, actual) } } @@ -252,7 +253,7 @@ func TestMakePlaintextRedirects(t *testing.T) { func TestEnableTLS(t *testing.T) { configs := []server.Config{ - server.Config{TLS: server.TLSConfig{Managed: true}}, + server.Config{Host: "example.com", TLS: server.TLSConfig{Managed: true}}, server.Config{}, // not managed - no changes! } @@ -325,8 +326,9 @@ func TestMarkQualified(t *testing.T) { {Host: "example.com", Port: "1234"}, {Host: "example.com", Scheme: "https"}, {Host: "example.com", Port: "80", Scheme: "https"}, + {Host: ""}, } - expectedManagedCount := 4 + expectedManagedCount := 5 MarkQualified(configs) diff --git a/caddy/letsencrypt/user.go b/caddy/letsencrypt/user.go index fca50ec9c..1fac1d71d 100644 --- a/caddy/letsencrypt/user.go +++ b/caddy/letsencrypt/user.go @@ -154,10 +154,11 @@ func getEmail(cfg server.Config, skipPrompt bool) string { if err != nil { return "" } + leEmail = strings.TrimSpace(leEmail) DefaultEmail = leEmail Agreed = true } - return strings.TrimSpace(leEmail) + return leEmail } // promptUserAgreement prompts the user to agree to the agreement