- Исходные данные
$ uname -sr FreeBSD 11.2-RELEASE-p5 $ pkg info | grep acme.sh acme.sh-2.7.9_1 ACME protocol client written in shell
Тип получаемого сертификата: wildcard. Это означает, что проверка владения доменом определяется только через DNS;
DNS-сервера: размещены у регистратора r01.ru. Изменения зон на DNS-серверах этого регистратора производятся в течение 40 минут.
- acme.sh - установка
# cd /usr/ports/security/acme.sh # make install clean
Настройки в процессе установки:[ ] BINDTOOLS Depend on bind-tools for nsupdate [x] DOCS Build and/or install documentation [ ] STANDALONE Standalone mode requires SOCAT ─────────────────────────────────── HTTP ───────────────────────────────── (*) CURL Depend on cURL for HTTP(S) queries ( ) WGET Depend on Wget for HTTP(S) queries
- Выпуск сертификата вручную
Для тех, кто забыл, напоминаю: зона расположена у регистратора r01.ru, у которого данные на dns серверах обновляются в течение 40 минут.# acme.sh --issue -d mysite.com -d *.mysite.com --dns dns_show --dnssleep 2500 --force
--dnssleep 2500 - задержка в ~41 минуту
--force - добавлять, если выполняете строку из-под root или при помощи sudo
В процессе нас попросят добавить в зону mysite.com две текстовые записи _acme-challenge. Добавляем, как и просят, ДВЕ записи, с разным содержимым.
Ждем 41 минуту.
Затем:# acme.sh --renew -d mysite.com -d *.mysite.com
Мы делали операции от root, поэтому сертификаты ищем в /root/.acme.sh
- DNS API hook для r01.ru
У меня все же дошли руки написать hook для автоматического добавления записей на dns сервера регистратора r01.ru через их SOAP API. acme.sh предполагает использование интерпретатора sh, я с SOAP умею работать только через perl, поэтому получилось то, что получилось. Я знаю, что нет предела совершенству, в том числе и в вылизывании кода, но мой вполне себе работает (а больше от него ничего не надо).
Итак.
Файл /root/.acme.sh/dns_r01.sh:#!/usr/bin/env sh ######################################################################## # r01.ru API hook script for acme.sh # # Author: Skull # Site: http://www.site-motor.ru/ #-- dns_r01_add() - Add TXT record -------------------------------------- # Usage: dns_r01_add _acme-challenge.subdomain.domain.com "XyZ123..." dns_r01_add() { _full_domain=$1 _txt_value=$2 _info "Using r01.ru DNS API hook" /root/.acme.sh/dnsapi/r01-add.pl $1 $2 } #-- dns_r01_rm() - Remove TXT record ------------------------------------ # Usage: dns_r01_rm _acme-challenge.subdomain.domain.com "XyZ123..." dns_r01_rm() { _full_domain=$1 _txt_value=$2 _info "Cleaning up after use r01.ru DNS API hook" /root/.acme.sh/dnsapi/r01-rm.pl $1 }
Как видите, я из sh-скрипта тупо передаю все в perl-скрипт.
Файл /root/.acme.sh/dnsapi/r01-add.pl:#!/usr/bin/env perl use strict; use warnings; use SOAP::Lite; use HTTP::Cookies; $|=1; my $user = ''; my $pass = ''; my $domain = $ARGV[0]; $domain =~ s/^_acme-challenge\.//; my $record = $ARGV[1]; print "DOMAIN:\t$domain\n"; print "DNS:\t_acme-challenge=$record\n"; my $soap = SOAP::Lite->new( user_agent => 'RegbaseSoapInterfaceClient', default_ns => 'urn:RegbaseSoapInterface' ); $soap->proxy( 'https://partner.r01.ru:1443/partner_api.khtml', cookie_jar => ( HTTP::Cookies->new( autosave => 1, ignore_discard => 1 )) ); # логин my $login = $soap->logIn($user,$pass); die 'logIn() ERROR ==> '.$login->faultstring if ($login->fault); print 'logIn() ',$login->result->{status}{code},': ',$login->result->{status}{name},"\n"; $soap->set_cookie('SOAPClient',$login->result->{status}{message}); # добавляем запись _acme-challenge my $params = SOAP::Data->value( SOAP::Data->name('domain' => uc($domain)), SOAP::Data->name('type_record' => 'TXT'), SOAP::Data->name('params' => \SOAP::Data->value( SOAP::Data->name('owner' => '_acme-challenge'), SOAP::Data->name('data' => $record), )) ); my $ret = $soap->addNewRrRecord($params); die 'addNewRrRecord() ERROR ==> '.$ret->faultstring if ($ret->fault); print 'addNewRrRecord() ',$ret->result->{status}{code},': ',$ret->result->{status}{name},"\n"; exit;
$user, $pass - здесь надо задать логин и пароль для API r01.ru
Файл /root/.acme.sh/dnsapi/r01-rm.pl:#!/usr/bin/env perl use strict; use warnings; use SOAP::Lite; use HTTP::Cookies; $|=1; my $user = ''; my $pass = ''; my $domain = $ARGV[0]; $domain =~ s/^_acme-challenge\.//; print "DOMAIN:\t$domain\n"; my $soap = SOAP::Lite->new( user_agent => 'RegbaseSoapInterfaceClient', default_ns => 'urn:RegbaseSoapInterface' ); $soap->proxy( 'https://partner.r01.ru:1443/partner_api.khtml', cookie_jar => ( HTTP::Cookies->new( autosave => 1, ignore_discard => 1 )) ); # логин в систему my $login = $soap->logIn($user,$pass); die 'logIn() ERROR ==> '.$login->faultstring if ($login->fault); print 'logIn() ',$login->result->{status}{code},': ',$login->result->{status}{name},"\n"; $soap->set_cookie('SOAPClient',$login->result->{status}{message}); # читаем записи домена my $records = $soap->getRrRecords(uc($domain)); die 'getRrRecords() ERROR ==> '.$records->faultstring if ($records->fault); print 'getRrRecords() ',$records->result->{status}{code},': ',$records->result->{status}{name},"\n"; for my $el (@{$records->result->{data}}){ if($el->{owner} eq '_acme-challenge'){ # удаляем запись my $ret = $soap->deleteRrRecord($el->{id}); die 'deleteRrRecord() '.$el->{id}.' ERROR ==> '.$ret->faultstring if ($ret->fault); print 'deleteRrRecord() ',$ret->result->{status}{code},': ',$ret->result->{status}{name},"\n"; } } # выход из системы my $logout = $soap->call('logOut'); exit;
$user, $pass - здесь надо задать логин и пароль для API r01.ru
Не забываем все файлы сделать исполняемыми (chmod +x)
- Выпуск сертификата в автоматическом режиме
# acme.sh --issue -d mysite.com -d *.mysite.com --dns dns_r01 --dnssleep 2500
В результате записи _acme-challenge будут автоматически добавлены в dns, но в процессе придется сидеть и ждать 2500 секунд. После чего записи в dns также автоматически будут удалены и вы станете счастливым обладателем wildcard-сертификата.
- Автоматический перевыпуск сертификатов
Для перезапуска после обновления, например, nginx, необходимо сделать следующее:
- открываем файл /root/.acme.sh/mysite.com/mysite.com.conf;
- ищем там строчку Le_RenewHook='' и меняем её (или добавляем новую):Le_RenewHook='/usr/local/etc/rc.d/nginx restart'
Для root в cron добавляем:34 1 * * * /usr/local/sbin/acme.sh --cron > /dev/null
34 - минута запуска, поменяйте на другое число от 0 до 59
1 - час запуска, поменяйте на другое число от 0 до 23
- nginx - пути к сертификатам для добавления в блок server
ssl_certificate /root/.acme.sh/mysite.com/fullchain.cer; ssl_certificate_key /root/.acme.sh/mysite.com/mysite.com.key;
- Посмотреть данные сертификата
# openssl x509 -in cert.pem -noout -text
- Ошибки (куда ж без них)
Create new order error. Le_OrderFinalize not found. {"type":"urn:ietf:params:acme:error:unauthorized","status":401,"detail":"A requested identifier is not permitted [site-motor.ru]"}
Для нового домена попросили сделать новую учетную запись, после чего при попытке получить сертификат выскочила ошибка. Лечим сменой сервера сертификации:# acme.sh --debug --log --set-default-ca --server letsencrypt
Статья опубликована: 2019-02-13 11:58:29
Последние правки: 2023-09-21 17:33:04
Let's Encrypt - центр сертификации от некоммерческой организации ISRG, существующий при поддержке EFF и многих компаний, взявшей на себя миссию дать людям бесплатные SSL/TLS сертификаты для сайтов и серверов. Хотя сам LE в качестве клиента рекомендует использовать certbot, могут возникнуть сложные случаи, где certbot, увы, бесполезен. В этом случае нам поможет acme.sh.
Связанные странички:
Asterisk 18. FreeBSD. Модем Huawei E1550.
Ubuntu 18.04 - установка mrtg
Ubuntu 24.04. Mosquitto, MQTT-брокер.
Asterisk 13. FreeBSD. Модем Huawei E1550.
Ubuntu 24.04. Установка и настройка snmp.
Ubuntu - создаем raid 1
Ubuntu 24.04, как изменить порт ssh
Asterisk 20. Ubuntu 24.04. Модем Huawei E1550.