mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-17 15:56:39 +00:00
attempt to trigger ssl before first request
1. When AddDomain() is called (when proxy receives a new mapping), it now spawns a goroutine to prefetch the certificate 2. prefetchCertificate() creates a synthetic tls.ClientHelloInfo and calls GetCertificate() to trigger the ACME flow 3. The certificate is cached by autocert.DirCache, so subsequent real requests will use the cached cert 4. If the cert is already cached (e.g., proxy restart), GetCertificate just returns it without making ACME requests
This commit is contained in:
@@ -2,8 +2,11 @@ package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/acme"
|
||||
@@ -64,7 +67,6 @@ func (mgr *Manager) hostPolicy(ctx context.Context, domain string) error {
|
||||
|
||||
func (mgr *Manager) AddDomain(domain, accountID, reverseProxyID string) {
|
||||
mgr.domainsMux.Lock()
|
||||
defer mgr.domainsMux.Unlock()
|
||||
mgr.domains[domain] = struct {
|
||||
accountID string
|
||||
reverseProxyID string
|
||||
@@ -72,8 +74,44 @@ func (mgr *Manager) AddDomain(domain, accountID, reverseProxyID string) {
|
||||
accountID: accountID,
|
||||
reverseProxyID: reverseProxyID,
|
||||
}
|
||||
mgr.domainsMux.Unlock()
|
||||
|
||||
go mgr.prefetchCertificate(domain)
|
||||
}
|
||||
|
||||
// prefetchCertificate proactively triggers certificate generation for a domain.
|
||||
func (mgr *Manager) prefetchCertificate(domain string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
hello := &tls.ClientHelloInfo{
|
||||
ServerName: domain,
|
||||
Conn: &dummyConn{ctx: ctx},
|
||||
}
|
||||
|
||||
log.Infof("prefetching certificate for domain %q", domain)
|
||||
_, err := mgr.GetCertificate(hello)
|
||||
if err != nil {
|
||||
log.Warnf("prefetch certificate for domain %q: %v", domain, err)
|
||||
return
|
||||
}
|
||||
log.Infof("successfully prefetched certificate for domain %q", domain)
|
||||
}
|
||||
|
||||
// dummyConn implements net.Conn to provide context for certificate fetching.
|
||||
type dummyConn struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (c *dummyConn) Read(b []byte) (n int, err error) { return 0, nil }
|
||||
func (c *dummyConn) Write(b []byte) (n int, err error) { return len(b), nil }
|
||||
func (c *dummyConn) Close() error { return nil }
|
||||
func (c *dummyConn) LocalAddr() net.Addr { return nil }
|
||||
func (c *dummyConn) RemoteAddr() net.Addr { return nil }
|
||||
func (c *dummyConn) SetDeadline(t time.Time) error { return nil }
|
||||
func (c *dummyConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
func (c *dummyConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
func (mgr *Manager) RemoveDomain(domain string) {
|
||||
mgr.domainsMux.Lock()
|
||||
defer mgr.domainsMux.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user