Letsencrypt (#17)

This commit is contained in:
Tobi Smethurst
2021-05-09 11:25:13 +02:00
committed by GitHub
parent 3c539cdfd6
commit 0cbab627c7
6 changed files with 204 additions and 30 deletions

View File

@ -31,6 +31,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/config"
"golang.org/x/crypto/acme/autocert"
)
// Router provides the REST interface for gotosocial, using gin.
@ -47,18 +48,43 @@ type Router interface {
// router fulfils the Router interface using gin and logrus
type router struct {
logger *logrus.Logger
engine *gin.Engine
srv *http.Server
logger *logrus.Logger
engine *gin.Engine
srv *http.Server
config *config.Config
certManager *autocert.Manager
}
// Start starts the router nicely
// Start starts the router nicely.
//
// Different ports and handlers will be served depending on whether letsencrypt is enabled or not.
// If it is enabled, then port 80 will be used for handling LE requests, and port 443 will be used
// for serving actual requests.
//
// If letsencrypt is not being used, then port 8080 only will be used for serving requests.
func (r *router) Start() {
go func() {
if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
r.logger.Fatalf("listen: %s", err)
}
}()
if r.config.LetsEncryptConfig.Enabled {
// serve the http handler on port 80 for receiving letsencrypt requests and solving their devious riddles
go func() {
if err := http.ListenAndServe(":http", r.certManager.HTTPHandler(http.HandlerFunc(httpsRedirect))); err != nil && err != http.ErrServerClosed {
r.logger.Fatalf("listen: %s", err)
}
}()
// and serve the actual TLS handler on port 443
go func() {
if err := r.srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
r.logger.Fatalf("listen: %s", err)
}
}()
} else {
// no tls required so just serve on port 8080
go func() {
if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
r.logger.Fatalf("listen: %s", err)
}
}()
}
}
// Stop shuts down the router nicely
@ -93,6 +119,8 @@ func New(config *config.Config, logger *logrus.Logger) (Router, error) {
default:
gin.SetMode(gin.ReleaseMode)
}
// create the actual engine here -- this is the core request routing handler for gts
engine := gin.Default()
// create a new session store middleware
@ -111,13 +139,40 @@ func New(config *config.Config, logger *logrus.Logger) (Router, error) {
logger.Debugf("loading templates from %s", tmPath)
engine.LoadHTMLGlob(tmPath)
return &router{
logger: logger,
engine: engine,
srv: &http.Server{
// create the actual http server here
var s *http.Server
var m *autocert.Manager
// We need to spawn the underlying server slightly differently depending on whether lets encrypt is enabled or not.
// In either case, the gin engine will still be used for routing requests.
if config.LetsEncryptConfig.Enabled {
// le IS enabled, so roll up an autocert manager for handling letsencrypt requests
m = &autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(config.Host),
Cache: autocert.DirCache(config.LetsEncryptConfig.CertDir),
Email: config.LetsEncryptConfig.EmailAddress,
}
// and create an HTTPS server
s = &http.Server{
Addr: ":https",
TLSConfig: m.TLSConfig(),
Handler: engine,
}
} else {
// le is NOT enabled, so just serve bare requests on port 8080
s = &http.Server{
Addr: ":8080",
Handler: engine,
},
}
}
return &router{
logger: logger,
engine: engine,
srv: s,
config: config,
certManager: m,
}, nil
}
@ -136,3 +191,13 @@ func sessionStore() (memstore.Store, error) {
return memstore.NewStore(auth, crypt), nil
}
func httpsRedirect(w http.ResponseWriter, req *http.Request) {
target := "https://" + req.Host + req.URL.Path
if len(req.URL.RawQuery) > 0 {
target += "?" + req.URL.RawQuery
}
http.Redirect(w, req, target, http.StatusTemporaryRedirect)
}