Настройка ACME#

Модуль ACME в Angie обеспечивает автоматическое получение сертификатов с использованием протокола ACME. Протокол ACME предусматривает несколько способов проверки доменов (также используется термин верификация); модуль реализует HTTP-проверку, DNS-проверку, ALPN-проверку, а также проверку с помощью хуков через самостоятельно реализуемый внешний сервис.

Шаги настройки#

Общие шаги для включения запроса сертификатов в конфигурации:

  • Настройте ACME-клиент в блоке http с помощью директивы acme_client, задающей уникальное имя клиента и другие параметры; можно настроить несколько клиентов ACME.

  • Укажите домены, для которых запрашиваются сертификаты: для доменных имен, перечисленных во всех директивах server_name всех блоков server с директивами acme, указывающими на один и тот же ACME-клиент, будет выдан единый сертификат.

  • Настройте обработку запросов и вызовов ACME: это нужно для проверки владения доменом. Способ настройки зависит от способа проверки доменных имен:

    Способ

    Требования к пользователю

    Мультидомены

    Домены со звездочкой

    HTTP-проверка

    Открыть порт 80 (или указанный в acme_http_port) для входящих соединений на сервере Angie.

    DNS-проверка

    Открыть порт 53 (или указанный в acme_dns_port) для входящих соединений на сервере Angie.

    Настроить NS-запись для поддомена _acme-challenge., направив ее на свой сервер Angie.

    ALPN-проверка

    Открыть порт 443 (или TLS-порт, используемый сервером Angie) для входящих соединений.

    Проверка хуками

    Реализовать внешний сервис (скрипт или приложение), который по команде Angie сможет внести изменения в DNS-зону или разместить специальный ответ на веб-сервере.

  • Настройте SSL с использованием полученного сертификата и ключа: Модуль делает сертификаты и ключи доступными в виде встроенных переменных, которые можно использовать в конфигурации для заполнения ssl_certificate и ssl_certificate_key.

    Инструкции по настройке SSL см. в разделе Настройка SSL.

Совет

Процесс получения и обновления сертификатов зависит от работы многих служб и может занимать какое-то время. Запаситесь терпением, а в случае возникновения проблем или сомнений обратитесь к отладочному логу.

Подробности реализации#

Здесь ключи и сертификаты клиентов хранятся в кодировке PEM в соответствующих подкаталогах каталога, заданного с помощью параметра сборки --http-acme-client-path:

$ ls /var/lib/angie/acme/example/

  account.key  certificate.pem  private.key

Клиенту ACME требуется учетная запись на сервере CA. Для ее создания и управления ею клиент использует закрытый ключ (account.key); если ключа у него еще нет, ключ создается при запуске. Затем клиент использует его для регистрации учетной записи на сервере.

Примечание

Если у вас уже есть ключ учетной записи, поместите его в подкаталог клиента перед запуском для повторного использования учетной записи. Файл ключа также можно указать с помощью параметра account_key в acme_client.

Клиент 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;
}

HTTP-проверка#

Проверка работает автоматически. Суть ее заключается в том, что ACME-сервер, получив запрос, запрашивает у клиента через HTTP особый файл-токен по адресу /.well-known/acme-challenge/<TOKEN>. Наш модуль ACME отслеживает такие запросы и самостоятельно обрабатывает их. Получив ожидаемый ответ с нужным содержимым, ACME-сервер подтверждает, что домен принадлежит клиенту.

Пример конфигурации#

Здесь ACME-клиент с именем example управляет сертификатами для example.com и www.example.com (учтите, что wildcard-сертификаты не поддерживаются при HTTP-проверке):

http {

    resolver 127.0.0.53; # требуется для директивы 'acme_client'

    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;
    }
}

Как уже отмечалось, порт 80 должен быть открыт для приема вызовов ACME по HTTP. Если ни один сервер не слушает порт HTTP‑проверки, модуль создаст отдельный слушающий сокет на порту 80 (или указанном в acme_http_port). Отдельный блок server не требуется.

DNS-проверка#

Проверка работает автоматически. Суть в том, что при получении запроса на сертификат ACME-сервер выполняет специальный DNS-запрос к поддомену _acme-challenge. проверяемого домена. После получения ожидаемого ответа ACME-сервер подтверждает, что домен принадлежит клиенту.

Наш модуль ACME отслеживает такие запросы и обрабатывает их автоматически, при условии, что ваши записи DNS настроены должным образом, чтобы указать сервер Angie в качестве авторитетного сервера имен для поддомена _acme-challenge..

Например, чтобы подтвердить домен example.com, используя сервер Angie с IP-адресом 93.184.215.14, DNS-конфигурация вашего домена должна включать следующие записи:

_acme-challenge.example.com. 60    IN      NS       ns.example.com.
             ns.example.com. 60    IN       A       93.184.215.14

Эта конфигурация делегирует разрешение DNS для _acme-challenge.example.com на ns.example.com, обеспечивая доступность ns.example.com путем сопоставления с IP-адресом (93.184.215.14).

Предупреждение

Распространение изменений 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-записи для сервера имен

  93.184.215.14

$ nc -zv 93.184.215.14 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 {

    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;
    }
}

ALPN-проверка#

Проверка работает автоматически. ACME‑сервер устанавливает TLS‑соединение и запрашивает через ALPN протокол acme-tls/1. Модуль отдает временный сертификат для валидационного запроса.

Чтобы использовать этот способ, задайте challenge=alpn в директиве acme_client и убедитесь, что ваш TLS‑слушатель доступен на порту 443 (или на используемом TLS‑порту).

Проверка с помощью хуков#

В отличие от предыдущих способов, эта проверка требует дополнительных усилий. Здесь ACME-сервер производит обычную HTTP-проверку или DNS-проверку, но обращается не к самому серверу Angie, а к внешнему сервису, которым сервер Angie управляет с помощью вызовов-хуков (acme_hook). В свою очередь, этот сервис настраивает отдельный DNS- или HTTP-сервер, куда и направляются запросы ACME-сервера.

Получив ожидаемый ответ от настроенного таким образом DNS- или HTTP-сервера, ACME-сервер подтверждает, что домен принадлежит клиенту.

Angie вызывает внешний сервис в моменты, когда требуется обновление сертификатов по протоколу ACME. Вызовы передаются путем проксирования запросов и данных на серверы FastCGI, SCGI и аналогичные с использованием директив fastcgi_pass, scgi_pass и т.д.

Сервис должен возвращать код 2xx, что можно сделать через заголовок Status. Любой другой код считается ошибкой, и обновление сертификата прекращается. При этом вывод от сервиса игнорируется.

Пример конфигурации#

Здесь настраивается ACME-клиент example для подтверждения домена при помощи DNS-вызова, на что указывает параметр challenge=dns директивы acme_client.

Блок server применяется ко всем поддоменам example.com (например, *.example.com) и использует ACME-клиент example для управления сертификатами, что указано в директиве acme.

Здесь также настроен именованный блок location, через который и производятся вызовы внешнего сервиса для DNS-верификации. Директива 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;
    }
}

Пример соответствующего внешнего FastCGI-сервиса на Perl:

#!/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;
}

Еще один пример настройки FastCGI-сервиса на 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
# ...

Переданные параметры доступны в PHP через $_SERVER['...'].

ACME в потоковом модуле#

Потоковый модуль ACME позволяет автоматизировать выпуск и использование сертификатов для TCP-трафика. Для его корректной работы необходимо сначала настроить HTTP-аналог: ACME-клиент должен быть объявлен в контексте http, а сам блок stream должен располагаться после блока http в конфигурации.

Пример конфигурации#

По умолчанию для получения сертификатов используется режим HTTP-проверки. Для него, как упоминалось в разделе HTTP-проверка, нужен HTTP-сервер, слушающий на порту 80:

# HTTP-часть
http {

    resolver 127.0.0.53;

    # 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;
    }
}

Также можно использовать DNS-проверку, настроив challenge=dns в директиве acme_client; тогда сервер будет не нужен.

Миграция с certbot#

Если до перехода с nginx на Angie вы использовали certbot для получения и продления SSL-сертификатов от центра сертификации Let's Encrypt, выполните следующие шаги, чтобы перейти к использованию нашего модуля ACME.

Предположим, вы настроили сертификаты следующим образом:

$ sudo certbot --nginx -d example.com -d www.example.com

Автоматически созданная при этом конфигурация обычно находится в файле /etc/nginx/sites-available/example.conf и выглядит приблизительно так:

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;
}

В примере выше выделены строки, которые потребуется изменить. В зависимости от ваших обстоятельств и предпочтений настройте HTTP-проверку или DNS-проверку с помощью модуля ACME.

Итоговая конфигурация Angie может выглядеть приблизительно так:

http {

    resolver 127.0.0.53;

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

    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;

        acme                 example;

        ssl_certificate      $acme_cert_example;
        ssl_certificate_key  $acme_cert_key_example;
    }
}

Не забудьте перезагрузить конфигурацию после изменения:

$ sudo kill -HUP $(cat /run/angie.pid)

Убедившись, что эта конфигурация работает, вы можете удалить сертификаты certbot, а также отключить или целиком удалить его с сервера, если он больше нигде не используется, например:

$ sudo rm -rf /etc/letsencrypt

$ sudo systemctl stop certbot.timer
$ sudo systemctl disable certbot.timer
$ # -- или --
$ sudo rm /etc/cron.d/certbot

$ sudo apt remove certbot
$ # -- или --
$ sudo dnf remove certbot