You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

web_letsencrypt.go 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package cmd
  5. import (
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "code.gitea.io/gitea/modules/log"
  10. "code.gitea.io/gitea/modules/setting"
  11. "github.com/caddyserver/certmagic"
  12. )
  13. func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error {
  14. // If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443.
  15. // Due to docker port mapping this can't be checked programmatically
  16. // TODO: these are placeholders until we add options for each in settings with appropriate warning
  17. enableHTTPChallenge := true
  18. enableTLSALPNChallenge := true
  19. altHTTPPort := 0
  20. altTLSALPNPort := 0
  21. if p, err := strconv.Atoi(setting.PortToRedirect); err == nil {
  22. altHTTPPort = p
  23. }
  24. if p, err := strconv.Atoi(setting.HTTPPort); err == nil {
  25. altTLSALPNPort = p
  26. }
  27. magic := certmagic.NewDefault()
  28. magic.Storage = &certmagic.FileStorage{Path: directory}
  29. myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{
  30. Email: email,
  31. Agreed: setting.LetsEncryptTOS,
  32. DisableHTTPChallenge: !enableHTTPChallenge,
  33. DisableTLSALPNChallenge: !enableTLSALPNChallenge,
  34. ListenHost: setting.HTTPAddr,
  35. AltTLSALPNPort: altTLSALPNPort,
  36. AltHTTPPort: altHTTPPort,
  37. })
  38. magic.Issuers = []certmagic.Issuer{myACME}
  39. // this obtains certificates or renews them if necessary
  40. err := magic.ManageSync([]string{domain})
  41. if err != nil {
  42. return err
  43. }
  44. tlsConfig := magic.TLSConfig()
  45. tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
  46. if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
  47. tlsConfig.MinVersion = version
  48. }
  49. if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
  50. tlsConfig.MaxVersion = version
  51. }
  52. // Set curve preferences
  53. if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
  54. tlsConfig.CurvePreferences = curves
  55. }
  56. // Set cipher suites
  57. if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
  58. tlsConfig.CipherSuites = ciphers
  59. }
  60. if enableHTTPChallenge {
  61. go func() {
  62. log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
  63. // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
  64. var err = runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
  65. if err != nil {
  66. log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
  67. }
  68. }()
  69. }
  70. return runHTTPSWithTLSConfig("tcp", listenAddr, "Web", tlsConfig, m)
  71. }
  72. func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
  73. if r.Method != "GET" && r.Method != "HEAD" {
  74. http.Error(w, "Use HTTPS", http.StatusBadRequest)
  75. return
  76. }
  77. // Remove the trailing slash at the end of setting.AppURL, the request
  78. // URI always contains a leading slash, which would result in a double
  79. // slash
  80. target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI()
  81. http.Redirect(w, r, target, http.StatusFound)
  82. }