updated layout for webmail and added http dns letsencrypt
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package acmecert
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"mailgoserver/internal/toolbox"
|
||||
)
|
||||
|
||||
// HTTP01Server is a long-lived HTTP server dedicated to the [LetsEncryptHTTP] HTTP-01
|
||||
// challenge — started once at boot (if enabled) and kept running for the whole process
|
||||
// lifetime, unlike lego's own http01.ProviderServer (challenge/http01), which binds and
|
||||
// unbinds the port on every single obtain/renew. Staying up lets an operator behind
|
||||
// NAT/a reverse proxy verify their port-forwarding actually reaches this host (curl it
|
||||
// directly, get a 200) without waiting for or burning a real, rate-limited ACME attempt.
|
||||
// It implements lego's challenge.Provider interface (Present/CleanUp) so a Manager hands
|
||||
// it token/keyAuth pairs as they come, instead of each obtain spinning up its own
|
||||
// server.
|
||||
type HTTP01Server struct {
|
||||
mu sync.RWMutex
|
||||
tokens map[string]string // token -> keyAuth
|
||||
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func NewHTTP01Server() *HTTP01Server {
|
||||
s := &HTTP01Server{tokens: map[string]string{}}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/.well-known/acme-challenge/", s.serveChallenge)
|
||||
mux.HandleFunc("/", s.serveHealth)
|
||||
s.server = &http.Server{Handler: mux}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *HTTP01Server) serveHealth(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
func (s *HTTP01Server) serveChallenge(w http.ResponseWriter, r *http.Request) {
|
||||
token := strings.TrimPrefix(r.URL.Path, "/.well-known/acme-challenge/")
|
||||
s.mu.RLock()
|
||||
keyAuth, ok := s.tokens[token]
|
||||
s.mu.RUnlock()
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(keyAuth))
|
||||
}
|
||||
|
||||
// Start binds addr (e.g. ":80") and serves in the background until the process exits.
|
||||
// Call once at boot. A bind failure (port already in use, missing
|
||||
// CAP_NET_BIND_SERVICE) is logged rather than crashing the process — HTTP-01
|
||||
// obtain/renew attempts then fail with a clear error from lego instead, same as any
|
||||
// other misconfiguration surfaced via Status.LastError.
|
||||
func (s *HTTP01Server) Start(addr string, logger *toolbox.Logger) {
|
||||
s.server.Addr = addr
|
||||
go func() {
|
||||
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
logger.Error("HTTP-01 challenge server: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Present and CleanUp implement github.com/go-acme/lego/v4/challenge.Provider.
|
||||
func (s *HTTP01Server) Present(domain, token, keyAuth string) error {
|
||||
s.mu.Lock()
|
||||
s.tokens[token] = keyAuth
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *HTTP01Server) CleanUp(domain, token, keyAuth string) error {
|
||||
s.mu.Lock()
|
||||
delete(s.tokens, token)
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user