about summary refs log tree commit diff stats
path: root/internal/server
diff options
context:
space:
mode:
authorAlan Pearce2024-06-24 17:18:27 +0200
committerAlan Pearce2024-06-24 17:18:27 +0200
commit50456c578497e9921558941eae59fa01bcf269bf (patch)
treec2520d354a789c50bffbf3bf961dc2a6e6b47659 /internal/server
parente6dd1b5f719ea483f5e77f78c045224607707d0a (diff)
downloadwebsite-50456c578497e9921558941eae59fa01bcf269bf.tar.lz
website-50456c578497e9921558941eae59fa01bcf269bf.tar.zst
website-50456c578497e9921558941eae59fa01bcf269bf.zip
handle TLS in server with ACME
Diffstat (limited to 'internal/server')
-rw-r--r--internal/server/server.go29
-rw-r--r--internal/server/tcp.go27
-rw-r--r--internal/server/tls.go47
3 files changed, 88 insertions, 15 deletions
diff --git a/internal/server/server.go b/internal/server/server.go
index 26d1c1f..9edebe3 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -11,7 +11,6 @@ import (
 
 	"website/internal/builder"
 	cfg "website/internal/config"
-	"website/internal/listenfd"
 	"website/internal/log"
 	"website/internal/website"
 
@@ -32,10 +31,13 @@ type Config struct {
 	Root          string `conf:"default:website"`
 	ListenAddress string `conf:"default:localhost"`
 	Port          string `conf:"default:3000,short:p"`
+	TLS           bool   `conf:"default:false"`
 }
 
 type Server struct {
 	*http.Server
+	config *cfg.Config
+	tls    bool
 }
 
 func applyDevModeOverrides(config *cfg.Config, listenAddress string) {
@@ -150,7 +152,7 @@ func New(runtimeConfig *Config) (*Server, error) {
 	})
 
 	return &Server{
-		&http.Server{
+		Server: &http.Server{
 			Addr:              listenAddress,
 			ReadHeaderTimeout: 1 * time.Minute,
 			Handler: http.MaxBytesHandler(h2c.NewHandler(
@@ -160,24 +162,21 @@ func New(runtimeConfig *Config) (*Server, error) {
 				},
 			), 0),
 		},
+		config: config,
+		tls:    runtimeConfig.TLS,
 	}, nil
 }
 
-func (s *Server) Start() error {
-	l, err := listenfd.GetListener(0)
-	if err != nil {
-		log.Warn("could not create listener from listenfd", "error", err)
-	}
-
-	log.Debug("listener from listenfd?", "passed", l != nil)
-	if l == nil {
-		l, err = net.Listen("tcp", s.Addr)
-		if err != nil {
-			return errors.Wrap(err, "could not create listener")
-		}
+func (s *Server) serve(tls bool) error {
+	if tls {
+		return s.serveTLS()
+	} else {
+		return s.serveTCP()
 	}
+}
 
-	if err := http.Serve(l, s.Handler); err != http.ErrServerClosed {
+func (s *Server) Start() error {
+	if err := s.serve(s.tls); err != http.ErrServerClosed {
 		return errors.Wrap(err, "error creating/closing server")
 	}
 
diff --git a/internal/server/tcp.go b/internal/server/tcp.go
new file mode 100644
index 0000000..4dc3314
--- /dev/null
+++ b/internal/server/tcp.go
@@ -0,0 +1,27 @@
+package server
+
+import (
+	"net"
+
+	"website/internal/listenfd"
+	"website/internal/log"
+
+	"github.com/pkg/errors"
+)
+
+func (s *Server) serveTCP() error {
+	l, err := listenfd.GetListener(0)
+	if err != nil {
+		log.Warn("could not create listener from listenfd", "error", err)
+	}
+
+	log.Debug("listener from listenfd?", "passed", l != nil)
+	if l == nil {
+		l, err = net.Listen("tcp", s.Addr)
+		if err != nil {
+			return errors.Wrap(err, "could not create listener")
+		}
+	}
+
+	return s.Serve(l)
+}
diff --git a/internal/server/tls.go b/internal/server/tls.go
new file mode 100644
index 0000000..b60f474
--- /dev/null
+++ b/internal/server/tls.go
@@ -0,0 +1,47 @@
+package server
+
+import (
+	"context"
+
+	"github.com/ardanlabs/conf/v3"
+	"github.com/caddyserver/caddy/v2"
+	"github.com/caddyserver/certmagic"
+	certmagic_redis "github.com/pberkel/caddy-storage-redis"
+	"github.com/pkg/errors"
+)
+
+type redisConfig struct {
+	Address       string `conf:"required"`
+	Username      string `conf:"default:default"`
+	Password      string `conf:"required"`
+	EncryptionKey string `conf:"required"`
+	KeyPrefix     string `conf:"default:certmagic"`
+}
+
+func (s *Server) serveTLS() (err error) {
+	rc := &redisConfig{}
+	_, err = conf.Parse("REDIS", rc)
+	if err != nil {
+		return errors.Wrap(err, "could not parse redis config")
+	}
+
+	rs := certmagic_redis.New()
+	rs.Address = []string{rc.Address}
+	rs.Username = rc.Username
+	rs.Password = rc.Password
+	rs.EncryptionKey = rc.EncryptionKey
+	rs.KeyPrefix = rc.KeyPrefix
+
+	certmagic.Default.Storage = rs
+	err = rs.Provision(caddy.Context{
+		Context: context.Background(),
+	})
+	if err != nil {
+		return errors.Wrap(err, "could not provision redis storage")
+	}
+
+	certmagic.DefaultACME.Agreed = true
+	certmagic.DefaultACME.Email = s.config.Email
+
+	return certmagic.HTTPS(s.config.Domains, s.Server.Handler)
+}