Настройка ACME#
Шаги настройки#
Общие шаги для включения запроса сертификатов в конфигурации:
Настройте ACME-клиент в блоке
httpс помощью директивы acme_client, задающей уникальное имя клиента и другие параметры; можно настроить несколько клиентов ACME.Укажите домены, для которых запрашиваются сертификаты: для доменных имен, перечисленных во всех директивах server_name всех блоков
serverс директивами acme, указывающими на один и тот же ACME-клиент, будет выдан единый сертификат.IP-адреса (IPv4 или IPv6), указанные в server_name, также являются допустимыми идентификаторами сертификата, за исключением DNS-проверки.
Обратите внимание: публичные центры сертификации могут выдавать сертификаты для IP-адресов только в рамках определенных профилей сертификатов; например, Let's Encrypt в настоящее время требует профиль, допускающий IP-идентификаторы (см. документацию по профилям). Чтобы запросить такой профиль, задайте параметр
profile=директивы acme_client.Настройте обработку запросов и вызовов ACME: это нужно для проверки владения доменом. Способ настройки зависит от способа проверки доменных имен:
Способ
Требования к пользователю
Мультидомены
Домены со звездочкой
Открыть порт 80 (или указанный в acme_http_port) для входящих соединений на сервере Angie.
✔
Открыть порт 53 (или указанный в acme_dns_port) для входящих соединений на сервере Angie.
Настроить NS-запись для поддомена
_acme-challenge., направив ее на свой сервер Angie.✔
✔
Открыть порт 443 (или TLS-порт, используемый сервером Angie) для входящих соединений.
✔
Реализовать внешний сервис (скрипт или приложение), который по команде Angie сможет внести изменения в DNS-зону или разместить специальный ответ на веб-сервере.
✔
✔
Подробности реализации#
Клиенту ACME требуется учетная запись на сервере CA.
Для ее создания и управления ею клиент использует закрытый ключ
(account.key);
если ключа у него еще нет, ключ создается при запуске.
Затем клиент использует его для регистрации учетной записи на сервере.
Примечание
Если у вас уже есть ключ учетной записи,
поместите его в подкаталог клиента перед запуском
для повторного использования учетной записи.
Файл ключа также можно указать с помощью параметра account_key
в acme_client.
Некоторые CA требуют привязать учетную запись ACME к уже существующей внешней
учетной записи с помощью External Account Binding (EAB), прежде
чем выпускать сертификаты. Для этого задайте параметр eab
директивы acme_client, указав идентификатор ключа и MAC-ключ,
предоставленные CA; точный синтаксис приведен в описании директивы.
Клиент ACME также использует отдельный ключ
(private.key) для запросов на подпись сертификата (CSR);
если нужно, этот ключ сертификата также создается автоматически при запуске.
При запуске клиент запрашивает сертификат, если его еще нет,
подписывая и отправляя CSR для всех доменов, которыми он управляет, серверу CA.
Сервер проверяет владение доменом
путем HTTP- или DNS-проверки
и выдает сертификат,
который клиент сохраняет локально (certificate.pem).
Как сказано выше, сертификат будет единым для всех доменных имен, для которых используется один и тот же ACME-клиент, то есть потенциально может быть мультидоменным. Список всех имен, для которых выдан сертификат, см. в разделе Subject Alternative Name (SAN) полученного сертификата. Проверить его можно в командной строке, например:
$ openssl x509 -in certificate.pem -noout -text | grep -A5 "Subject Alternative Name"
Когда приближается завершение срока действия сертификата или изменяется список доменов, клиент подписывает и отправляет еще один CSR на сервер CA. Сервер снова проверяет владение и выдает новый сертификат, который клиент устанавливает локально, заменяя предыдущий.
В конфигурации полученный сертификат и соответствующий ключ доступны через префиксные переменные $acme_cert_<имя> и $acme_cert_key_<имя>. Их значения — содержимое соответствующих файлов, которое следует использовать с директивами ssl_certificate и ssl_certificate_key, например:
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;
}
Примечание
Клиент ACME определяет адрес сервера CA по его имени через resolver
того же контекста, который по умолчанию обращается к DNS-серверам из
/etc/resolv.conf; задавайте директиву явно, только если нужны
другие серверы или параметры. На узле без поддержки IPv6 resolver может
все равно отправлять AAAA-запросы (IPv6) для сервера CA и не суметь
подключиться; отключите их параметром ipv6=off, например
resolver conf ipv6=off;.
Сбор доменов и использование сертификата#
Директива acme служит только для сбора доменных имен
для запросов сертификатов.
Она не определяет, где можно использовать сертификат:
любой блок server может ссылаться на полученный сертификат
через переменную $acme_cert_<имя>,
независимо от того, содержит ли блок директиву acme.
Например, если у вас есть блок server с маской,
который уже охватывает все поддомены,
дополнительные блоки server для конкретных поддоменов
не нуждаются в директиве acme:
http {
acme_client example https://acme-v02.api.letsencrypt.org/directory
challenge=dns;
# В этом блоке перечислены домены для запроса сертификата
server {
listen 443 ssl;
server_name example.com *.example.com;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
}
# Этот блок использует тот же сертификат, но не добавляет
# свой server_name в запрос на сертификат
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
}
}
Явный список доменов#
Чтобы точно контролировать набор доменных имен в сертификате,
не полагаясь на автоматический сбор из всех блоков server,
создайте отдельный блок server,
содержащий только директивы server_name и acme.
Чтобы этот блок не обрабатывал реальный трафик,
привяжите его к Unix-сокету:
# Отдельный блок, определяющий список доменов сертификата
server {
listen unix:/tmp/acme_example.sock;
server_name example.com www.example.com;
acme example;
}
Другие блоки server могут затем использовать сертификат
через переменную $acme_cert_<имя>,
не влияя на то, какие домены запрашиваются.
Отдельные сертификаты для разных доменов#
Каждый acme_client управляет одним сертификатом. Чтобы получить
несколько независимых сертификатов (например, для несвязанных доменов, которым
не следует использовать общий сертификат), настройте отдельный
acme_client для каждого из них в блоке http и укажите в директиве
acme каждого блока server соответствующий клиент по имени:
http {
# Два независимых клиента, каждый управляет своим сертификатом
acme_client shop https://acme-v02.api.letsencrypt.org/directory
challenge=http;
acme_client blog https://acme-v02.api.letsencrypt.org/directory
challenge=http;
server {
listen 443 ssl;
server_name shop.example.com www.shop.example.com;
acme shop;
ssl_certificate $acme_cert_shop;
ssl_certificate_key $acme_cert_key_shop;
}
server {
listen 443 ssl;
server_name blog.example.com;
acme blog;
ssl_certificate $acme_cert_blog;
ssl_certificate_key $acme_cert_key_blog;
}
}
HTTP-проверка#
Проверка выполняется автоматически.
Когда Angie заказывает сертификат, ACME-сервер
запрашивает по HTTP
файл-токен по адресу Здесь ACME-клиент с именем Как уже отмечалось,
порт 80 должен быть открыт для приема вызовов ACME по HTTP.
Если ни один сервер не слушает порт HTTP-проверки,
модуль создает отдельный слушающий сокет на порту 80
(или указанном в acme_http_port). Отдельный блок
server не требуется./.well-known/acme-challenge/<TOKEN>.
Angie отвечает на такие запросы сам, поэтому отдавать этот путь
вручную не требуется. Получив файл, ACME-сервер сверяет токен
с выданным значением и, если они совпадают, засчитывает проверку домена.Пример конфигурации#
example управляет сертификатами для
example.com и www.example.com
(учтите, что wildcard-сертификаты не поддерживаются при HTTP-проверке):http {
acme_client example https://acme-v02.api.letsencrypt.org/directory;
server {
listen 80; # Не обязательно: если порт HTTP-проверки
# никто не слушает, модуль откроет его сам
# (см. директиву 'acme_http_port')
listen 443 ssl;
server_name example.com www.example.com;
acme example;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
}
}
DNS-проверка#
Проверка выполняется автоматически, но требует настройки DNS с вашей стороны.
Когда Angie заказывает сертификат, ACME-сервер отправляет DNS-запрос
TXT-записи в поддомене _acme-challenge. проверяемого домена.
Angie отвечает на такие запросы сам: он выступает авторитетным сервером имен
для этого поддомена и возвращает TXT-запись с тем значением, которого ждет
ACME-сервер. ACME-сервер сверяет полученную запись с выданным значением и,
если они совпадают, засчитывает проверку домена.
Чтобы запрос дошел до Angie, DNS вашего домена должен делегировать поддомен
_acme-challenge. серверу Angie; нужные записи приведены ниже.
По умолчанию Angie отвечает с очень небольшим TTL, а некоторые DNS-провайдеры
отфильтровывают ответы с таким низким TTL — если проверка не завершается,
увеличьте его директивой acme_dns_ttl.
DNS-проверка подтверждает контроль над доменным именем,
поэтому не может проверять идентификаторы в виде IP-адресов:
для клиента с challenge=dns Angie игнорирует IP-адрес
в server_name и выводит предупреждение при запуске.
Блок server, в котором указан IP-адрес, должен по-прежнему содержать
хотя бы одно доменное имя, которое клиент может проверить.
Примечание
Сервер Angie должен быть доступен из интернета на UDP-порту 53 (или указанном в acme_dns_port). Если сервер находится за межсетевым экраном, убедитесь, что этот порт открыт для входящих соединений.
Например, чтобы подтвердить домен example.com,
используя сервер Angie с IP-адресом 203.0.113.10,
DNS-конфигурация вашего домена должна включать следующие записи:
_acme-challenge.example.com. 60 IN NS ns.example.com.
ns.example.com. 60 IN A 203.0.113.10
Эта конфигурация делегирует разрешение DNS для
_acme-challenge.example.com на ns.example.com,
обеспечивая доступность ns.example.com
путем сопоставления с IP-адресом (203.0.113.10).
Предупреждение
Распространение изменений NS-записей может занимать от нескольких минут до 48 часов в зависимости от TTL и DNS-провайдера. Рекомендуется проверить корректность настройки перед запросом сертификата.
Для проверки корректности настройки DNS можно использовать следующие команды:
$ dig NS _acme-challenge.example.com +short # Проверка NS-записи для поддомена _acme-challenge
ns.example.com.
$ dig A ns.example.com +short # Проверка A-записи для сервера имен
203.0.113.10
$ nc -zv 203.0.113.10 53 # Проверка доступности DNS-сервера на порту 53
Этот способ позволяет запрашивать wildcard-сертификаты, например сертификат,
включающий запись *.example.com в разделе Subject Alternative Name
(SAN). Чтобы в явной форме запросить сертификат для поддомена, например
www.example.com, следует отдельно подтвердить этот поддомен описанным
выше способом.
Предупреждение
Применимость данного сценария во многом зависит от возможностей, предоставляемых вашим DNS-провайдером; некоторые провайдеры не позволяют выполнять такие настройки.
Пример конфигурации#
В целом, конфигурация схожа с примером из предыдущего раздела.
Нет необходимости в настройках, специфичных для HTTP;
вместо этого достаточно установить challenge=dns
для директивы acme_client.
Здесь ACME-клиент с именем example управляет сертификатами для
example.com и *.example.com:
http {
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;
}
}
ALPN-проверка#
Проверка работает автоматически. ACME‑сервер устанавливает TLS‑соединение и
запрашивает через ALPN протокол acme-tls/1. Модуль отдает временный
сертификат для валидационного запроса.
Чтобы использовать этот способ, задайте Конфигурация аналогична предыдущим разделам; достаточно задать
Здесь ACME-клиент с именем challenge=alpn в директиве
acme_client и убедитесь, что ваш TLS‑слушатель доступен на порту 443
(или на используемом TLS‑порту).Пример конфигурации#
challenge=alpn для директивы acme_client и убедиться, что
TLS-сервер доступен на порту 443.example управляет сертификатом для
example.com и www.example.com:http {
acme_client example https://acme-v02.api.letsencrypt.org/directory
challenge=alpn;
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;
}
}
Проверка с помощью хуков#
В отличие от предыдущих способов, эта проверка требует дополнительных усилий. Здесь ACME-сервер производит обычную HTTP-проверку или DNS-проверку, но обращается не к самому серверу Angie, а к внешнему сервису, которым сервер Angie управляет с помощью вызовов-хуков (acme_hook). В свою очередь, этот сервис настраивает отдельный DNS- или HTTP-сервер, куда и направляются запросы ACME-сервера.
Получив ожидаемый ответ от настроенного таким образом DNS- или HTTP-сервера, ACME-сервер подтверждает, что домен принадлежит клиенту.
Когда для выпуска или обновления сертификата требуется проверка домена,
Angie формирует внутренний запрос
к именованному location, содержащему директиву acme_hook.
Способ обработки этого запроса полностью зависит
от других директив, заданных в том же location.
Общая схема такова:
Обработчик должен возвращать код состояния Независимо от используемого обработчика,
При DNS-проверке обработчик должен использовать Здесь настраивается ACME-клиент Блок Именованный блок Пример соответствующего внешнего FastCGI-сервиса на Perl: Здесь Еще один пример, с использованием PHP-FPM: Переданные параметры доступны в PHP через 2xx,
который можно передать через заголовок Status.
Любой другой код от хука add прерывает попытку обновления сертификата;
от хука remove тот же код только записывается в журнал
как предупреждение, и обновление продолжается.
Вывод обработчика игнорируется.Минимальная конфигурация#
location для хука имеет следующую структуру:ACME_HOOK
для определения действия:
если значение add,
создать TXT-запись для _acme-challenge.ACME_DOMAIN
со значением из ACME_KEYAUTH;
если значение remove, удалить эту запись.Пример с FastCGI#
example
для подтверждения домена при помощи DNS-вызова,
на что указывает параметр challenge=dns директивы acme_client.server применяется ко всем поддоменам example.com
(например, *.example.com)
и использует ACME-клиент example для управления сертификатами,
что указано в директиве acme.location обрабатывает вызовы хуков.
Директива acme_hook связывает его
с ACME-клиентом example.
Запросы хуков отправляются на локальный FastCGI-сервер
на порту 9000 с помощью fastcgi_pass.
Директивы fastcgi_param передают
переменные ACME во внешний сервис.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() и DNS_clear_TXT_record() —
функции, предположительно добавляющие и удаляющие TXT-записи
в конфигурации некого внешнего DNS-сервера, к которому и обратится ACME-сервер.
В этих записях должны содержаться переданные сервером Angie данные,
что позволит внешнему DNS-серверу успешно пройти проверку,
аналогичную описанной в разделе DNS-проверка.
Подробности реализации таких функций выходят за рамки этого руководства;
так, например, передавать параметры можно и через URI запроса:# ...
location @acme_hook_location {
acme_hook example uri=/acme_hook/$acme_hook_name?domain=$acme_hook_domain&key=$acme_hook_keyauth;
fastcgi_pass localhost:9000;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param ACME_CLIENT $acme_hook_client;
fastcgi_param ACME_CHALLENGE $acme_hook_challenge;
fastcgi_param ACME_TOKEN $acme_hook_token;
include fastcgi.conf;
}
Пример с PHP-FPM#
location @acme_hook_location {
acme_hook example;
root /var/www/dns;
fastcgi_pass unix:/run/php-fpm/php-dns.sock;
fastcgi_index hook.php;
fastcgi_param SCRIPT_FILENAME /var/www/dns/hook.php;
include fastcgi_params;
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;
}
[dns]
listen = /run/php-fpm/php-dns.sock
listen.mode = 0666
user = angie
group = angie
chdir = /var/www/dns
# ...
$_SERVER['...'].
ACME в потоковом модуле#
Потоковый модуль ACME позволяет автоматизировать
выпуск и использование сертификатов для TCP-трафика.
Для его корректной работы необходимо сначала настроить HTTP-аналог:
ACME-клиент должен быть объявлен в контексте По умолчанию для получения сертификатов используется режим HTTP-проверки.
Для него, как упоминалось в разделе HTTP-проверка,
нужен HTTP-сервер, слушающий на порту 80: Также можно использовать DNS-проверку,
настроив http,
а сам блок stream должен располагаться после блока http
в конфигурации.Пример конфигурации#
# HTTP-часть
http {
# ACME-клиент для потоковой части
acme_client example https://acme-v02.api.letsencrypt.org/directory;
# Сервер для HTTP-проверки
server {
listen 80;
return 444;
}
}
# Потоковая часть
stream {
server {
listen 12345 ssl;
proxy_pass backend_upstream;
ssl_certificate $acme_cert_example;
ssl_certificate_key $acme_cert_key_example;
server_name example.com www.example.com;
acme example; # ссылка на ACME-клиент, определенный в HTTP-части
}
upstream backend_upstream {
server 127.0.0.1:54321;
}
}
challenge=dns в директиве acme_client;
тогда сервер будет не нужен.