Support systemd socket activation (#35)

* Support systemd socket activation

If the process has been started with systemd socket activation
configured, then serve requests on the passed-in socket instead of
attempting to bind to an address.

* Add example systemd unit files.

Add example systemd unit files which make use of systemd's security
facilities, and also allow binding to port 80 whilst running as an
unpriviliged process (using systemd socket activation).
This commit is contained in:
Tim Small
2022-01-18 07:47:32 +00:00
committed by GitHub
parent 281aff1725
commit c67b8ec91d
5 changed files with 231 additions and 3 deletions

View File

@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"github.com/coreos/go-systemd/activation"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
@ -64,8 +65,6 @@ func ListenAndServe(conf *config.Config) error {
assetFS = justFilesFilesystem{fs: http.Dir(conf.AssetsPath), readDirBatchSize: 2}
}
addr := net.JoinHostPort(conf.BindAddress, conf.Port)
log.Infof("Starting backend server on %s", addr)
r.Get("/*", pages(assetFS))
r.HandleFunc("/empty", empty)
r.HandleFunc("/backend/empty", empty)
@ -95,7 +94,31 @@ func ListenAndServe(conf *config.Config) error {
r.HandleFunc("/backend/stats.php", results.Stats)
go listenProxyProtocol(conf, r)
return http.ListenAndServe(addr, r)
// See if systemd socket activation has been used when starting our process
listeners, err := activation.Listeners()
if err != nil {
log.Fatalf("Error whilst checking for systemd socket activation %s", err)
}
var s error
switch len(listeners) {
case 0:
addr := net.JoinHostPort(conf.BindAddress, conf.Port)
log.Infof("Starting backend server on %s", addr)
s = http.ListenAndServe(addr, r)
case 1:
log.Info("Starting backend server on inherited file descriptor via systemd socket activation")
if (conf.BindAddress != "" || conf.Port != "") {
log.Errorf("Both an address/port (%s:%s) has been specificed in the config AND externally configured socket activation has been detected", conf.BindAddress, conf.Port)
log.Fatal(`Please deconfigure socket activation (e.g. in systemd unit files), or set both 'bind_address' and 'listen_port' to ''`)
}
s = http.Serve(listeners[0], r)
default:
log.Fatalf("Asked to listen on %s sockets via systemd activation. Sorry we currently only support listening on 1 socket.", len(listeners))
}
return s
}
func listenProxyProtocol(conf *config.Config, r *chi.Mux) {