fix: ACME HTTP-01 via nginx config without HTTPS redirect
This commit is contained in:
+49
-19
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge/http01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
)
|
||||
@@ -33,42 +34,55 @@ type ACMEUser struct {
|
||||
|
||||
func (u *ACMEUser) GetEmail() string { return u.Email }
|
||||
func (u *ACMEUser) GetRegistration() *registration.Resource { return u.Registration }
|
||||
func (u *ACMEUser) GetPrivateKey() crypto.PrivateKey { return u.key }
|
||||
func (u *ACMEUser) GetPrivateKey() crypto.PrivateKey { return u.key }
|
||||
|
||||
type webrootProvider struct {
|
||||
webroot string
|
||||
store *ChallengeStore
|
||||
type challengeProvider struct {
|
||||
webroot string
|
||||
store *ChallengeStore
|
||||
httpAddr string
|
||||
httpSrv *http01.ProviderServer
|
||||
}
|
||||
|
||||
func (p *webrootProvider) Present(domain, token, keyAuth string) error {
|
||||
func (p *challengeProvider) Present(domain, token, keyAuth string) error {
|
||||
p.store.Set(token, keyAuth)
|
||||
dir := filepath.Join(p.webroot, ".well-known", "acme-challenge")
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(filepath.Join(dir, token), []byte(keyAuth), 0o644)
|
||||
if err := os.WriteFile(filepath.Join(dir, token), []byte(keyAuth), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.httpSrv != nil {
|
||||
return p.httpSrv.Present(domain, token, keyAuth)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *webrootProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
func (p *challengeProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
p.store.Delete(token)
|
||||
_ = os.Remove(filepath.Join(p.webroot, ".well-known", "acme-challenge", token))
|
||||
if p.httpSrv != nil {
|
||||
return p.httpSrv.CleanUp(domain, token, keyAuth)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Issuer struct {
|
||||
staging bool
|
||||
storageDir string
|
||||
store *ChallengeStore
|
||||
mu sync.Mutex
|
||||
clients map[string]*lego.Client
|
||||
staging bool
|
||||
storageDir string
|
||||
acmeHTTPAddr string
|
||||
store *ChallengeStore
|
||||
mu sync.Mutex
|
||||
clients map[string]*lego.Client
|
||||
}
|
||||
|
||||
func NewIssuer(staging bool, storageDir string, store *ChallengeStore) *Issuer {
|
||||
func NewIssuer(staging bool, storageDir, acmeHTTPAddr string, store *ChallengeStore) *Issuer {
|
||||
return &Issuer{
|
||||
staging: staging,
|
||||
storageDir: storageDir,
|
||||
store: store,
|
||||
clients: make(map[string]*lego.Client),
|
||||
staging: staging,
|
||||
storageDir: storageDir,
|
||||
acmeHTTPAddr: acmeHTTPAddr,
|
||||
store: store,
|
||||
clients: make(map[string]*lego.Client),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +97,15 @@ func (i *Issuer) Obtain(ctx context.Context, email, domain, webroot string) (*ce
|
||||
return nil, err
|
||||
}
|
||||
|
||||
provider := &webrootProvider{webroot: webroot, store: i.store}
|
||||
provider := &challengeProvider{webroot: webroot, store: i.store}
|
||||
if i.acmeHTTPAddr != "" {
|
||||
port := "80"
|
||||
if strings.Contains(i.acmeHTTPAddr, ":") {
|
||||
port = strings.TrimPrefix(i.acmeHTTPAddr, ":")
|
||||
}
|
||||
provider.httpSrv = http01.NewProviderServer("", port)
|
||||
}
|
||||
|
||||
if err := client.Challenge.SetHTTP01Provider(provider); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -95,7 +117,7 @@ func (i *Issuer) Obtain(ctx context.Context, email, domain, webroot string) (*ce
|
||||
|
||||
res, err := client.Certificate.Obtain(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("acme obtain: %w", err)
|
||||
return nil, fmt.Errorf("acme obtain: %w%s", err, tlsErrorHint(err))
|
||||
}
|
||||
|
||||
if err := i.saveToDisk(domain, res); err != nil {
|
||||
@@ -105,6 +127,14 @@ func (i *Issuer) Obtain(ctx context.Context, email, domain, webroot string) (*ce
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func tlsErrorHint(err error) string {
|
||||
msg := err.Error()
|
||||
if strings.Contains(msg, "error:tls") || strings.Contains(msg, "remote error: tls") {
|
||||
return " — домен перенаправляет HTTP→HTTPS; нужен nginx location для /.well-known/acme-challenge/ без редиректа"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (i *Issuer) getClient(email string) (*lego.Client, error) {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user