Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add letsencrypt to Gitea #4189

Merged
merged 34 commits into from Aug 21, 2018
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
aa3fccb
add letsencrypt to Gitea
flynnnnnnnnnn Jun 8, 2018
2771df7
downgrade cypto lib
flynnnnnnnnnn Jun 8, 2018
dd01b57
fix typo
flynnnnnnnnnn Jun 8, 2018
ce3840f
update docs
Jun 9, 2018
95a4191
Merge branch 'master' into letsencrypt
Jun 9, 2018
c56d4a2
let user customize directory and set email
flynnnnnnnnnn Jun 10, 2018
1d0097a
Update to using named port
Jun 10, 2018
caa2d3a
Merge branch 'master' into letsencrypt
Jun 10, 2018
6bbf48c
add docs
Jun 11, 2018
42411f8
redirect to AppURL instead of assuming port 443
HarukaMa Jun 12, 2018
e5afbb9
Merge branch 'master' into letsencrypt
Jun 12, 2018
6fcb86b
Update IP listening on for LE
Jun 13, 2018
f58c5b4
Merge branch 'master' into letsencrypt
Jun 13, 2018
fd0103f
Merge branch 'master' into letsencrypt
techknowlogick Jun 19, 2018
f09fb9c
Merge branch 'master' into letsencrypt
techknowlogick Jul 3, 2018
75dd8ed
dont use protocol for letsencrypt
flynnnnnnnnnn Jul 4, 2018
89c5e1c
Merge branch 'master' into letsencrypt
Jul 4, 2018
bfe3769
resolve variable name
flynnnnnnnnnn Jul 4, 2018
c195fe1
Merge branch 'letsencrypt' of https://github.com/flufmonster/gitea in…
Jul 4, 2018
ceebba5
Merge branch 'master' into letsencrypt
techknowlogick Jul 5, 2018
5c57c62
Merge branch 'master' into letsencrypt
techknowlogick Jul 8, 2018
9169a46
update docs
Jul 12, 2018
f961204
added check for TOS acceptance
Jul 12, 2018
7a79c2b
update docs
Jul 12, 2018
60708ca
update docs
Jul 12, 2018
34b5519
Merge branch 'master' into letsencrypt
Jul 12, 2018
be6b426
fix use of variable
Jul 12, 2018
793c460
Merge branch 'master' into letsencrypt
techknowlogick Jul 21, 2018
aa80181
allow listen to other ports for redir
Jul 21, 2018
77a65fa
Merge branch 'master' into letsencrypt
Jul 21, 2018
d3cbc0c
Add log statement re: TOS
Jul 26, 2018
9112ba2
Merge branch 'master' into letsencrypt
Jul 26, 2018
9042772
Merge branch 'master' into letsencrypt
Aug 14, 2018
3d84f1f
Merge branch 'master' into letsencrypt
daviian Aug 21, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ignored = ["google.golang.org/appengine*"]
name = "code.gitea.io/sdk"

[[constraint]]
revision = "9f005a07e0d31d45e6656d241bb5c0f2efd4bc94"
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
name = "golang.org/x/crypto"

[[constraint]]
Expand Down
31 changes: 31 additions & 0 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package cmd

import (
"crypto/tls"
"fmt"
"net"
"net/http"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/Unknwon/com"
context2 "github.com/gorilla/context"
"github.com/urfave/cli"
"golang.org/x/crypto/acme/autocert"
ini "gopkg.in/ini.v1"
)

Expand Down Expand Up @@ -71,6 +73,33 @@ func runHTTPRedirector() {
}
}

func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error {
certManager := autocert.Manager{
Prompt: autocert.AcceptTOS,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This HAS to be behind its own setting (LETSENCRYPT_ACCEPT_TOS) 😱 People will not read the comments...

HostPolicy: autocert.HostWhitelist(domain),
Cache: autocert.DirCache(directory),
Email: email,
}
go http.ListenAndServe(listenAddr+":http", certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validatio happens here)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope that certManager has panic-handling :trollface: Otherwise this might just silently fail 😄

server := &http.Server{
Addr: listenAddr,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK Let's Encrypt enforces port 443

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's Encrypt only enforces a port when requesting the certificate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP port is not really required, the autocert HTTP handler does only a simple redirect to HTTPS, so this port 443 is enforced by Let's Encrypt.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP port is required. The HTTP handler doesn't just do a simple redirect it also handles the HTTP-01 validation per the acme standard: https://tools.ietf.org/html/draft-ietf-acme-acme-07#section-8.3 and here is the code https://github.com/golang/crypto/blob/master/acme/autocert/autocert.go#L333

I think what you are thinking of is the TLS-SNI challenge which was disabled permanently due to security issues. A new version of TLS only challenge is being worked on but it is still only being discussed on mailing lists.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right on that, but since you are not defining a fallback handler HTTPS must run on 443: https://github.com/golang/crypto/blob/master/acme/autocert/autocert.go#L323-L326

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just setup a fallback handler to redirect to AppURL so that the user is redirected to the correct place.

Handler: m,
TLSConfig: &tls.Config{
GetCertificate: certManager.GetCertificate,
},
}
return server.ListenAndServeTLS("", "")
}

func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "HEAD" {
http.Error(w, "Use HTTPS", http.StatusBadRequest)
return
}
target := setting.AppURL + r.URL.RequestURI()
http.Redirect(w, r, target, http.StatusFound)
}

func runWeb(ctx *cli.Context) error {
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
Expand Down Expand Up @@ -147,6 +176,8 @@ func runWeb(ctx *cli.Context) error {
go runHTTPRedirector()
}
err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
case setting.LetsEncrypt:
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
case setting.FCGI:
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.

## Server (`server`)

- `PROTOCOL`: **http**: \[http, https, fcgi, unix\]
- `PROTOCOL`: **http**: \[http, https, fcgi, unix, letsencrypt\] If using letsencrypt you must set `DOMAIN` to valid domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also inform that by using letsencrypt we (the user) agree with their TOS.

- `DOMAIN`: **localhost**: Domain name of this server.
- `ROOT_URL`: **%(PROTOCOL)s://%(DOMAIN)s:%(HTTP\_PORT)s/**:
Overwrite the automatically generated public URL.
Expand Down Expand Up @@ -119,6 +119,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, redirects http requests
on another (https) port.
- `PORT_TO_REDIRECT`: **80**: Port used when `REDIRECT_OTHER_PORT` is true.
- `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)

## Database (`database`)

Expand Down
14 changes: 14 additions & 0 deletions docs/content/doc/usage/https-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ KEY_FILE = key.pem
```
To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server).

## Using 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put a note about the TOS consent here (better to over communicate)

```ini
[server]
PROTOCOL=letsencrypt
DOMAIN=git.example.com
LETSENCRYPT_DIRECTORY=https
LETSENCRYPT_EMAIL=email@example.com
```

To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server).

## Using reverse proxy

Setup up your reverse proxy like shown in the [reverse proxy guide](../reverse-proxies).
Expand Down
15 changes: 11 additions & 4 deletions modules/setting/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ type Scheme string

// enumerates all the scheme types
const (
HTTP Scheme = "http"
HTTPS Scheme = "https"
FCGI Scheme = "fcgi"
UnixSocket Scheme = "unix"
HTTP Scheme = "http"
HTTPS Scheme = "https"
FCGI Scheme = "fcgi"
UnixSocket Scheme = "unix"
LetsEncrypt Scheme = "letsencrypt"
)

// LandingPage describes the default page
Expand Down Expand Up @@ -105,6 +106,8 @@ var (
LandingPageURL LandingPage
UnixSocketPermission uint32
EnablePprof bool
LetsEncryptDirectory string
LetsEncryptEmail string

SSH = struct {
Disabled bool `ini:"DISABLE_SSH"`
Expand Down Expand Up @@ -709,6 +712,10 @@ func NewContext() {
log.Fatal(4, "Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
}
UnixSocketPermission = uint32(UnixSocketPermissionParsed)
} else if sec.Key("PROTOCOL").String() == "letsencrypt" {
Protocol = LetsEncrypt
LetsEncryptDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https")
LetsEncryptEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("")
}
Domain = sec.Key("DOMAIN").MustString("localhost")
HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
Expand Down
Loading