From eb2dc85016f282975d011c9f6598be4c1187607f Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Thu, 20 Jan 2022 17:53:12 +0900 Subject: [PATCH 01/15] Added ACMECAURL option to support custom ACME provider Closes #18306 Signed-off-by: Cristian Le --- cmd/web_letsencrypt.go | 22 ++++++++++++++++++++++ modules/setting/setting.go | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/cmd/web_letsencrypt.go b/cmd/web_letsencrypt.go index 517d71f0172c..cc62e756bf01 100644 --- a/cmd/web_letsencrypt.go +++ b/cmd/web_letsencrypt.go @@ -5,6 +5,9 @@ package cmd import ( + "crypto/x509" + "encoding/pem" + "io/ioutil" "net/http" "strconv" "strings" @@ -34,7 +37,26 @@ 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) + if err != nil { + log.Warn("Failed to read CARoot certificate, using default CA trust: %v", err) + } else { + block, _ := pem.Decode(r) + CARoot, err := x509.ParseCertificate(block.Bytes) + if err != nil { + log.Warn("Failed to parse CARoot certificate, using default CA trust: %v", err) + } else { + CertPool = x509.NewCertPool() + CertPool.AddCert(CARoot) + } + } + } myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{ + CA: setting.ACMECAURL, + TrustedRoots: CertPool, Email: email, Agreed: setting.LetsEncryptTOS, DisableHTTPChallenge: !enableHTTPChallenge, diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 5b8683f57838..c962c5cd1045 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -113,6 +113,8 @@ var ( LetsEncryptTOS bool LetsEncryptDirectory string LetsEncryptEmail string + ACMECAURL string + ACMECARoot string SSLMinimumVersion string SSLMaximumVersion string SSLCurvePreferences []string @@ -654,6 +656,8 @@ func loadFromConf(allowEmpty bool, extraConfig string) { } } 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") From 11f0ef8687aaa89aae6dae28eea732c519e0c552 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Fri, 21 Jan 2022 14:34:04 +0900 Subject: [PATCH 02/15] Refactor setting.go https settings, renamed options and variables, and documented app.example.ini Signed-off-by: Cristian Le --- cmd/web.go | 4 +- cmd/{web_letsencrypt.go => web_acme.go} | 20 +++---- custom/conf/app.example.ini | 26 +++++++++ modules/setting/setting.go | 71 ++++++++++++++++--------- 4 files changed, 84 insertions(+), 37 deletions(-) rename cmd/{web_letsencrypt.go => web_acme.go} (88%) 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) From 4350b76ea38245627bb88c7c413c10844c5e41f0 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Fri, 21 Jan 2022 14:40:23 +0900 Subject: [PATCH 03/15] Refactored runLetsEncrypt to runACME Signed-off-by: Cristian Le --- cmd/web.go | 17 +++++++++-------- cmd/web_acme.go | 8 ++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cmd/web.go b/cmd/web.go index ee3b44248a35..710c12775fd0 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -223,17 +223,18 @@ func listen(m http.Handler, handleRedirector bool) error { err = runHTTP("tcp", listenAddr, "Web", m) case setting.HTTPS: if setting.EnableAcme { - err = runLetsEncrypt(listenAddr, setting.Domain, setting.AcmeLiveDirectory, setting.AcmeEmail, m) + err = runACME(listenAddr, m) break - } - if handleRedirector { - if setting.RedirectOtherPort { - go runHTTPRedirector() - } else { - NoHTTPRedirector() + } else { + if handleRedirector { + if setting.RedirectOtherPort { + go runHTTPRedirector() + } else { + NoHTTPRedirector() + } } + err = runHTTPS("tcp", listenAddr, "Web", setting.CertFile, setting.KeyFile, m) } - err = runHTTPS("tcp", listenAddr, "Web", setting.CertFile, setting.KeyFile, m) case setting.FCGI: if handleRedirector { NoHTTPRedirector() diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 89c2a33c5206..7ab24e012e13 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -19,7 +19,7 @@ import ( "github.com/caddyserver/certmagic" ) -func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error { +func runACME(listenAddr string, m http.Handler) error { // If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443. // Due to docker port mapping this can't be checked programmatically // TODO: these are placeholders until we add options for each in settings with appropriate warning @@ -36,7 +36,7 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) } magic := certmagic.NewDefault() - magic.Storage = &certmagic.FileStorage{Path: directory} + magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory} // Try to use private CA root if provided, otherwise defaults to system's trust var certPool *x509.CertPool if setting.AcmeCARoot != "" { @@ -57,7 +57,7 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{ CA: setting.AcmeURL, TrustedRoots: certPool, - Email: email, + Email: setting.AcmeEmail, Agreed: setting.LetsEncryptTOS, DisableHTTPChallenge: !enableHTTPChallenge, DisableTLSALPNChallenge: !enableTLSALPNChallenge, @@ -69,7 +69,7 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) magic.Issuers = []certmagic.Issuer{myACME} // this obtains certificates or renews them if necessary - err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{domain}) + err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{setting.Domain}) if err != nil { return err } From 21a57c7aa8e51d14f122de5fcf5f1c227353dbdd Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Fri, 21 Jan 2022 16:49:42 +0900 Subject: [PATCH 04/15] Updated the documentation and switched off TLS ALPN challenge as it's not implemented yet. Signed-off-by: Cristian Le --- cmd/web_acme.go | 2 +- .../doc/advanced/config-cheat-sheet.en-us.md | 15 ++++++----- docs/content/doc/usage/https-support.md | 27 ++++++++++++++----- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 7ab24e012e13..334cfe2e1125 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -24,7 +24,7 @@ func runACME(listenAddr string, m http.Handler) error { // Due to docker port mapping this can't be checked programmatically // TODO: these are placeholders until we add options for each in settings with appropriate warning enableHTTPChallenge := true - enableTLSALPNChallenge := true + enableTLSALPNChallenge := false altHTTPPort := 0 altTLSALPNPort := 0 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index d8a3b897cc01..8ff3a058f429 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -291,8 +291,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type. - `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures. -- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). From 1.11 paths are relative to `CUSTOM_PATH`. -- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`. +- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`. +- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`. - `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. - `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. - `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev". @@ -346,11 +346,12 @@ The following configuration set `Content-Type: application/vnd.android.package-a - Aliased names - "ecdhe_rsa_with_chacha20_poly1305" is an alias for "ecdhe_rsa_with_chacha20_poly1305_sha256" - "ecdhe_ecdsa_with_chacha20_poly1305" is alias for "ecdhe_ecdsa_with_chacha20_poly1305_sha256" -- `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server). - By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). -- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt. -- `LETSENCRYPT_DIRECTORY`: **https**: Directory that Letsencrypt will use to cache information such as certs and private keys. -- `LETSENCRYPT_EMAIL`: **email@example.com**: Email used by Letsencrypt to notify about problems with issued certificates. (No default) +- `ENABLE_ACME`: **false**: Flag to enable automatic certificate management via an ACME capable Certificate Authority (CA) server (default: Lets Encrypt). If enabled, `CERT_FILE` and `KEY_FILE` are ignored, and the CA must resolve `DOMAIN` to this gitea server (ensure DNS records are set and port 80 is accessible by the CA server (the public internet by default)). +- `ACME_URL`: **\**: The CA's ACME directory URL, e.g. for a self-hosted [smallstep CA server](https://github.com/smallstep/certificates), it can look like `https://ca.example.com/acme/acme/directory`. If left empty, it defaults to using Let's Encerypt's production CA (check `LETSENCRYPT_ACCEPTTOS` as well). +- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt. By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). +- `ACME_DIRECTORY`: **https**: Directory that the certificate manager will use to cache information such as certs and private keys. +- `ACME_EMAIL`: **\**: Email used for the ACME registration. Usually it is to notify about problems with issued certificates. +- `ACME_CA_ROOT`: **\**: The CA's root certificate. If left empty, it defaults to using the system's trust chain. - `ALLOW_GRACEFUL_RESTARTS`: **true**: Perform a graceful restart on SIGHUP - `GRACEFUL_HAMMER_TIME`: **60s**: After a restart the parent process will stop accepting new connections and will allow requests to finish before stopping. Shutdown will be forced if it takes longer than this time. - `STARTUP_TIMEOUT`: **0**: Shutsdown the server if startup takes longer than the provided time. On Windows setting this sends a waithint to the SVC host to tell the SVC host startup may take some time. Please note startup is determined by the opening of the listeners - HTTP/HTTPS/SSH. Indexers may take longer to startup and can have their own timeouts. diff --git a/docs/content/doc/usage/https-support.md b/docs/content/doc/usage/https-support.md index d7563a0f08f4..f47eb4242ac0 100644 --- a/docs/content/doc/usage/https-support.md +++ b/docs/content/doc/usage/https-support.md @@ -55,20 +55,33 @@ PORT_TO_REDIRECT = 3080 If you are using Docker, make sure that this port is configured in your `docker-compose.yml` file. -## Using Let's Encrypt +## Using ACME (Default: Let's Encrypt) -[Let's Encrypt](https://letsencrypt.org/) is a Certificate Authority that allows you to automatically request and renew SSL/TLS certificates. In addition to starting Gitea on your configured port, to request HTTPS certificates, Gitea will also need to listed on port 80, and will set up an autoredirect to HTTPS for you. Let's Encrypt will need to be able to access Gitea via the Internet to verify your ownership of the domain. - -By using Let's Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). +[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Currently only the `HTTP-01` challenge is implemented, so gitea needs to listen on port 80 to answer the ACME challenge and verify your domain ownership. Setting up [HTTP redirection](#setting-up-http-redirection) might be needed. Normal traffic to port 80 will otherwise be automatically redirected to HTTPS. +If you are using the default Let's Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). Refer to the following configuration for the minimum setup: ```ini [server] PROTOCOL=https DOMAIN=git.example.com -ENABLE_LETSENCRYPT=true +ENABLE_ACME=true LETSENCRYPT_ACCEPTTOS=true -LETSENCRYPT_DIRECTORY=https -LETSENCRYPT_EMAIL=email@example.com +ACME_DIRECTORY=https +;; Email can be omitted here and provided manually at first run, after which it is cached +ACME_EMAIL=email@example.com +``` + +For generic ACME setup, you are responsible to adhere to the terms of service of the ACME server you are configuring for. The following is an example configuration using [smallstep CA](https://github.com/smallstep/certificates), refer to [their tutorial](https://smallstep.com/docs/tutorials/acme-challenge) for more information. +```ini +[server] +PROTOCOL=https +DOMAIN=git.example.com +ENABLE_ACME=true +ACME_URL=https://ca.example.com/acme/acme/directory +;; Can be omitted if using the system's trust is preferred +;ACME_CA_ROOT=/path/to/root_ca.crt +ACME_DIRECTORY=https +ACME_EMAIL=email@example.com ``` To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server-server). From cc43ff6bf37ecd1467fffc868fe46739d702113b Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Fri, 21 Jan 2022 17:54:14 +0900 Subject: [PATCH 05/15] TLS ALPN challenge is actually used, but it is not documented. Reverted the previous change Signed-off-by: Cristian Le --- cmd/web_acme.go | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- docs/content/doc/usage/https-support.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 334cfe2e1125..7ab24e012e13 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -24,7 +24,7 @@ func runACME(listenAddr string, m http.Handler) error { // Due to docker port mapping this can't be checked programmatically // TODO: these are placeholders until we add options for each in settings with appropriate warning enableHTTPChallenge := true - enableTLSALPNChallenge := false + enableTLSALPNChallenge := true altHTTPPort := 0 altTLSALPNPort := 0 diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 8ff3a058f429..9dc52e794e25 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -346,7 +346,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - Aliased names - "ecdhe_rsa_with_chacha20_poly1305" is an alias for "ecdhe_rsa_with_chacha20_poly1305_sha256" - "ecdhe_ecdsa_with_chacha20_poly1305" is alias for "ecdhe_ecdsa_with_chacha20_poly1305_sha256" -- `ENABLE_ACME`: **false**: Flag to enable automatic certificate management via an ACME capable Certificate Authority (CA) server (default: Lets Encrypt). If enabled, `CERT_FILE` and `KEY_FILE` are ignored, and the CA must resolve `DOMAIN` to this gitea server (ensure DNS records are set and port 80 is accessible by the CA server (the public internet by default)). +- `ENABLE_ACME`: **false**: Flag to enable automatic certificate management via an ACME capable Certificate Authority (CA) server (default: Lets Encrypt). If enabled, `CERT_FILE` and `KEY_FILE` are ignored, and the CA must resolve `DOMAIN` to this gitea server. Ensure that DNS records are set and either port `80` or port `443` are accessible by the CA server (the public internet by default), and redirected to the appropriate ports `PORT_TO_REDIRECT` or `HTTP_PORT` respectively. - `ACME_URL`: **\**: The CA's ACME directory URL, e.g. for a self-hosted [smallstep CA server](https://github.com/smallstep/certificates), it can look like `https://ca.example.com/acme/acme/directory`. If left empty, it defaults to using Let's Encerypt's production CA (check `LETSENCRYPT_ACCEPTTOS` as well). - `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt. By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). - `ACME_DIRECTORY`: **https**: Directory that the certificate manager will use to cache information such as certs and private keys. diff --git a/docs/content/doc/usage/https-support.md b/docs/content/doc/usage/https-support.md index f47eb4242ac0..692b6b65edc0 100644 --- a/docs/content/doc/usage/https-support.md +++ b/docs/content/doc/usage/https-support.md @@ -57,7 +57,7 @@ If you are using Docker, make sure that this port is configured in your `docker- ## Using ACME (Default: Let's Encrypt) -[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Currently only the `HTTP-01` challenge is implemented, so gitea needs to listen on port 80 to answer the ACME challenge and verify your domain ownership. Setting up [HTTP redirection](#setting-up-http-redirection) might be needed. Normal traffic to port 80 will otherwise be automatically redirected to HTTPS. +[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Only `HTTP-01` and `TLS-ALPN-01` challenges are implemented. In order for ACME challenges to pass and verify your domain ownership, external traffic to the gitea domain on port `80` (`HTTP-01`) or port `443` (`TLS-ALPN-01`) has to be served by the gitea instance. Setting up [HTTP redirection](#setting-up-http-redirection) and port-forwards might be needed for external traffic to route correctly. Normal traffic to port `80` will otherwise be automatically redirected to HTTPS. If you are using the default Let's Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). Refer to the following configuration for the minimum setup: ```ini From 8045ff5b6ed11cbb3eaee77db30ee866bc074254 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:24:28 +0800 Subject: [PATCH 06/15] Update modules/setting/setting.go Co-authored-by: Gusted --- modules/setting/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 5cc4dbd83b24..412d1d469f2d 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -656,7 +656,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { } else { CertFile = sec.Key("CERT_FILE").String() KeyFile = sec.Key("KEY_FILE").String() - if !filepath.IsAbs(CertFile) && len(CertFile) > 0 { + if len(CertFile) > 0 && !filepath.IsAbs(CertFile) { CertFile = filepath.Join(CustomPath, CertFile) } if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 { From 816fe981733152ed2145ac735ddd3866e7881efb Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:24:37 +0800 Subject: [PATCH 07/15] Update modules/setting/setting.go Co-authored-by: Gusted --- modules/setting/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 412d1d469f2d..df0c92f7163d 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -659,7 +659,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { if len(CertFile) > 0 && !filepath.IsAbs(CertFile) { CertFile = filepath.Join(CustomPath, CertFile) } - if !filepath.IsAbs(KeyFile) && len(KeyFile) > 0 { + if len(KeyFile) > 0 && !filepath.IsAbs(KeyFile) { KeyFile = filepath.Join(CustomPath, KeyFile) } } From ba01a220a801873f198b5db6e5b37cf452bc874d Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:24:46 +0800 Subject: [PATCH 08/15] Update cmd/web_acme.go Co-authored-by: Gusted --- cmd/web_acme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 7ab24e012e13..1bd76f260d6e 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -40,7 +40,7 @@ func runACME(listenAddr string, m http.Handler) error { // Try to use private CA root if provided, otherwise defaults to system's trust var certPool *x509.CertPool if setting.AcmeCARoot != "" { - r, err := ioutil.ReadFile(setting.AcmeCARoot) + r, err := os.ReadFile(setting.AcmeCARoot) if err != nil { log.Warn("Failed to read CA Root certificate, using default CA trust: %v", err) } else { From c2f0a1dfd10827a3c2344868b170bf495f189c65 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:24:51 +0800 Subject: [PATCH 09/15] Update cmd/web_acme.go Co-authored-by: Gusted --- cmd/web_acme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 1bd76f260d6e..ca20c1062564 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -7,7 +7,7 @@ package cmd import ( "crypto/x509" "encoding/pem" - "io/ioutil" + "os" "net/http" "strconv" "strings" From 321fa92f704936218093620935847b0d58613ae1 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:25:00 +0800 Subject: [PATCH 10/15] Update custom/conf/app.example.ini Co-authored-by: Gusted --- custom/conf/app.example.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b6ab49f90a28..e74b67a93839 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -179,7 +179,9 @@ RUN_MODE = ; prod ;; (Other common TLS configuration are found before) ;ENABLE_ACME = false ;; -;; ACME automatic TLS settings: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 From 31ed266ab87c01f77bf3779a762300b0b611d0c1 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:25:07 +0800 Subject: [PATCH 11/15] Update custom/conf/app.example.ini Co-authored-by: Gusted --- custom/conf/app.example.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index e74b67a93839..014dd4bcf50d 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -201,8 +201,10 @@ RUN_MODE = ; prod ;; (Refer to caddy's ACME manager https://github.com/caddyserver/certmagic) ;ACME_DIRECTORY = https ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Manual TLS settings: (Only applicable if ENABLE_ACME=false) ;; -;; Manual TLS settings: (Only applicable if ENABLE_ACME=false) ;; Generate steps: ;; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com ;; From 572c88af4547c0334d362a59be14d3f4c480f31e Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Jan 2022 23:28:03 +0800 Subject: [PATCH 12/15] Update cmd/web_acme.go Co-authored-by: Gusted --- cmd/web_acme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index ca20c1062564..f6f2de1660d6 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -7,8 +7,8 @@ package cmd import ( "crypto/x509" "encoding/pem" - "os" "net/http" + "os" "strconv" "strings" From f96f2061ae31396e68646c9cef14616ec7d841cc Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Mon, 31 Jan 2022 12:00:30 +0900 Subject: [PATCH 13/15] Changed setting to `ACME_ACCEPTTOS` and improved CA root reading Signed-off-by: Cristian Le --- cmd/web_acme.go | 35 +++++++++++++++++++++++------------ modules/setting/setting.go | 15 ++++++++++----- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/cmd/web_acme.go b/cmd/web_acme.go index f6f2de1660d6..9a04274db580 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -7,6 +7,7 @@ package cmd import ( "crypto/x509" "encoding/pem" + "fmt" "net/http" "os" "strconv" @@ -19,6 +20,24 @@ import ( "github.com/caddyserver/certmagic" ) +func getCARoot(path string) (*x509.CertPool, error) { + r, err := os.ReadFile(path) + if err != nil { + return nil, err + } + block, _ := pem.Decode(r) + if block == nil { + return nil, fmt.Errorf("no PEM found in the file %s", path) + } + caRoot, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + certPool := x509.NewCertPool() + certPool.AddCert(caRoot) + return certPool, nil +} + func runACME(listenAddr string, m http.Handler) error { // If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443. // Due to docker port mapping this can't be checked programmatically @@ -40,25 +59,17 @@ func runACME(listenAddr string, m http.Handler) error { // Try to use private CA root if provided, otherwise defaults to system's trust var certPool *x509.CertPool if setting.AcmeCARoot != "" { - r, err := os.ReadFile(setting.AcmeCARoot) + var err error + certPool, err = getCARoot(setting.AcmeCARoot) if err != nil { - 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) - if err != nil { - log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) - } else { - certPool = x509.NewCertPool() - certPool.AddCert(caRoot) - } + log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) } } myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{ CA: setting.AcmeURL, TrustedRoots: certPool, Email: setting.AcmeEmail, - Agreed: setting.LetsEncryptTOS, + Agreed: setting.AcmeTOS, DisableHTTPChallenge: !enableHTTPChallenge, DisableTLSALPNChallenge: !enableTLSALPNChallenge, ListenHost: setting.HTTPAddr, diff --git a/modules/setting/setting.go b/modules/setting/setting.go index df0c92f7163d..d2ae789bab02 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -110,7 +110,7 @@ var ( EnablePprof bool PprofDataPath string EnableAcme bool - LetsEncryptTOS bool + AcmeTOS bool AcmeLiveDirectory string AcmeEmail string AcmeURL string @@ -634,10 +634,15 @@ func loadFromConf(allowEmpty bool, extraConfig string) { 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_ACCEPTTOS") { + AcmeTOS = sec.Key("ACME_ACCEPTTOS").MustBool(false) + } else { + deprecatedSetting("server", "LETSENCRYPT_ACCEPTTOS", "server", "ACME_ACCEPTTOS") + AcmeTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false) + } + if !AcmeTOS { + log.Fatal("ACME TOS is not accepted (ACME_ACCEPTTOS).") } // FIXME: DEPRECATED to be removed in v1.18.0 if sec.HasKey("ACME_DIRECTORY") { From cd58378aceb77ef710d2dec7a0b0d97f34473afb Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Mon, 31 Jan 2022 12:31:22 +0900 Subject: [PATCH 14/15] Improved documentation Signed-off-by: Cristian Le --- custom/conf/app.example.ini | 5 +++-- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- docs/content/doc/usage/https-support.md | 9 +++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 014dd4bcf50d..90f41016e40e 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -187,8 +187,9 @@ RUN_MODE = ; prod ;; 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 +;; Explicitly accept the ACME's TOS. The specific TOS cannot be retrieved at the moment. +;; TODO: waiting on caddyserver/certmagic#165, after which this option should only be used if interactive setup is unavailable +;ACME_ACCEPTTOS = false ;; ;; If the ACME CA is not in your system's CA trust chain, it can be manually added here ;ACME_CA_ROOT = diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 9dc52e794e25..6e1dfd434955 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -348,7 +348,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - "ecdhe_ecdsa_with_chacha20_poly1305" is alias for "ecdhe_ecdsa_with_chacha20_poly1305_sha256" - `ENABLE_ACME`: **false**: Flag to enable automatic certificate management via an ACME capable Certificate Authority (CA) server (default: Lets Encrypt). If enabled, `CERT_FILE` and `KEY_FILE` are ignored, and the CA must resolve `DOMAIN` to this gitea server. Ensure that DNS records are set and either port `80` or port `443` are accessible by the CA server (the public internet by default), and redirected to the appropriate ports `PORT_TO_REDIRECT` or `HTTP_PORT` respectively. - `ACME_URL`: **\**: The CA's ACME directory URL, e.g. for a self-hosted [smallstep CA server](https://github.com/smallstep/certificates), it can look like `https://ca.example.com/acme/acme/directory`. If left empty, it defaults to using Let's Encerypt's production CA (check `LETSENCRYPT_ACCEPTTOS` as well). -- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt. By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). +- `ACME_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service of the ACME provider. The default is Lets Encrypt [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). - `ACME_DIRECTORY`: **https**: Directory that the certificate manager will use to cache information such as certs and private keys. - `ACME_EMAIL`: **\**: Email used for the ACME registration. Usually it is to notify about problems with issued certificates. - `ACME_CA_ROOT`: **\**: The CA's root certificate. If left empty, it defaults to using the system's trust chain. diff --git a/docs/content/doc/usage/https-support.md b/docs/content/doc/usage/https-support.md index 692b6b65edc0..756e11fd03e2 100644 --- a/docs/content/doc/usage/https-support.md +++ b/docs/content/doc/usage/https-support.md @@ -57,26 +57,27 @@ If you are using Docker, make sure that this port is configured in your `docker- ## Using ACME (Default: Let's Encrypt) -[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Only `HTTP-01` and `TLS-ALPN-01` challenges are implemented. In order for ACME challenges to pass and verify your domain ownership, external traffic to the gitea domain on port `80` (`HTTP-01`) or port `443` (`TLS-ALPN-01`) has to be served by the gitea instance. Setting up [HTTP redirection](#setting-up-http-redirection) and port-forwards might be needed for external traffic to route correctly. Normal traffic to port `80` will otherwise be automatically redirected to HTTPS. +[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Only `HTTP-01` and `TLS-ALPN-01` challenges are implemented. In order for ACME challenges to pass and verify your domain ownership, external traffic to the gitea domain on port `80` (`HTTP-01`) or port `443` (`TLS-ALPN-01`) has to be served by the gitea instance. Setting up [HTTP redirection](#setting-up-http-redirection) and port-forwards might be needed for external traffic to route correctly. Normal traffic to port `80` will otherwise be automatically redirected to HTTPS. **You must consent** to the ACME provider's terms of service (default Let's Encrypt's [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf)). -If you are using the default Let's Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). Refer to the following configuration for the minimum setup: +Minimum setup using the default Let's Encrypt: ```ini [server] PROTOCOL=https DOMAIN=git.example.com ENABLE_ACME=true -LETSENCRYPT_ACCEPTTOS=true +ACME_ACCEPTTOS=true ACME_DIRECTORY=https ;; Email can be omitted here and provided manually at first run, after which it is cached ACME_EMAIL=email@example.com ``` -For generic ACME setup, you are responsible to adhere to the terms of service of the ACME server you are configuring for. The following is an example configuration using [smallstep CA](https://github.com/smallstep/certificates), refer to [their tutorial](https://smallstep.com/docs/tutorials/acme-challenge) for more information. +Minimumg setup using a [smallstep CA](https://github.com/smallstep/certificates), refer to [their tutorial](https://smallstep.com/docs/tutorials/acme-challenge) for more information. ```ini [server] PROTOCOL=https DOMAIN=git.example.com ENABLE_ACME=true +ACME_ACCEPTTOS=true ACME_URL=https://ca.example.com/acme/acme/directory ;; Can be omitted if using the system's trust is preferred ;ACME_CA_ROOT=/path/to/root_ca.crt From 7ea21e97e50f79667e34fac48cd745d9bb18e459 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 2 Feb 2022 12:00:29 +0900 Subject: [PATCH 15/15] Removed TODO note Signed-off-by: Cristian Le --- custom/conf/app.example.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 90f41016e40e..723ff450fe5f 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -188,7 +188,6 @@ RUN_MODE = ; prod ;ACME_URL = ;; ;; Explicitly accept the ACME's TOS. The specific TOS cannot be retrieved at the moment. -;; TODO: waiting on caddyserver/certmagic#165, after which this option should only be used if interactive setup is unavailable ;ACME_ACCEPTTOS = false ;; ;; If the ACME CA is not in your system's CA trust chain, it can be manually added here