diff --git a/cmd/web.go b/cmd/web.go index 9a8d9dfa73c8..ee3b44248a35 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -222,8 +222,8 @@ func listen(m http.Handler, handleRedirector bool) error { } err = runHTTP("tcp", listenAddr, "Web", m) case setting.HTTPS: - if setting.EnableLetsEncrypt { - err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, m) + if setting.EnableAcme { + err = runLetsEncrypt(listenAddr, setting.Domain, setting.AcmeLiveDirectory, setting.AcmeEmail, m) break } if handleRedirector { diff --git a/cmd/web_letsencrypt.go b/cmd/web_acme.go similarity index 88% rename from cmd/web_letsencrypt.go rename to cmd/web_acme.go index cc62e756bf01..89c2a33c5206 100644 --- a/cmd/web_letsencrypt.go +++ b/cmd/web_acme.go @@ -38,25 +38,25 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) magic := certmagic.NewDefault() magic.Storage = &certmagic.FileStorage{Path: directory} // Try to use private CA root if provided, otherwise defaults to system's trust - var CertPool *x509.CertPool = nil - if setting.ACMECARoot != "" { - r, err := ioutil.ReadFile(setting.ACMECARoot) + var certPool *x509.CertPool + if setting.AcmeCARoot != "" { + r, err := ioutil.ReadFile(setting.AcmeCARoot) if err != nil { - log.Warn("Failed to read CARoot certificate, using default CA trust: %v", err) + log.Warn("Failed to read CA Root certificate, using default CA trust: %v", err) } else { block, _ := pem.Decode(r) - CARoot, err := x509.ParseCertificate(block.Bytes) + caRoot, err := x509.ParseCertificate(block.Bytes) if err != nil { - log.Warn("Failed to parse CARoot certificate, using default CA trust: %v", err) + log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) } else { - CertPool = x509.NewCertPool() - CertPool.AddCert(CARoot) + certPool = x509.NewCertPool() + certPool.AddCert(caRoot) } } } myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{ - CA: setting.ACMECAURL, - TrustedRoots: CertPool, + CA: setting.AcmeURL, + TrustedRoots: certPool, Email: email, Agreed: setting.LetsEncryptTOS, DisableHTTPChallenge: !enableHTTPChallenge, diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 3343af95a975..b6ab49f90a28 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -175,6 +175,32 @@ RUN_MODE = ; prod ;OFFLINE_MODE = false ;DISABLE_ROUTER_LOG = false ;; +;; TLS Settings: Either ACME or manual +;; (Other common TLS configuration are found before) +;ENABLE_ACME = false +;; +;; ACME automatic TLS settings: +;; +;; ACME directory URL (e.g. LetsEncrypt's staging/testing URL: https://acme-staging-v02.api.letsencrypt.org/directory) +;; Leave empty to default to LetsEncrypt's (production) URL +;ACME_URL = +;; +;; If using LetsEncrypt please read their TOS and manually change this setting to true +;LETSENCRYPT_ACCEPTTOS = false +;; +;; If the ACME CA is not in your system's CA trust chain, it can be manually added here +;ACME_CA_ROOT = +;; +;; Email used for the ACME registration service +;; Can be left blank to initialize at first run and use the cached value +;ACME_EMAIL = +;; +;; ACME live directory (not to be confused with ACME directory URL: ACME_URL) +;; (Refer to caddy's ACME manager https://github.com/caddyserver/certmagic) +;ACME_DIRECTORY = https +;; +;; +;; Manual TLS settings: (Only applicable if ENABLE_ACME=false) ;; Generate steps: ;; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com ;; diff --git a/modules/setting/setting.go b/modules/setting/setting.go index c962c5cd1045..5cc4dbd83b24 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -109,12 +109,12 @@ var ( UnixSocketPermission uint32 EnablePprof bool PprofDataPath string - EnableLetsEncrypt bool + EnableAcme bool LetsEncryptTOS bool - LetsEncryptDirectory string - LetsEncryptEmail string - ACMECAURL string - ACMECARoot string + AcmeLiveDirectory string + AcmeEmail string + AcmeURL string + AcmeCARoot string SSLMinimumVersion string SSLMaximumVersion string SSLCurvePreferences []string @@ -624,14 +624,49 @@ func loadFromConf(allowEmpty bool, extraConfig string) { switch protocolCfg { case "https": Protocol = HTTPS - CertFile = sec.Key("CERT_FILE").String() - KeyFile = sec.Key("KEY_FILE").String() - if !filepath.IsAbs(CertFile) && len(CertFile) > 0 { - CertFile = filepath.Join(CustomPath, CertFile) + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ENABLE_ACME") { + EnableAcme = sec.Key("ENABLE_ACME").MustBool(false) + } else { + deprecatedSetting("server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME") + EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) } - if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 { - KeyFile = filepath.Join(CustomPath, KeyFile) + if EnableAcme { + AcmeURL = sec.Key("ACME_URL").MustString("") + AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("") + LetsEncryptTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false) + // The TOS is only required when using LetsEncrypt + if AcmeURL == "" && !LetsEncryptTOS { + log.Fatal("Let's Encrypt TOS (LETSENCRYPT_ACCEPTTOS) is not accepted. Either accept it or configure a different ACME provider (ACME_URL)") + } + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ACME_DIRECTORY") { + AcmeLiveDirectory = sec.Key("ACME_DIRECTORY").MustString("https") + } else { + deprecatedSetting("server", "LETSENCRYPT_DIRECTORY", "server", "ACME_DIRECTORY") + AcmeLiveDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https") + } + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ACME_EMAIL") { + AcmeEmail = sec.Key("ACME_EMAIL").MustString("") + } else { + deprecatedSetting("server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL") + AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") + } + } else { + CertFile = sec.Key("CERT_FILE").String() + KeyFile = sec.Key("KEY_FILE").String() + if !filepath.IsAbs(CertFile) && len(CertFile) > 0 { + CertFile = filepath.Join(CustomPath, CertFile) + } + if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 { + KeyFile = filepath.Join(CustomPath, KeyFile) + } } + SSLMinimumVersion = sec.Key("SSL_MIN_VERSION").MustString("") + SSLMaximumVersion = sec.Key("SSL_MAX_VERSION").MustString("") + SSLCurvePreferences = sec.Key("SSL_CURVE_PREFERENCES").Strings(",") + SSLCipherSuites = sec.Key("SSL_CIPHER_SUITES").Strings(",") case "fcgi": Protocol = FCGI case "fcgi+unix", "unix", "http+unix": @@ -655,20 +690,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) { HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr) } } - EnableLetsEncrypt = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) - ACMECAURL = sec.Key("ACME_CAURL").MustString("") - ACMECARoot = sec.Key("ACME_CARoot").MustString("") - LetsEncryptTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false) - if !LetsEncryptTOS && EnableLetsEncrypt { - log.Warn("Failed to enable Let's Encrypt due to Let's Encrypt TOS not being accepted") - EnableLetsEncrypt = false - } - LetsEncryptDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https") - LetsEncryptEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") - SSLMinimumVersion = sec.Key("SSL_MIN_VERSION").MustString("") - SSLMaximumVersion = sec.Key("SSL_MAX_VERSION").MustString("") - SSLCurvePreferences = sec.Key("SSL_CURVE_PREFERENCES").Strings(",") - SSLCipherSuites = sec.Key("SSL_CIPHER_SUITES").Strings(",") GracefulRestartable = sec.Key("ALLOW_GRACEFUL_RESTARTS").MustBool(true) GracefulHammerTime = sec.Key("GRACEFUL_HAMMER_TIME").MustDuration(60 * time.Second) StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(0 * time.Second)