mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
Happy weekend! Due the latest news we have a single change for your own safety. iris.AutoTLS
users should pass all the necessary information now, these are the recommended by letsencrypt.
Iris devs should declare all the information now, there is no option to "leave something out" anymore, it's for your own good. Version is not changed yet, giving you time to see that changelog and do the necessary changes to your codebase. Happy weekend! Former-commit-id: 490ce14a1022a2b81d347d7f59c2bb5412cfcdf2
This commit is contained in:
parent
878acec003
commit
83fbef2d2f
21
README.md
21
README.md
|
@ -135,11 +135,13 @@ $ go run main.go
|
||||||
<details>
|
<details>
|
||||||
<summary>Hello World with Go 1.9</summary>
|
<summary>Hello World with Go 1.9</summary>
|
||||||
|
|
||||||
If you've installed Go 1.9 then you can omit the `github.com/kataras/iris/context` package from the imports statement.
|
Go 1.9 just released.
|
||||||
|
|
||||||
|
Dcumentation and examples will be updated soon to use the already-type aliases inside the framework, such as `iris.Context` instead of the origin pacage.
|
||||||
|
|
||||||
|
If you've installed [Go 1.9](https://golang.org/dl) then you can omit the `github.com/kataras/iris/context` package from the imports statement.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/kataras/iris"
|
import "github.com/kataras/iris"
|
||||||
|
@ -157,19 +159,6 @@ func main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We expect Go version 1.9 to be released in August, however you can install Go 1.9 RC2 today.
|
|
||||||
|
|
||||||
### Installing Go 1.9rc2
|
|
||||||
|
|
||||||
1. Go to https://golang.org/dl/#go1.9rc2
|
|
||||||
2. Download a compatible, with your OS, archive or executable, i.e `go1.9rc2.windows-amd64.zip`
|
|
||||||
3. Unzip the contents of `go1.9rc2.windows-amd64.zip` folder to your $GOROOT, i.e `C:\Go` or just execute the executable you've just download
|
|
||||||
4. Open a terminal and execute `go version`, it should output the go1.9rc2 version, i.e:
|
|
||||||
```sh
|
|
||||||
C:\Users\kataras>go version
|
|
||||||
go version go1.9rc2 windows/amd64
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kataras/iris/core/netutil"
|
"github.com/kataras/iris/core/netutil"
|
||||||
)
|
)
|
||||||
|
@ -59,13 +60,13 @@ func ProxyHandler(target *url.URL) *httputil.ReverseProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProxy returns a new host (server supervisor) which
|
// NewProxy returns a new host (server supervisor) which
|
||||||
// redirects all requests to the target.
|
// proxies all requests to the target.
|
||||||
// It uses the httputil.NewSingleHostReverseProxy.
|
// It uses the httputil.NewSingleHostReverseProxy.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// target, _ := url.Parse("https://mydomain.com")
|
// target, _ := url.Parse("https://mydomain.com")
|
||||||
// proxy := NewProxy("mydomain.com:80", target)
|
// proxy := NewProxy("mydomain.com:80", target)
|
||||||
// proxy.ListenAndServe() // use of proxy.Shutdown to close the proxy server.
|
// proxy.ListenAndServe() // use of `proxy.Shutdown` to close the proxy server.
|
||||||
func NewProxy(hostAddr string, target *url.URL) *Supervisor {
|
func NewProxy(hostAddr string, target *url.URL) *Supervisor {
|
||||||
proxyHandler := ProxyHandler(target)
|
proxyHandler := ProxyHandler(target)
|
||||||
proxy := New(&http.Server{
|
proxy := New(&http.Server{
|
||||||
|
@ -75,3 +76,38 @@ func NewProxy(hostAddr string, target *url.URL) *Supervisor {
|
||||||
|
|
||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewRedirection returns a new host (server supervisor) which
|
||||||
|
// redirects all requests to the target.
|
||||||
|
// Usage:
|
||||||
|
// target, _ := url.Parse("https://mydomain.com")
|
||||||
|
// r := NewRedirection(":80", target, 307)
|
||||||
|
// r.ListenAndServe() // use of `r.Shutdown` to close this server.
|
||||||
|
func NewRedirection(hostAddr string, target *url.URL, redirectStatus int) *Supervisor {
|
||||||
|
targetURI := target.String()
|
||||||
|
if redirectStatus <= 300 {
|
||||||
|
// here we should use StatusPermanentRedirect but
|
||||||
|
// that may result on unexpected behavior
|
||||||
|
// for end-developers who might change their minds
|
||||||
|
// after a while, so keep status temporary.
|
||||||
|
// Note thatwe could also use StatusFound
|
||||||
|
// as we do on the `Context#Redirect`.
|
||||||
|
// It will also help us to prevent any post data issues.
|
||||||
|
redirectStatus = http.StatusTemporaryRedirect
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectSrv := &http.Server{
|
||||||
|
ReadTimeout: 30 * time.Second,
|
||||||
|
WriteTimeout: 60 * time.Second,
|
||||||
|
Addr: hostAddr,
|
||||||
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
redirectTo := singleJoiningSlash(targetURI, r.URL.Path)
|
||||||
|
if len(r.URL.RawQuery) > 0 {
|
||||||
|
redirectTo += "?" + r.URL.RawQuery
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, redirectTo, redirectStatus)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(redirectSrv)
|
||||||
|
}
|
||||||
|
|
|
@ -5,12 +5,16 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/acme/autocert"
|
||||||
|
|
||||||
"github.com/kataras/iris/core/errors"
|
"github.com/kataras/iris/core/errors"
|
||||||
"github.com/kataras/iris/core/netutil"
|
"github.com/kataras/iris/core/netutil"
|
||||||
"golang.org/x/crypto/acme/autocert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configurator provides an easy way to modify
|
// Configurator provides an easy way to modify
|
||||||
|
@ -231,19 +235,15 @@ func (su *Supervisor) ListenAndServe() error {
|
||||||
return su.Serve(l)
|
return su.Serve(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupHTTP2(cfg *tls.Config) {
|
|
||||||
cfg.NextProtos = append(cfg.NextProtos, "h2") // HTTP2
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenAndServeTLS acts identically to ListenAndServe, except that it
|
// ListenAndServeTLS acts identically to ListenAndServe, except that it
|
||||||
// expects HTTPS connections. Additionally, files containing a certificate and
|
// expects HTTPS connections. Additionally, files containing a certificate and
|
||||||
// matching private key for the server must be provided. If the certificate
|
// matching private key for the server must be provided. If the certificate
|
||||||
// is signed by a certificate authority, the certFile should be the concatenation
|
// is signed by a certificate authority, the certFile should be the concatenation
|
||||||
// of the server's certificate, any intermediates, and the CA's certificate.
|
// of the server's certificate, any intermediates, and the CA's certificate.
|
||||||
func (su *Supervisor) ListenAndServeTLS(certFile string, keyFile string) error {
|
func (su *Supervisor) ListenAndServeTLS(certFile string, keyFile string) error {
|
||||||
if certFile == "" || keyFile == "" {
|
su.manuallyTLS = true
|
||||||
return errors.New("certFile or keyFile missing")
|
|
||||||
}
|
if certFile != "" && keyFile != "" {
|
||||||
cfg := new(tls.Config)
|
cfg := new(tls.Config)
|
||||||
var err error
|
var err error
|
||||||
cfg.Certificates = make([]tls.Certificate, 1)
|
cfg.Certificates = make([]tls.Certificate, 1)
|
||||||
|
@ -251,26 +251,103 @@ func (su *Supervisor) ListenAndServeTLS(certFile string, keyFile string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
setupHTTP2(cfg)
|
|
||||||
su.Server.TLSConfig = cfg
|
su.Server.TLSConfig = cfg
|
||||||
su.manuallyTLS = true
|
|
||||||
return su.ListenAndServe()
|
return su.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if su.Server.TLSConfig == nil {
|
||||||
|
return errors.New("certFile or keyFile missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
return su.supervise(func() error { return su.Server.ListenAndServeTLS("", "") })
|
||||||
|
}
|
||||||
|
|
||||||
// ListenAndServeAutoTLS acts identically to ListenAndServe, except that it
|
// ListenAndServeAutoTLS acts identically to ListenAndServe, except that it
|
||||||
// expects HTTPS connections. server's certificates are auto generated from LETSENCRYPT using
|
// expects HTTPS connections. Server's certificates are auto generated from LETSENCRYPT using
|
||||||
// the golang/x/net/autocert package.
|
// the golang/x/net/autocert package.
|
||||||
func (su *Supervisor) ListenAndServeAutoTLS() error {
|
//
|
||||||
autoTLSManager := autocert.Manager{
|
// The whitelisted domains are separated by whitespace in "domain" argument, i.e "iris-go.com".
|
||||||
Prompt: autocert.AcceptTOS,
|
// If empty, all hosts are currently allowed. This is not recommended,
|
||||||
|
// as it opens a potential attack where clients connect to a server
|
||||||
|
// by IP address and pretend to be asking for an incorrect host name.
|
||||||
|
// Manager will attempt to obtain a certificate for that host, incorrectly,
|
||||||
|
// eventually reaching the CA's rate limit for certificate requests
|
||||||
|
// and making it impossible to obtain actual certificates.
|
||||||
|
//
|
||||||
|
// For an "e-mail" use a non-public one, letsencrypt needs that for your own security.
|
||||||
|
//
|
||||||
|
// The "cacheDir" is being, optionally, used to provide cache
|
||||||
|
// stores and retrieves previously-obtained certificates.
|
||||||
|
// If empty, certs will only be cached for the lifetime of the auto tls manager.
|
||||||
|
//
|
||||||
|
// Note: If domain is not empty and the server's port was "443" then
|
||||||
|
// it will start a new server, automaticall for you, which will redirect all
|
||||||
|
// http versions to their https as well.
|
||||||
|
func (su *Supervisor) ListenAndServeAutoTLS(domain string, email string, cacheDir string) error {
|
||||||
|
var (
|
||||||
|
cache autocert.Cache
|
||||||
|
hostPolicy autocert.HostPolicy
|
||||||
|
)
|
||||||
|
|
||||||
|
if cacheDir != "" {
|
||||||
|
cache = autocert.DirCache(cacheDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if domain != "" {
|
||||||
|
domains := strings.Split(domain, " ")
|
||||||
|
hostPolicy = autocert.HostWhitelist(domains...)
|
||||||
|
}
|
||||||
|
|
||||||
|
autoTLSManager := &autocert.Manager{
|
||||||
|
Prompt: autocert.AcceptTOS,
|
||||||
|
HostPolicy: hostPolicy,
|
||||||
|
Email: email,
|
||||||
|
Cache: cache,
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &tls.Config{
|
||||||
|
GetCertificate: autoTLSManager.GetCertificate,
|
||||||
|
MinVersion: tls.VersionTLS10,
|
||||||
|
PreferServerCipherSuites: true,
|
||||||
|
CurvePreferences: []tls.CurveID{
|
||||||
|
tls.X25519,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := new(tls.Config)
|
|
||||||
cfg.GetCertificate = autoTLSManager.GetCertificate
|
|
||||||
setupHTTP2(cfg)
|
|
||||||
su.Server.TLSConfig = cfg
|
su.Server.TLSConfig = cfg
|
||||||
su.manuallyTLS = true
|
|
||||||
return su.ListenAndServe()
|
// Redirect all http://$path requests to their
|
||||||
|
// https://$path versions if a specific domain is passed on
|
||||||
|
// and the port was 443.
|
||||||
|
if hostPolicy != nil && netutil.ResolvePort(su.Server.Addr) == 443 {
|
||||||
|
// find the first domain if more than one.
|
||||||
|
spaceIdx := strings.IndexByte(domain, ' ')
|
||||||
|
if spaceIdx != -1 {
|
||||||
|
domain = domain[0:spaceIdx]
|
||||||
|
}
|
||||||
|
// create the url for the secured server.
|
||||||
|
target, err := url.Parse("https://" + domain)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the redirect server.
|
||||||
|
redirectSrv := NewRedirection(":80", target, -1)
|
||||||
|
// register a shutdown callback to this
|
||||||
|
// supervisor in order to close the "secondary redirect server" as well.
|
||||||
|
|
||||||
|
su.RegisterOnShutdown(func() {
|
||||||
|
// give it some time to close itself...
|
||||||
|
timeout := 5 * time.Second
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
redirectSrv.Shutdown(ctx)
|
||||||
|
})
|
||||||
|
// start that redirect server using a different goroutine.
|
||||||
|
go redirectSrv.ListenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
return su.ListenAndServeTLS("", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterOnShutdown registers a function to call on Shutdown.
|
// RegisterOnShutdown registers a function to call on Shutdown.
|
||||||
|
|
31
iris.go
31
iris.go
|
@ -552,9 +552,24 @@ func TLS(addr string, certFile, keyFile string, hostConfigs ...host.Configurator
|
||||||
// certifications created on the fly by the "autocert" golang/x package,
|
// certifications created on the fly by the "autocert" golang/x package,
|
||||||
// so localhost may not be working, use it at "production" machine.
|
// so localhost may not be working, use it at "production" machine.
|
||||||
//
|
//
|
||||||
// Addr should have the form of [host]:port, i.e mydomain.com:443.
|
// Addr should have the form of [host]:port, i.e mydomain.com:443 or :443.
|
||||||
//
|
//
|
||||||
// Second argument is optional, it accepts one or more
|
// The whitelisted domains are separated by whitespace in "domain" argument,
|
||||||
|
// i.e "iris-go.com", can be different than "addr".
|
||||||
|
// If empty, all hosts are currently allowed. This is not recommended,
|
||||||
|
// as it opens a potential attack where clients connect to a server
|
||||||
|
// by IP address and pretend to be asking for an incorrect host name.
|
||||||
|
// Manager will attempt to obtain a certificate for that host, incorrectly,
|
||||||
|
// eventually reaching the CA's rate limit for certificate requests
|
||||||
|
// and making it impossible to obtain actual certificates.
|
||||||
|
//
|
||||||
|
// For an "e-mail" use a non-public one, letsencrypt needs that for your own security.
|
||||||
|
//
|
||||||
|
// Note: If domain is not empty and the server's port was "443" then
|
||||||
|
// it will start a new server, automaticall for you, which will redirect all
|
||||||
|
// http versions to their https as well.
|
||||||
|
//
|
||||||
|
// Last argument is optional, it accepts one or more
|
||||||
// `func(*host.Configurator)` that are being executed
|
// `func(*host.Configurator)` that are being executed
|
||||||
// on that specific host that this function will create to start the server.
|
// on that specific host that this function will create to start the server.
|
||||||
// Via host configurators you can configure the back-end host supervisor,
|
// Via host configurators you can configure the back-end host supervisor,
|
||||||
|
@ -563,12 +578,18 @@ func TLS(addr string, certFile, keyFile string, hostConfigs ...host.Configurator
|
||||||
// https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
|
// https://github.com/kataras/iris/blob/master/_examples/http-listening/notify-on-shutdown/main.go
|
||||||
// Look at the `ConfigureHost` too.
|
// Look at the `ConfigureHost` too.
|
||||||
//
|
//
|
||||||
// See `Run` for more.
|
// Usage:
|
||||||
func AutoTLS(addr string, hostConfigs ...host.Configurator) Runner {
|
// app.Run(iris.AutoTLS(":443", "example.com", "mail@example.com"))
|
||||||
|
//
|
||||||
|
// See `Run` and `core/host/Supervisor#ListenAndServeAutoTLS` for more.
|
||||||
|
func AutoTLS(
|
||||||
|
addr string,
|
||||||
|
domain string, email string,
|
||||||
|
hostConfigs ...host.Configurator) Runner {
|
||||||
return func(app *Application) error {
|
return func(app *Application) error {
|
||||||
return app.NewHost(&http.Server{Addr: addr}).
|
return app.NewHost(&http.Server{Addr: addr}).
|
||||||
Configure(hostConfigs...).
|
Configure(hostConfigs...).
|
||||||
ListenAndServeAutoTLS()
|
ListenAndServeAutoTLS(domain, email, "letscache")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user