Angie ACME / Let’s Encrypt

Angie includes a native ACME client — no Certbot, no cron jobs, no hooks. It handles certificate issuance, renewal, and reloading automatically, all from inside nginx.conf.

How it works

Angie implements the ACME protocol (RFC 8555) directly in the server process. When Angie starts (or reloads), it checks whether the certificate for each acme-enabled server is absent, expiring, or already valid. If a certificate is needed, it completes the HTTP-01 challenge on port 80, saves the certificate and private key to disk, and loads them into memory — all without external tooling.

Renewal is triggered automatically when the certificate has fewer than 30 days remaining (configurable). Angie performs a graceful reload after renewal so in-flight requests are not dropped.

Basic setup

Declare the ACME client once in the http block, then attach it to each server with the acme directive:

http {
    acme_client letsencrypt https://acme-v02.api.letsencrypt.org/directory;

    server {
        listen 80;
        listen 443 ssl;
        server_name example.com;

        acme letsencrypt;
        ssl_certificate      $acme_cert_letsencrypt;
        ssl_certificate_key  $acme_cert_key_letsencrypt;
    }
}

Angie handles the HTTP-01 challenge automatically on port 80. No separate location /.well-known/acme-challenge/ block is needed.

Multiple domains on one certificate

All names in server_name are added to the certificate’s Subject Alternative Name (SAN) list automatically. A single certificate covers all of them:

server {
    listen 443 ssl;
    server_name example.com www.example.com static.example.com;

    acme letsencrypt;
    ssl_certificate      $acme_cert_letsencrypt;
    ssl_certificate_key  $acme_cert_key_letsencrypt;
}

Multiple CAs

Declare multiple acme_client entries and attach more than one to a server. The server will present certificates from whichever CA the client supports best:

acme_client letsencrypt https://acme-v02.api.letsencrypt.org/directory;
acme_client zerossl    https://acme.zerossl.com/v2/DV90;

server {
    acme letsencrypt;
    acme zerossl;
    ssl_certificate      $acme_cert_letsencrypt;
    ssl_certificate_key  $acme_cert_key_letsencrypt;
}

Staging / testing

Use the Let’s Encrypt staging endpoint during testing to avoid hitting rate limits. Staging certificates are not trusted by browsers but are otherwise identical to production certificates:

acme_client letsencrypt_staging
    https://acme-staging-v02.api.letsencrypt.org/directory;

Custom email and storage path

The email parameter registers your contact address with the CA (used for expiry warnings). The path parameter controls where certificates and private keys are stored on disk:

acme_client letsencrypt https://acme-v02.api.letsencrypt.org/directory
    email moc.elpmaxeobfsctd-24c320@nimda
    path /etc/angie/ssl/acme;

Full example with HTTP redirect

http {
    acme_client letsencrypt https://acme-v02.api.letsencrypt.org/directory
        email moc.elpmaxeobfsctd-525a58@nimda;

    server {
        listen 80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        http2 on;
        server_name example.com www.example.com;

        acme letsencrypt;
        ssl_certificate      $acme_cert_letsencrypt;
        ssl_certificate_key  $acme_cert_key_letsencrypt;

        ssl_protocols       TLSv1.2 TLSv1.3;
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 1d;

        location / {
            root /var/www/example.com;
        }
    }
}

Renewal

Angie renews automatically before expiry (default: 30 days before). On renewal it performs a graceful reload — zero downtime, no cron needed. To monitor certificate expiry:

curl -s http://127.0.0.1/status | python3 -m json.tool | grep -A10 '"acme"'

Checking certificate status

With the status API enabled, Angie exposes certificate expiry timestamps in the /status JSON output. Useful for alerting:

location /status {
    api;
    allow 127.0.0.1;
    deny all;
}

# Check expiry from the command line:
curl -s http://127.0.0.1/status | python3 -m json.tool | grep -A5 acme

HTTP-01 challenge behind a proxy

If Angie sits behind a load balancer or CDN, HTTP-01 challenges must reach Angie on port 80. Forward challenge traffic through the upstream proxy:

# Upstream proxy: forward challenge traffic to Angie
location /.well-known/acme-challenge/ {
    proxy_pass http://angie_backend;
}

Frequently asked questions

Does Angie ACME work if port 80 is blocked?

Not with HTTP-01 challenges. Let’s Encrypt requires port 80 to be reachable from the internet for HTTP-01. If port 80 is blocked by a firewall, use DNS-01 challenges instead — but Angie’s built-in ACME module only supports HTTP-01. For DNS-01 you would need Certbot with a DNS plugin.

Can I use Angie ACME with wildcard certificates?

No. Wildcard certificates require DNS-01 challenges. The Angie ACME module only supports HTTP-01, which validates domain control via a file served on port 80. Wildcards are not possible with HTTP-01.

Where does Angie store the certificates?

In the path specified by the path parameter of acme_client. The default is /etc/angie/acme/. The private key and certificate are stored as PEM files and referenced by the $acme_cert_* and $acme_cert_key_* variables.

What happens if the ACME CA is unreachable at renewal time?

Angie will retry. As long as the existing certificate has not yet expired, it continues serving the current certificate. Let’s Encrypt certificates are valid for 90 days; with a 30-day renewal window there is a 60-day buffer for retries. If the certificate does expire, Angie logs an error and stops serving TLS on that server.

Can I use Angie ACME with an internal CA (e.g. Step CA)?

Yes — any ACME-compatible CA works. Set the acme_client URL to your internal CA’s ACME directory URL. Step CA, Smallstep, HashiCorp Vault PKI, and EJBCA all support RFC 8555.

Does ACME renewal cause any downtime?

No. Angie performs a graceful reload after issuing a new certificate. Active connections complete normally; new connections start using the new certificate. The reload typically takes under 100 ms.

How do I migrate from Certbot to Angie ACME?

  1. Add the acme_client and acme directives to your config
  2. Change ssl_certificate and ssl_certificate_key to the $acme_cert_* variables
  3. Run angie -t to check the config
  4. Reload Angie: systemctl reload angie
  5. Angie will fetch a new certificate immediately on reload
  6. Once confirmed working, remove Certbot: apt-get remove certbot and delete the cron/systemd timer

Further reading

Leave a comment