The ACME packages provide automated certificate acquisition and management for Let's Encrypt and other ACME-compliant Certificate Authorities. The acme package implements the core ACME protocol, while acme/autocert provides a higher-level API for automatic certificate management.
Core ACME protocol implementation for certificate lifecycle management.
const (
LetsEncryptURL = "https://acme-v02.api.letsencrypt.org/directory"
ALPNProto = "acme-tls/1"
)
const (
StatusDeactivated = "deactivated"
StatusExpired = "expired"
StatusInvalid = "invalid"
StatusPending = "pending"
StatusProcessing = "processing"
StatusReady = "ready"
StatusRevoked = "revoked"
StatusUnknown = "unknown"
StatusValid = "valid"
)var (
ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
ErrAccountAlreadyExists = errors.New("acme: account already exists")
ErrNoAccount = errors.New("acme: account does not exist")
)type Client struct {
// Key is the account private key used to register with and
// authenticate to the CA.
Key crypto.Signer
// HTTPClient optionally specifies an HTTP client to use
// instead of http.DefaultClient.
HTTPClient *http.Client
// DirectoryURL is the ACME directory URL.
DirectoryURL string
// RetryBackoff computes the duration after which the nth retry of a failed request
// should occur. If nil, the default exponential backoff is used.
RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
// UserAgent is prepended to the User-Agent header sent to the ACME server.
UserAgent string
// KID is the key identity for the account.
KID KeyID
}
// Discover performs ACME server discovery using c.DirectoryURL.
func (c *Client) Discover(ctx context.Context) (Directory, error)
// Register creates a new account with the ACME CA.
// It returns the registered account. The account acct is not modified.
func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error)
// GetReg retrieves an existing account associated with c.Key.
func (c *Client) GetReg(ctx context.Context, url string) (*Account, error)
// UpdateReg updates an existing account.
// It returns an updated account copy. The provided account is not modified.
func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error)
// DeactivateReg permanently deactivates the account associated with the given URL.
func (c *Client) DeactivateReg(ctx context.Context) error
// AccountKeyRollover replaces the account's current key with newKey.
func (c *Client) AccountKeyRollover(ctx context.Context, newKey crypto.Signer) error
// Authorize performs the initial step in the pre-authorization flow.
// Deprecated: Use AuthorizeOrder instead.
func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error)
// AuthorizeIP is the same as Authorize but for IP addresses.
// Deprecated: Use AuthorizeOrder instead.
func (c *Client) AuthorizeIP(ctx context.Context, ipaddr string) (*Authorization, error)
// AuthorizeOrder creates a new order authorization for the given identifiers.
func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error)
// GetAuthorization retrieves an authorization specified by the given URL.
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error)
// WaitAuthorization polls an authorization at the given URL until it is in one of the final states.
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error)
// RevokeAuthorization relinquishes a completed authorization.
func (c *Client) RevokeAuthorization(ctx context.Context, url string) error
// GetChallenge retrieves the current status of a challenge.
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error)
// Accept informs the server that the client accepts one of its challenges.
func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error)
// HTTP01ChallengePath returns the URL path for the HTTP-01 challenge response.
func (c *Client) HTTP01ChallengePath(token string) string
// HTTP01ChallengeResponse returns the response body for the HTTP-01 challenge.
func (c *Client) HTTP01ChallengeResponse(token string) (string, error)
// DNS01ChallengeRecord returns the DNS record value for the DNS-01 challenge.
func (c *Client) DNS01ChallengeRecord(token string) (string, error)
// TLSALPN01ChallengeCert creates a certificate for the TLS-ALPN-01 challenge.
func (c *Client) TLSALPN01ChallengeCert(token, identifier string, opt ...CertOption) (cert tls.Certificate, err error)
// GetOrder retrieves an order identified by the given URL.
func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error)
// WaitOrder polls the order at the given URL until it is in one of the final states.
func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error)
// CreateOrderCert submits the CSR (Certificate Signing Request) to finalize the order
// and fetches the issued certificate chain.
func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error)
// FetchCert retrieves already issued certificate from the given URL, in DER format.
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error)
// ListCertAlternates returns alternate certificate chain URLs for the certificate.
func (c *Client) ListCertAlternates(ctx context.Context, url string) ([]string, error)
// RevokeCert revokes a previously issued certificate.
func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error
// CreateCert is the legacy method for creating certificates.
// Deprecated: Use AuthorizeOrder and CreateOrderCert instead.
func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error)
// TLSSNI01ChallengeCert creates a certificate for the TLS-SNI-01 challenge.
// Deprecated: The TLS-SNI-01 challenge type is no longer supported by ACME servers.
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (tls.Certificate, string, error)
// TLSSNI02ChallengeCert creates a certificate for the TLS-SNI-02 challenge.
// Deprecated: The TLS-SNI-02 challenge type is no longer supported by ACME servers.
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (tls.Certificate, string, error)// Account represents a user account.
type Account struct {
// URI is the account unique ID.
URI string
// Contact is a list of contact URLs.
Contact []string
// Status indicates the current account status.
Status string
// OrdersURL is the URL for listing orders for this account.
OrdersURL string
// AgreedTerms indicates the Terms of Service URL the account agreed to.
AgreedTerms string
// CurrentTerms is the Terms of Service URL that the account should agree to.
CurrentTerms string
// Authz is the URL from which a list of authorizations granted to this account can be fetched.
Authz string
// Authorizations is the URL from which a list of authorizations can be fetched.
Authorizations string
// Certificates is the URL from which a list of certificates can be fetched.
Certificates string
// ExternalAccountBinding represents an external account binding.
ExternalAccountBinding *ExternalAccountBinding
}
// Authorization represents an authorization response.
type Authorization struct {
// URI is the authorization unique identifier.
URI string
// Status is the current status.
Status string
// Identifier is what is being authorized.
Identifier AuthzID
// Expires is when the authorization expires.
Expires time.Time
// Wildcard indicates whether the authorization is for a wildcard domain.
Wildcard bool
// Challenges is the list of challenges that can be used to validate the authorization.
Challenges []*Challenge
// Combinations indicates sets of challenges that can be used to validate the authorization.
Combinations [][]int
}
// AuthorizationError indicates that an authorization failed for a specific identifier.
type AuthorizationError struct {
// URI is the authorization URL.
URI string
// Identifier is the identifier that failed authorization.
Identifier string
// Errors are the authorization errors.
Errors []error
}
func (a *AuthorizationError) Error() string
// AuthzID identifies an authorization request.
type AuthzID struct {
// Type is the identifier type, e.g. "dns" or "ip".
Type string
// Value is the identifier value, e.g. "example.org" or "203.0.113.1".
Value string
}
// Challenge represents a CA challenge.
type Challenge struct {
// Type is the challenge type.
Type string
// URI is the challenge URL.
URI string
// Token is the challenge token.
Token string
// Status is the current challenge status.
Status string
// Validated is when the challenge was validated.
Validated time.Time
// Error is any error that occurred during challenge validation.
Error error
// Payload contains type-specific challenge data.
Payload json.RawMessage
}
// CRLReasonCode identifies the reason for certificate revocation.
type CRLReasonCode int
const (
CRLReasonUnspecified CRLReasonCode = 0
CRLReasonKeyCompromise CRLReasonCode = 1
CRLReasonCACompromise CRLReasonCode = 2
CRLReasonAffiliationChanged CRLReasonCode = 3
CRLReasonSuperseded CRLReasonCode = 4
CRLReasonCessationOfOperation CRLReasonCode = 5
CRLReasonCertificateHold CRLReasonCode = 6
CRLReasonRemoveFromCRL CRLReasonCode = 8
CRLReasonPrivilegeWithdrawn CRLReasonCode = 9
CRLReasonAACompromise CRLReasonCode = 10
)
// CertOption is an option type for TLS challenge certificate creation.
type CertOption interface {
// contains unexported methods
}
// Directory represents an ACME server discovery data.
type Directory struct {
// NonceURL is the URL to fetch a new nonce.
NonceURL string
// RegURL is the registration URL.
RegURL string
// OrderURL is the URL for creating new orders.
OrderURL string
// AuthzURL is the authorization URL.
AuthzURL string
// CertURL is the certificate URL.
CertURL string
// RevokeURL is the certificate revocation URL.
RevokeURL string
// KeyChangeURL is the key rollover URL.
KeyChangeURL string
// Terms is the Terms of Service URL.
Terms string
// Website is a URL for more information.
Website string
// CAA is the list of CAA identities for the ACME server.
CAA []string
// ExternalAccountRequired indicates whether external account binding is required.
ExternalAccountRequired bool
}
// Error represents an ACME error.
type Error struct {
// StatusCode is the HTTP response status code.
StatusCode int
// ProblemType is a URI identifying the type of problem.
ProblemType string
// Detail is a human-readable explanation.
Detail string
// Instance is a URI identifying the specific occurrence of the problem.
Instance string
// Header is the HTTP response header.
Header http.Header
// Subproblems are additional, more specific problems.
Subproblems []Subproblem
}
func (e *Error) Error() string
// ExternalAccountBinding represents external account binding data.
type ExternalAccountBinding struct {
// KID is the key identifier.
KID string
// Key is the MAC key.
Key []byte
}
func (e *ExternalAccountBinding) String() string
// KeyID is an account key identity.
type KeyID string
// Order represents a certificate order.
type Order struct {
// URI is the order unique identifier.
URI string
// Status is the current order status.
Status string
// Expires is when the order expires.
Expires time.Time
// Identifiers are the names being requested.
Identifiers []AuthzID
// NotBefore is the requested not-before time.
NotBefore time.Time
// NotAfter is the requested not-after time.
NotAfter time.Time
// Error is any error that occurred during order processing.
Error *Error
// Authorizations are the authorization URLs.
Authorizations []string
// FinalizeURL is the URL to submit the CSR.
FinalizeURL string
// CertURL is the certificate URL once issued.
CertURL string
}
// OrderError indicates that an order failed.
type OrderError struct {
// OrderURL is the order URL.
OrderURL string
// Status is the order status.
Status string
}
func (e *OrderError) Error() string
// OrderOption is an option type for order creation.
type OrderOption interface {
// contains unexported methods
}
// Subproblem represents a detailed error.
type Subproblem struct {
// Type is the problem type.
Type string
// Detail is a human-readable explanation.
Detail string
// Identifier is the identifier related to this problem.
Identifier *AuthzID
}// AcceptTOS is a PromptFunc that always returns true.
func AcceptTOS(tosURL string) bool
// JWKThumbprint creates a JWK thumbprint from a public key.
func JWKThumbprint(pub crypto.PublicKey) (string, error)
// RateLimit reports whether err is a rate limit error and
// Retry-After duration returned by the server.
func RateLimit(err error) (time.Duration, bool)
// DomainIDs creates a slice of AuthzID with "dns" identifier type.
func DomainIDs(names ...string) []AuthzID
// IPIDs creates a slice of AuthzID with "ip" identifier type.
func IPIDs(addr ...string) []AuthzID
// WithKey returns a CertOption that uses the provided key pair.
func WithKey(key crypto.Signer) CertOption
// WithTemplate returns a CertOption that uses the provided certificate template.
func WithTemplate(t *x509.Certificate) CertOption
// WithOrderNotBefore returns an OrderOption that sets the NotBefore time.
func WithOrderNotBefore(t time.Time) OrderOption
// WithOrderNotAfter returns an OrderOption that sets the NotAfter time.
func WithOrderNotAfter(t time.Time) OrderOptionAutomatic certificate management with Let's Encrypt.
const DefaultACMEDirectory = "https://acme-v02.api.letsencrypt.org/directory"var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")// Manager is a stateful certificate manager.
type Manager struct {
// Prompt specifies a callback function to accept the CA's Terms of Service.
// If nil, the default AcceptTOS is used.
Prompt func(tosURL string) bool
// Cache optionally stores and retrieves previously obtained certificates.
Cache Cache
// HostPolicy controls which domains the Manager will attempt to obtain certificates for.
// If nil, all domains are allowed.
HostPolicy HostPolicy
// RenewBefore optionally specifies how long before expiry a certificate should be renewed.
// Default is 30 days.
RenewBefore time.Duration
// Client is the ACME client used to obtain certificates.
// If nil, a default client is used.
Client *acme.Client
// Email optionally specifies a contact email address.
Email string
// ForceRSA makes the Manager generate RSA certificates instead of ECDSA.
// Deprecated: The Manager will automatically generate either RSA or ECDSA certificates.
ForceRSA bool
// ExtraExtensions are additional extensions to include in certificate requests.
ExtraExtensions []pkix.Extension
// ExternalAccountBinding optionally represents external account credentials.
ExternalAccountBinding *acme.ExternalAccountBinding
}
// GetCertificate implements the tls.Config.GetCertificate hook.
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error)
// TLSConfig creates a TLS config suitable for use with the Manager.
func (m *Manager) TLSConfig() *tls.Config
// Listener returns a net.Listener that listens on port 443 and automatically obtains certificates.
func (m *Manager) Listener() net.Listener
// HTTPHandler creates an http.Handler that handles ACME HTTP-01 challenges.
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler// Cache is used to store and retrieve certificates.
type Cache interface {
// Get returns a certificate data for the specified key.
Get(ctx context.Context, key string) ([]byte, error)
// Put stores the certificate data in the cache under the specified key.
Put(ctx context.Context, key string, data []byte) error
// Delete removes a certificate data from the cache under the specified key.
Delete(ctx context.Context, key string) error
}
// DirCache implements Cache using a directory on the local filesystem.
type DirCache string
func (d DirCache) Get(ctx context.Context, name string) ([]byte, error)
func (d DirCache) Put(ctx context.Context, name string, data []byte) error
func (d DirCache) Delete(ctx context.Context, name string) error// HostPolicy is a function that determines whether the Manager should obtain a certificate for the given host.
type HostPolicy func(ctx context.Context, host string) error
// HostWhitelist returns a HostPolicy that only allows the specified hosts.
func HostWhitelist(hosts ...string) HostPolicy// AcceptTOS is a PromptFunc that always returns true.
func AcceptTOS(tosURL string) bool
// NewListener returns a net.Listener that listens on TCP port 443
// and automatically obtains certificates for the given domains.
func NewListener(domains ...string) net.Listenerpackage main
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"golang.org/x/crypto/acme"
)
func main() {
// Create account key
accountKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
// Create ACME client
client := &acme.Client{
Key: accountKey,
DirectoryURL: acme.LetsEncryptURL,
}
// Register account
account := &acme.Account{
Contact: []string{"mailto:admin@example.com"},
}
account, _ = client.Register(context.Background(), account, acme.AcceptTOS)
// Create order for domain
order, _ := client.AuthorizeOrder(context.Background(), acme.DomainIDs("example.com"))
// Get authorization
authz, _ := client.GetAuthorization(context.Background(), order.Authorizations[0])
// Find HTTP-01 challenge
var httpChallenge *acme.Challenge
for _, c := range authz.Challenges {
if c.Type == "http-01" {
httpChallenge = c
break
}
}
// Set up HTTP challenge response
path := client.HTTP01ChallengePath(httpChallenge.Token)
response, _ := client.HTTP01ChallengeResponse(httpChallenge.Token)
// Serve response at /.well-known/acme-challenge/{token}
// Accept challenge
client.Accept(context.Background(), httpChallenge)
// Wait for order to be ready
order, _ = client.WaitOrder(context.Background(), order.URI)
// Create CSR
certKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
template := &x509.CertificateRequest{
Subject: pkix.Name{CommonName: "example.com"},
}
csr, _ := x509.CreateCertificateRequest(rand.Reader, template, certKey)
// Finalize order and get certificate
der, certURL, _ := client.CreateOrderCert(context.Background(), order.FinalizeURL, csr, true)
// Parse certificate
cert, _ := x509.ParseCertificate(der[0])
}package main
import (
"crypto/tls"
"net/http"
"golang.org/x/crypto/acme/autocert"
)
func main() {
// Create manager with cache
m := &autocert.Manager{
Cache: autocert.DirCache("certs"),
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.com", "www.example.com"),
Email: "admin@example.com",
}
// Create HTTP server with automatic HTTPS
server := &http.Server{
Addr: ":https",
TLSConfig: m.TLSConfig(),
}
// Start HTTP-01 challenge handler
go http.ListenAndServe(":http", m.HTTPHandler(nil))
// Start HTTPS server
server.ListenAndServeTLS("", "")
}package main
import (
"net/http"
"golang.org/x/crypto/acme/autocert"
)
func main() {
// Create listener that automatically obtains certificates
listener := autocert.NewListener("example.com")
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, TLS!"))
})
http.Serve(listener, nil)
}