Add initial tls support
Some checks are pending
/ docker (push) Waiting to run

- Uses certificate and key files provided by admin in config
- Let's Encrypt integration planned, but not even close to working
- Initial HTTP3 Support added
This commit is contained in:
Melody Becker 2025-05-27 14:06:08 +02:00
parent 68d7a5e8c3
commit 9151bfb3be
Signed by: mstar
SSH key fingerprint: SHA256:9VAo09aaVNTWKzPW7Hq2LW+ox9OdwmTSHRoD4mlz1yI
6 changed files with 250 additions and 42 deletions

View file

@ -0,0 +1,40 @@
package webmiddleware
import (
"fmt"
"net/http"
"git.mstar.dev/mstar/linstrom/config"
)
func AddUpgradeHeader(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.ProtoMajor {
case 1:
// Always offer upgrade to http2
headerText := fmt.Sprintf(
"h2=\":%d\"; ma=3600",
config.GlobalConfig.General.GetFinalPublicPort(),
)
// Offer upgrade to http3 if enabled
if config.GlobalConfig.Experimental.Http3Support && config.GlobalConfig.SSL.HandleSSL {
headerText = fmt.Sprintf(
"h3=\":%d\"; ma=3600, %s",
config.GlobalConfig.General.GetFinalPublicPort(),
headerText,
)
}
w.Header().Add("Alt-Svc", headerText)
case 2:
// Offer upgrade to http3 if enabled
if config.GlobalConfig.Experimental.Http3Support && config.GlobalConfig.SSL.HandleSSL {
headerText := fmt.Sprintf(
"h3=\":%d\"; ma=3600",
config.GlobalConfig.General.GetFinalPublicPort(),
)
w.Header().Add("Alt-Svc", headerText)
}
}
h.ServeHTTP(w, r)
})
}

View file

@ -32,13 +32,18 @@ import (
"net/http"
webutils "git.mstar.dev/mstar/goutils/http"
"github.com/quic-go/quic-go/http3"
"github.com/rs/zerolog/log"
"git.mstar.dev/mstar/linstrom/auth-new"
"git.mstar.dev/mstar/linstrom/config"
"git.mstar.dev/mstar/linstrom/web/public/api"
webmiddleware "git.mstar.dev/mstar/linstrom/web/public/middleware"
)
type Server struct {
server *http.Server
server *http.Server
quicServer *http3.Server
}
func New(addr string, duckImg *string, duckFs fs.FS) *Server {
@ -51,28 +56,92 @@ func New(addr string, duckImg *string, duckFs fs.FS) *Server {
handler.HandleFunc("GET /errors/{name}", errorTypeHandler)
handler.HandleFunc("GET /default-image", buildServeDefaultImage(duckImg, duckFs))
handler.HandleFunc("GET /default-image.webp", buildServeDefaultImage(duckImg, duckFs))
server := http.Server{
Handler: webutils.ChainMiddlewares(
handler,
webutils.BuildLoggingMiddleware(
true,
[]string{"/assets"},
map[string]string{"server": "public"},
),
webmiddleware.AppendFullPathMiddleware,
webmiddleware.TraceRequestInfoMiddleware,
rootHandler := webutils.ChainMiddlewares(
handler,
webutils.BuildLoggingMiddleware(
true,
[]string{"/assets"},
map[string]string{"server": "public"},
),
Addr: addr,
webmiddleware.AppendFullPathMiddleware,
webmiddleware.TraceRequestInfoMiddleware,
webmiddleware.AddUpgradeHeader,
)
server := http.Server{
Handler: rootHandler,
Addr: addr,
}
return &Server{&server}
quicServer := http3.Server{
Handler: rootHandler,
Addr: addr,
}
if config.GlobalConfig.General.PublicPort != nil {
quicServer.Port = *config.GlobalConfig.General.PublicPort
}
return &Server{server: &server, quicServer: &quicServer}
}
func (s *Server) Start() error {
return s.server.ListenAndServe()
if config.GlobalConfig.SSL.HandleSSL {
certFile, keyFile, err := auth.TlsFromConfig()
if err != nil {
return err
}
if config.GlobalConfig.Experimental.Http3Support {
errChan := make(chan error, 2)
go func() {
errChan <- s.server.ListenAndServeTLS(certFile, keyFile)
}()
go func() {
errChan <- s.quicServer.ListenAndServeTLS(certFile, keyFile)
}()
err := <-errChan
if err != nil && err != http.ErrServerClosed {
return err
}
// Always gets two values back on the channel since both servers are running
err = <-errChan
if err != nil && err != http.ErrServerClosed {
return err
}
return nil
} else {
return s.server.ListenAndServeTLS(certFile, keyFile)
}
} else {
// But refuse http3 support here, since it doesn't work without tls
return s.server.ListenAndServe()
}
}
func (s *Server) Stop() error {
return s.server.Shutdown(context.Background())
if config.GlobalConfig.SSL.HandleSSL && config.GlobalConfig.Experimental.Http3Support {
errChan := make(chan error, 2)
go func() {
log.Debug().Msg("Stopping tcp server")
errChan <- s.server.Shutdown(context.Background())
log.Debug().Msg("Tcp server stopped")
}()
go func() {
log.Debug().Msg("Stopping udp server")
errChan <- s.quicServer.Shutdown(context.Background())
log.Debug().Msg("Udp server stopped")
}()
err := <-errChan
if err != nil && err != http.ErrServerClosed {
return err
}
// Always gets two values back on the channel since both servers are running
err = <-errChan
if err != nil && err != http.ErrServerClosed {
return err
}
return nil
} else {
return s.server.Shutdown(context.Background())
}
}
func buildServeDefaultImage(