Advanced usages

  • This section describes how to use hooks.
  • This section describes advanced options that can be used to configure lego.
  • This page describes the usage of CA servers (ACME servers).
  • This section describes operations on the archives.
  • This section contains some tips and tricks for using lego.
May 13, 2026

Subsections of Advanced usages

Hooks

This section describes how to use hooks.

There are three hooks available:

Hook When it runs
pre-hook Before the certificate is created or renewed (only if a change will actually happen)
deploy-hook After the certificate is successfully created or renewed
post-hook After the operation completes, regardless of outcome

Don’t hesitate to share your hook scripts with the community.

Pre-Hook

This hook is executed, before the creation or the renewal, in cases where a certificate will be effectively created/renewed.

Execute the following command:

lego run -d 'example.com' --pre-hook='./my-pre-hook.sh'

Define the following section in your .lego.yaml file:

hooks:
  pre:
    command: './my-pre-hook.sh'

Deploy-Hook

This hook is executed after the successful creation or the renewal of a certificate.

Execute the following command:

lego run -d 'example.com' --deploy-hook='./my-deploy-hook.sh'

Define the following section in your .lego.yaml file:

hooks:
  deploy:
    command: './my-deploy-hook.sh'

Post-Hook

This hook is executed, after the creation or the renewal, in cases where a certificate is created/renewed, regardless of whether any errors occurred.

Execute the following command:

lego run -d 'example.com' --post-hook='./my-post-hook.sh'

Define the following section in your .lego.yaml file:

hooks:
  post:
    command: './my-post-hook.sh'

Environment Variables

Some details are passed through environment variables to help you with your hooks:

Environment Variable Description
LEGO_HOOK_ACCOUNT_ID The account ID.
LEGO_HOOK_ACCOUNT_EMAIL The account email (if available).
LEGO_HOOK_ACCOUNT_SERVER The server related to the account.
LEGO_HOOK_CERT_NAME The name/ID of the certificate.
LEGO_HOOK_CERT_NAME_SANITIZED The sanitized name/ID of the certificate.
LEGO_HOOK_CERT_KEY_TYPE The type of the certificate key.
LEGO_HOOK_CERT_DOMAINS The domains of the certificate.
LEGO_HOOK_CERT_PATH The path of the certificate.
LEGO_HOOK_CERT_KEY_PATH The path of the certificate key.
LEGO_HOOK_ISSUER_CERT_PATH The path of the issuer certificate.
LEGO_HOOK_CERT_PEM_PATH (only with --pem) The path to the PEM certificate.
LEGO_HOOK_CERT_PFX_PATH (only with --pfx) The path to the PFX certificate.

Use Case

A typical use case is distributing the certificate for other services and reload them if necessary. Since many programs understand PEM-formatted TLS certificates, it is relatively simple to use certificates for more than a web server.

This example script installs the new certificate for a mail server and reloads it. Beware: this is just a starting point, error checking is omitted for brevity.

#!/bin/bash

# copy certificates to a directory controlled by Postfix
postfix_cert_dir="/etc/postfix/certificates"

# our Postfix server only handles mail for @example.com domain
if [ "$LEGO_HOOK_CERT_NAME" = "example.com" ]; then
  install -u postfix -g postfix -m 0644 "$LEGO_HOOK_CERT_PATH" "$postfix_cert_dir"
  install -u postfix -g postfix -m 0640 "$LEGO_HOOK_CERT_KEY_PATH"  "$postfix_cert_dir"

  systemctl reload postfix@-service
fi

Don’t hesitate to share your hook scripts with the community.

May 13, 2026

Certificate Operations

This section describes certificate operations.

List Certificates

You can list all certificates managed by lego with:

lego certificates list

Output:

Found the following certificates:
_.example.com
├── Status: this certificate is expired.
├── Domains: *.example.com, example.com
├── Expiration Date: 2026-04-08 21:02:27 +0000 UTC
├── Issuer: CN=(STAGING) Puzzling Parsnip E7,O=(STAGING) Let's Encrypt,C=US
└── Certificate Path: /path/to/.lego/certificates/_.example.com.crt

...

Revoke Certificates

You can revoke existing certificates.

Execute the following command:

lego certificates revoke --cert-name 'example.com'

If you have the following .lego.yml configuration file:

certificates:
  foo:
    challenge: http-01
    domains:
      - example.com

And execute:

lego certificates revoke --cert-name foo

When using a configuration file, you can revoke all certificates at once:

lego certificates revoke
Apr 13, 2026

Account Operations

This section describes account operations.

List Accounts

You can list all the accounts registered in your local storage:

lego accounts list

Output:

Found the following accounts:
noemail@example.com
├── Email: 
├── Server: https://acme-v02.api.letsencrypt.org/directory
├── Key Type: EC256
└── Path: /path/to/.lego/accounts/acme-v02.api.letsencrypt.org/noemail@example.com/account.json

...

Register

You can register a new account by using the following command:

lego accounts register --account-id='myaccount'
lego accounts register --account-id='myaccount' \
    --server https://example.com/ca \
    --eab \
    --eab.kid xxx \
    --eab.hmac yyy

Key Rollover

You can change the account private key (a key rollover) by using the following command:

lego accounts keyrollover --account-id='myaccount'

Account Recovery

You can recover/import an account, to do that, you need the private key of the account.

lego account recover --account-id='myaccount' --private-key /path/to/private-key.pem

The account will be imported and added to .lego/accounts/.

Apr 17, 2026

Options

This section describes advanced options that can be used to configure lego.

LEGO_CA_CERTIFICATES

The environment variable LEGO_CA_CERTIFICATES allows to specify the path to PEM-encoded CA certificates that can be used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list.

Multiple file paths can be added by using : (unix) or ; (Windows) as a separator.

Example:

# On Unix system
LEGO_CA_CERTIFICATES=/foo/cert1.pem:/foo/cert2.pem

LEGO_CA_SYSTEM_CERT_POOL

The environment variable LEGO_CA_SYSTEM_CERT_POOL can be used to define if the certificates pool must use a copy of the system cert pool.

Example:

LEGO_CA_SYSTEM_CERT_POOL=true

LEGO_CA_SERVER_NAME

The environment variable LEGO_CA_SERVER_NAME allows to specify the CA server name used to authenticate an ACME server with an HTTPS certificate not issued by a CA in the system-wide trusted root list.

Example:

LEGO_CA_SERVER_NAME=foo

LEGO_DISABLE_CNAME_SUPPORT

By default, lego follows CNAME, the environment variable LEGO_DISABLE_CNAME_SUPPORT allows to disable this support.

Example:

LEGO_DISABLE_CNAME_SUPPORT=true

There is a Let’s Encrypt blog post about the behavior of CNAMEs.

LEGO_DEBUG_CLIENT_VERBOSE_ERROR

The environment variable LEGO_DEBUG_CLIENT_VERBOSE_ERROR allows to enrich error messages from some of the DNS clients.

Example:

LEGO_DEBUG_CLIENT_VERBOSE_ERROR=true

LEGO_DEBUG_DNS_API_HTTP_CLIENT

⚠️ WARNING: This will expose credentials in the log output! ⚠️

Do not run this in production environments, or if you can’t be sure that logs aren’t accessed by third parties or tools (like log collectors).

You have been warned. Here be dragons.

The environment variable LEGO_DEBUG_DNS_API_HTTP_CLIENT allows debugging the DNS API interaction. It will dump the full request and response to the log output.

Some DNS providers don’t support this option.

Example:

LEGO_DEBUG_DNS_API_HTTP_CLIENT=true

LEGO_DEBUG_ACME_HTTP_CLIENT

The environment variable LEGO_DEBUG_ACME_HTTP_CLIENT allows debug the calls to the ACME server.

Example:

LEGO_DEBUG_ACME_HTTP_CLIENT=true
Apr 25, 2026

CA servers

This page describes the usage of CA servers (ACME servers).

Note

Any CA server that follow RFC 8555 can be used with lego.

Let’s Encrypt ACME server

lego defaults to communicating with the production Let’s Encrypt ACME server.

If you’d like to test something without issuing real certificates, consider using the staging endpoint instead:

lego run --server='letsencrypt-staging'

CA Server short-codes

To ease the usage of the CA server in most of cases, we provide a short-code for each already known CA server.

Name Code Directory URL
Actalis actalis https://acme-api.actalis.com/acme/directory
Digicert digicert https://one.digicert.com/mpki/api/v1/acme/v2/directory
FreeSSL freessl https://acmepro.freessl.cn/v2/DV
GlobalSign globalsign https://emea.acme.atlas.globalsign.com/directory
Google Trust googletrust https://dv.acme-v02.api.pki.goog/directory
Google Trust staging googletrust-staging https://dv.acme-v02.test-api.pki.goog/directory
Let’s Encrypt letsencrypt https://acme-v02.api.letsencrypt.org/directory
Let’s Encrypt staging letsencrypt-staging https://acme-staging-v02.api.letsencrypt.org/directory
LiteSSL litessl https://acme.litessl.com/acme/v2/directory
PeeringHub peeringhub https://stica.peeringhub.io/acme
SSL.com ECDSA sslcomecc https://acme.ssl.com/sslcom-dv-ecc
SSL.com RSA sslcomrsa https://acme.ssl.com/sslcom-dv-rsa
Sectigo DV (Domain Validation) sectigo https://acme.sectigo.com/v2/DV
Sectigo EV (Extended Validation) sectigoev https://acme.sectigo.com/v2/EV
Sectigo OV (Organization Validation) sectigoov https://acme.sectigo.com/v2/OV
ZeroSSL zerossl https://acme.zerossl.com/v2/DV90

ZeroSSL

lego supports three different ways to authenticate with ZeroSSL.

  1. Access key: if the environment variable ZERO_SSL_ACCESS_KEY is set.
  2. Email: if the email address is set and the environment variable ZERO_SSL_ACCESS_KEY is not set.
  3. External Account Binding (EAB): if none of the above elements are defined.
May 12, 2026

Archives

This section describes operations on the archives.

List

You can list all the backuped accounts and certificates with the following command:

lego archives list

Restore

You can restore a backup of an account or a certificate with the following command:

lego archives restore

The command will ask you for the backup file to restore.

Apr 13, 2026

Tips

This section contains some tips and tricks for using lego.

Automatic Renewal

It is tempting to create a cron job (or systemd timer) to automatically renew all you certificates.

When doing so, please note that some cron defaults will cause a measurable load on the ACME provider’s infrastructure. Notably @daily jobs run at midnight.

To both counteract load spikes (caused by all lego users) and reduce subsequent renewal failures, we were asked to implement a small random delay for non-interactive renewals.1 Since v4.8.0, lego will pause for up to 8 minutes to help spread the load.

You can help further, by adjusting your crontab entry, like so:

# avoid:
#@daily      /usr/bin/lego ...
#@midnight   /usr/bin/lego ...
#0 0 * * *   /usr/bin/lego ...

# instead, use a randomly chosen time:
35 3 * * *  /usr/bin/lego ...

If you use systemd timers, consider doing something similar, and/or introduce a RandomizedDelaySec:

[Unit]
Description=Renew certificates

[Timer]
Persistent=true
# avoid:
#OnCalendar=*-*-* 00:00:00
#OnCalendar=daily

# instead, use a randomly chosen time:
OnCalendar=*-*-* 3:35
# add extra delay, here up to 1 hour:
RandomizedDelaySec=1h

[Install]
WantedBy=timers.target

Running without root privileges

The CLI does not require root permissions but needs to bind to port 80 and 443 for certain challenges. To run the CLI without sudo, you have four options:

  • Use setcap 'cap_net_bind_service=+ep' /path/to/lego (Linux only)
  • Pass the --http.address or/and the --tls.address option and specify a custom port to bind to. In this case you have to forward port 80/443 to these custom ports (see Port Usage).
  • Pass the --http.webroot option and specify the path to your webroot folder. In this case the challenge will be written in a file in .well-known/acme-challenge/ inside your webroot.
  • Pass the --dns option and specify a DNS provider.

Port Usage

By default, lego assumes it is able to bind to ports 80 and 443 to solve challenges. If this is not possible in your environment, you can use the --http.address and --tls.address options to instruct lego to listen on that interface:port for any incoming challenges.

If you are using either of these options, make sure you setup a proxy to redirect traffic to the chosen ports.

HTTP Port: All plaintext HTTP requests to port 80 which begin with a request path of /.well-known/acme-challenge/ for the HTTP challenge2.

TLS Port: All TLS handshakes on port 443 for the TLS-ALPN challenge.

This traffic redirection is only needed as long as lego solves challenges. As soon as you have received your certificates you can deactivate the forwarding.

DNS Resolvers and Challenge Verification

When using a DNS challenge provider (via --dns <name>), Lego tries to ensure the ACME challenge token is properly setup before instructing the ACME provider to perform the validation.

This involves a few DNS queries to different servers:

  1. Determining the DNS zone and resolving CNAMEs.

    The DNS zone for a given domain is determined by the SOA record, which contains the authoritative name server for the domain and all its subdomains. For simple domains like example.com, this is usually example.com itself. For other domains (like fra.eu.cdn.example.com), this can get complicated, as cdn.example.com may be delegated to the CDN provider, which means for cdn.example.com must exist a different SOA record.

    To find the correct zone, Lego requests the SOA record for each DNS label (starting on the leaf domain, i.e. the left-most DNS label). If there is no SOA record, Lego requests the SOA record of the parent label, then for its parent, etc., until it reaches the apex domain3. Should any DNS label on the way be a CNAME, it is resolved as per usual.

    In the default configuration, Lego uses the system name servers for this, and falls back to Google’s DNS servers, should they be absent.

  2. Verifying the challenge token.

    The _acme-challenge.<yourdomain> TXT record must be correctly installed. Lego verifies this by directly querying the authoritative name server for this record (as detected in the previous step).

Strictly speaking, this verification step is not necessary, but helps to protect your ACME account. Remember that some ACME providers impose a rate limit on certain actions (at the time of writing, Let’s Encrypt allows 300 new certificate orders per account per 3 hours).

There are also situations where this verification step doesn’t work as expected:

  • A “split DNS” setup gives different answers to clients on the internal network (Lego) vs. on the public internet (ACME server).
  • With “hidden master” setups, Lego may be able to directly talk to the primary DNS server, while the _acme-challenge record might not have fully propagated to the (public) secondary servers, yet.

The effect is the same: Lego determined the challenge token to be installed correctly, while the ACME server has a different view and rejects the certificate order.

In these cases, you can instruct Lego to use a different DNS resolver, using the --dns.resolvers flag. You should prefer one on the public internet, otherwise you might be susceptible to the same problem.


  1. See GitHub issue #1656 for an excellent problem description. ↩︎

  2. You must ensure that incoming validation requests contains the correct value for the HTTP Host header. If you operate lego behind a non-transparent reverse proxy (such as Apache or NGINX), you might need to alter the header field using --http.proxy-header X-Forwarded-Host↩︎

  3. The apex domain is the domain you have registered with your domain registrar. For gTLDs (.com, .fyi) this is the 2nd level domain, but for ccTLDs, this can either be the 2nd level (.de) or 3rd level domain (.co.uk). ↩︎