ACME Configuration#
The ACME module in Angie enables automatic certificate
acquisition using the ACME protocol. The ACME protocol supports
various domain verification methods (also called "validation"); this module
implements HTTP validation, DNS validation, and hook-based validation through
a custom external service. General steps to enable certificate requests in the configuration: Configure an ACME client in the Specify the domains for which certificates are requested: A single
certificate will be issued for all domain names listed in server_name
directives within all Set up request handling and ACME callbacks: This is required to verify
domain ownership. The setup depends on the chosen domain validation method: Method Requirements Certificates Requires responding to a specific request (callback) from the ACME
server. Port 80 must be open on the Angie server. Does not support wildcard certificates. Allows issuing multi-domain certificates. Requires handling specific DNS queries (callbacks) from the ACME
server. Requires the ability to modify DNS records. The Angie server must have a port open as specified by the
acme_dns_port directive (default is 53). Supports issuing both multi-domain and wildcard certificates. Requires implementing an external service that Angie communicates with. Requires an external DNS or HTTP server configured by the external
service. The requirements for the external DNS or HTTP server match the
respective points above. Supports issuing both multi-domain and wildcard certificates. Configure SSL using the obtained certificate and key: Certificates and
keys are made available as embedded variables
that can be used in configuration to populate
ssl_certificate and ssl_certificate_key. For SSL setup instructions, refer to SSL Configuration. Client keys and certificates are stored in PEM encoding within subdirectories of the
directory specified by the The ACME client requires an account on the CA server, managed using a private
key ( Note If you already have an account key, place it in the client's subdirectory
before starting to reuse the account. Alternatively, specify the key using
the The client also uses a separate key ( The CA server verifies domain ownership using HTTP or
DNS validation and issues a certificate, which is saved
locally ( As mentioned earlier, a single certificate covers all domains managed by the
same ACME client. The list of all covered names can be found in the Subject
Alternative Name (SAN) field of the certificate. To check this in the terminal: When a certificate is about to expire or domain changes occur, the client
submits a new CSR, and the CA server re-verifies ownership before issuing a new
certificate. In the configuration,
the obtained certificate and its corresponding key
are available through the prefix variables
$acme_cert_<name> and $acme_cert_key_<name>.
Their values are the contents of the respective files,
which should be used with the directives
ssl_certificate and ssl_certificate_key: Validation is handled automatically. The process involves the ACME server, upon
receiving a request, retrieving a special file token via HTTP from the address
In this example, the ACME client named As noted earlier, port 80 must be open to handle HTTP callbacks from ACME.
However, as shown in this example, the listen directive for this port can
be placed in a separate server block. If no existing block with this
directive is present, a new block limited to ACME callbacks can be created: Why does this work? The module intercepts requests to
Validation is handled automatically. When processing a certificate request, the
ACME server performs a special DNS query to the
The ACME module tracks and processes such requests automatically, provided that
your DNS records are configured properly to designate the Angie server as the
authoritative name server for the For example, to verify the domain This configuration delegates DNS resolution for
This method allows requesting wildcard certificates, e.g. a certificate that
will include the entry Attention The applicability of this scenario largely depends on the capabilities of
your DNS provider; some providers do not allow such configurations. The configuration is generally similar to the example in the previous section.
There is no need for HTTP-specific settings; instead, set In this example, the ACME client named Unlike the previous methods, this validation requires additional effort. The
ACME server performs a standard HTTP validation or
DNS validation, but instead of interacting directly
with the Angie server, it communicates with an external service managed by the
Angie server using hooks (acme_hook). This service configures a separate
DNS or HTTP server where the ACME server sends its requests. Once the ACME server receives the expected response from the configured DNS or
HTTP server, it confirms domain ownership. The external service is invoked by Angie when it needs to perform certificate
renewal under the ACME protocol. Requests and data are proxied to FastCGI, SCGI,
or similar servers using directives such as fastcgi_pass,
scgi_pass, etc. The service must return a In this example, the ACME client A A named The following Perl script demonstrates a simple external FastCGI service: Here, If you previously used certbot to obtain and renew
SSL certificates from Let's Encrypt while using nginx, follow these steps to
transition to using the ACME module. Suppose you initially configured certificates with the following command: The configuration automatically created by certbot is typically located in
In the example above, the highlighted lines must be modified. Depending on your
circumstances and preferences, configure HTTP validation or DNS validation using the ACME
module. The resulting Angie configuration might look like this: Remember to reload the configuration after making changes: Once the new configuration is verified, you can delete the certbot
certificates and optionally disable or remove certbot entirely, if it is no
longer used elsewhere:Configuration Steps#
http
block using the
acme_client directive, which specifies a unique client name and other
parameters. Multiple ACME clients can be configured.server
blocks that use acme, pointing to
the same ACME client.Implementation Details#
--http-acme-client-path
build option:$ ls /var/lib/angie/acme/example/
account.key certificate.pem private.key
account.key
). If no key exists, it is generated at startup. The
client registers the account with the CA server using this key.account_key
parameter in acme_client.private.key
) for Certificate
Signing Requests (CSRs). This key is automatically created if needed. At
startup, the client requests a certificate by signing and sending a CSR for all
domains under its management to the CA server.certificate.pem
).$ openssl x509 -in certificate.pem -noout -text | grep -A5 "Subject Alternative Name"
server {
listen 443 ssl;
server_name example.com www.example.com;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
}
HTTP Validation#
/.well-known/acme-challenge/<TOKEN>
. The ACME module intercepts and
processes such requests automatically. When the expected response with the
correct content is received, the ACME server confirms domain ownership.Configuration Example#
example
manages the certificates
for example.com
and www.example.com
(note that wildcards aren't
supported with HTTP validation):http {
resolver 127.0.0.53; # Required for the 'acme_client' directive
acme_client example https://acme-v02.api.letsencrypt.org/directory;
server {
listen 80; # May reside in a different 'server' block
# with a different domain list
# or even without one
listen 443 ssl;
server_name example.com www.example.com;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
}
}
server {
listen 80;
return 444; # No response, connection closed
}
/.well-known/acme-challenge/<TOKEN>
after reading headers but before
selecting a virtual server or processing rewrite and location
directives. Such intercepted requests are processed if the value of
<TOKEN>
matches the expected value for the specific callback. No
directory access is performed; the module handles the request entirely.DNS Validation#
_acme-challenge.
subdomain of the domain being verified. Once the
expected response is received, the ACME server confirms domain ownership._acme-challenge.
subdomain.example.com
using an Angie server at
IP address 93.184.215.14
, your domain's DNS configuration should include
the following records:_acme-challenge.example.com. 60 IN NS ns.example.com.
ns.example.com. 60 IN A 93.184.215.14
_acme-challenge.example.com
to ns.example.com
, ensuring the
availability of ns.example.com
via its IP address
(93.184.215.14
).*.example.com
in the Subject Alternative Name
(SAN) section. To explicitly request a certificate for a subdomain, such as
www.example.com
, you must separately verify that subdomain using the
method described above.Configuration Example#
challenge=dns
in the acme_client directive.example
manages the certificates
for example.com
and *.example.com
:http {
resolver 127.0.0.53;
acme_client example https://acme-v02.api.letsencrypt.org/directory
challenge=dns;
server {
server_name example.com *.example.com;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
}
}
Hook-Based Validation#
2xx
status code, which can be sent via the
Status
header. Any other code is treated as an error, and certificate
renewal is halted. Output from the service is ignored.Configuration Example#
example
is configured to use DNS-based
validation, indicated by the challenge=dns
parameter in the
acme_client
directive.server
block applies to all subdomains of example.com
(e.g.,
*.example.com
) and uses the ACME client example
to manage
certificates, as specified by the acme
directive.location
block is set up to handle external service calls for
DNS validation. The acme_hook
directive links the server to the ACME
client example
. Requests are proxied to a local FastCGI server running
on port 9000 using the fastcgi_pass
directive. The fastcgi_param
directives pass data about the ACME client, hook, challenge type, domain, token,
and key authorization to the external service.acme_client example https://acme-v02.api.letsencrypt.org/directory
challenge=dns;
server {
listen 80;
server_name *.example.com;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
location @acme_hook_location {
acme_hook example;
fastcgi_pass localhost:9000;
fastcgi_param ACME_CLIENT $acme_hook_client;
fastcgi_param ACME_HOOK $acme_hook_name;
fastcgi_param ACME_CHALLENGE $acme_hook_challenge;
fastcgi_param ACME_DOMAIN $acme_hook_domain;
fastcgi_param ACME_TOKEN $acme_hook_token;
fastcgi_param ACME_KEYAUTH $acme_hook_keyauth;
include fastcgi.conf;
}
}
#!/usr/bin/perl
use strict; use warnings;
use FCGI;
my $socket = FCGI::OpenSocket(":9000", 5);
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);
while ($request->Accept() >= 0) {
print "\r\n";
my $client = $ENV{ACME_CLIENT};
my $hook = $ENV{ACME_HOOK};
my $challenge = $ENV{ACME_CHALLENGE};
my $domain = $ENV{ACME_DOMAIN};
my $token = $ENV{ACME_TOKEN};
my $keyauth = $ENV{ACME_KEYAUTH};
if ($hook eq 'add') {
DNS_set_TXT_record("_acme-challenge.$domain.", $keyauth);
} elsif ($hook eq 'remove') {
DNS_clear_TXT_record("_acme-challenge.$domain.");
}
};
FCGI::CloseSocket($socket);
DNS_set_TXT_record()
and DNS_clear_TXT_record()
are
functions assumed to add and remove TXT records in the configuration of an
external DNS server that the ACME server queries. These records must contain the
data provided by the Angie server to allow successful validation, similar to the
process described in DNS Validation. The implementation details of such
functions are beyond the scope of this guide.Migrating from certbot#
$ sudo certbot --nginx -d example.com -d www.example.com
/etc/nginx/sites-available/example.conf
and looks something like this:server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
try_files $uri $uri/ =404;
}
}
http {
resolver 127.0.0.53;
acme_client example https://acme-v02.api.letsencrypt.org/directory;
server {
listen 80;
return 444;
}
server {
listen 443 ssl;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
location / {
try_files $uri $uri/ =404;
}
}
}
$ sudo angie -s reload
$ sudo rm -rf /etc/letsencrypt
$ sudo systemctl stop certbot.timer
$ sudo systemctl disable certbot.timer
$ # -- or --
$ sudo rm /etc/cron.d/certbot
$ sudo apt remove certbot
$ # -- or --
$ sudo dnf remove certbot