Automatic certificate management via ACME

Maddy supports obtaining certificates using ACME protocol.

To use it, create a configuration name for tls.loader.acme and reference it from endpoints that should use automatically configured certificates:

tls.loader.acme local_tls {
    email put-your-email-here@example.org
    agreed # indicate your agreement with Let's Encrypt ToS
    challenge dns-01
}

smtp tcp://127.0.0.1:25 {
    tls &local_tls
    ...
}

You can also use a global tls directive to use automatically obtained certificates for all endpoints:

tls {
    loader acme {
        email maddy-acme@example.org
        agreed
        challenge dns-01
    }
}

Currently the only supported challenge is dns-01 one therefore you also need to configure the DNS provider:

tls.loader.acme local_tls {
    email maddy-acme@example.org
    agreed
    challenge dns-01
    dns PROVIDER_NAME {
        ...
    }
}

See below for supported providers and necessary configuration for each.

Configuration directives

tls.loader.acme {
    debug off
    hostname example.maddy.invalid
    store_path /var/lib/maddy/acme
    ca https://acme-v02.api.letsencrypt.org/directory
    test_ca https://acme-staging-v02.api.letsencrypt.org/directory
    email test@maddy.invalid
    agreed off
    challenge dns-01
    dns ...
}

debug boolean

Default: global directive value

Enable debug logging.


hostname str

Required.
Default: global directive value

Domain name to issue certificate for.


store_path path

Default: state_dir/acme

Where to store issued certificates and associated metadata. Currently only filesystem-based store is supported.


ca url

Default: Let's Encrypt production CA

URL of ACME directory to use.


test_ca url

Default: Let's Encrypt staging CA

URL of ACME directory to use for retries should primary CA fail.

maddy will keep attempting to issues certificates using test_ca until it succeeds then it will switch back to the one configured via 'ca' option.

This avoids rate limit issues with production CA.


override_domain domain

Default: not set

Override the domain to set the TXT record on for DNS-01 challenge. This is to delegate the challenge to a different domain.

See https://www.eff.org/deeplinks/2018/02/technical-deep-dive-securing-automation-acme-dns-challenge-validation for explanation why this might be useful.


email str

Default: not set

Email to pass while registering an ACME account.


agreed boolean

Default: false

Whether you agreed to ToS of the CA service you are using.


challenge dns-01

Default: not set

Challenge(s) to use while performing domain verification.

DNS providers

Support for some providers is not provided by standard builds. To be able to use these, you need to compile maddy with "libdns_PROVIDER" build tag. E.g.

./build.sh -tags 'libdns_googleclouddns'
dns gandi {
    api_token "token"
}
dns digitalocean {
    api_token "..."
}

See https://github.com/libdns/cloudflare#authenticating

dns cloudflare {
    api_token "..."
}
dns vultr {
    api_token "..."
}
dns hetzner {
    api_token "..."
}
dns namecheap {
    api_key "..."
    api_username "..."

    # optional: API endpoint, production one is used if not set.
    endpoint "https://api.namecheap.com/xml.response"

    # optional: your public IP, discovered using icanhazip.com if not set
    client_ip 1.2.3.4
}
dns googleclouddns {
    project "project_id"
    service_account_json "path"
}
dns route53 {
    secret_access_key "..."
    access_key_id "..."
    # or use environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
}
dns leaseweb {
    api_key "key"
}
dns metaname {
    api_key "key"
    account_ref "reference"
}
dns alidns {
    key_id "..."
    key_secret "..."
}
dns namedotcom {
    user "..."
    token "..."
}