SSL-сертификат Let’s Encrypt на Nginx

Проект Let’sEncrypt вошёл в стадию публичной беты 3-го декабря 2015 года. Теперь его можно попробовать.

В чём суть проекта: он позволяет выпускать и продлевать SSL сертификаты бесплатно и автоматически.

На счёт «бесплатно» — здесь всё ясно. Можно бесплатно получить сертификат уровня Domain Validation.

А вот на счёт «автоматически» — чуть посложнее. Разберём процесс получения и установки сертификата.

UPD: Увеличена степень «автоматизма» получения сертификата, убраны однообразные ручные операции.

Испокон веков получение SSL-сертификата было, в некотором роде, геморроем, который заключался в выполнении следующих пунктов:

  • Создание CSR-запроса
  • Отправка CSR-запроса в форму сертифицирующего центра
  • Подтверждение владения доменом при помощи щелчка по ссылке, присланной на почту admin@yourhost.ru
  • Получение сертификатов
  • Подготовка сертификатов для использования в конкретном web-сервере, в частности, для Nginx, цепочку сертификатов нужно «слеплять» в один.
  • Через год — проделать всё заново.

Так вот, для того, чтобы вам не нужно было проходить через всё это, некоммерческая организация Let’s Encrypt разработала специальный протокол ACME а также клиент, работающий с ним. Также, эта организация создала свой доверенный центр сертификации, который признаётся корневыми центрами сертификации, и уже есть во всех последних версиях браузеров.

Таким образом, в идеальном случае, вам достаточно будет установить клиент, и выполнить специальную команду, которая запросит сертификат, сама пройдёт проверку владения вами доменом, после чего получит сертификат и положит его в соответствующее место. Но это в теории. На практике же, инструмент может потребовать некоторых усилий.

В частности, если вы используете веб-сервер Nginx, а также, если веб-сервер у вас уже настроен, и работает, а вам нужно получить для него сертификат.

Алгоритм действий для получения сертификата

Условия:

  • Сайт с поддоменами работает на Nginx
  • Сервер работает на Debian Jessie 8.0

Я буду создавать сертификат для своего домена mihanentalpo.me, а также для поддоменов www и redmine. Поддомен www и вам пригодится, а другие поддомены выбирайте по своему усмотрению.

Настройка веб-сервера для использования Let’s Encrypt

Сервер Let’s Encrypt, перед выдачей сертификата убеждается в том, что домен принадлежит именно вам, для этого он обращается по определённому адресу вашего домена, и ожидает получить оттуда определённые данные. Для того, чтобы было удобно проходить эту проверку, будем размещать файлы проверок в конкретной папке.

1. Создадим папку /var/www/letsencrypt, в ней папку для файлов-испытаний letsencrypt и дадим серверу права на них:

# mkdir /var/www/letsencrypt
# mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
# chown -hR www-data:www-data /var/www/letsencrypt

Можно использовать и другую папку, но всюду где она будет упомянута далее, вам нужно будет также её подменять на свою придуманную.

В эту папку (.well-known/acme-challenge) мы будем класть файлик с «испытанием» для подтверждения владения сервером.

2. Изменим конфигурацию nginx для домена и поддоменов.

В секции server, описывающей ваш домен (порт 80, протокол http), добавим следующий блок:

# Папка с челенджами для ACME 
location ~ /.well-known 
{ 
    location ~ /.well-known/acme-challenge/(.*) 
    {
        default_type "text/plain";
        root /var/www/letsencrypt;
    } 
} 

ВАЖНО! Если в вашем файле конфигурации сервера есть блок для запрета открытия файлов, начинающихся с точки, то нужно вставлять блок с .well-known ДО НЕГО,
иначе при попытке зайти в браузере по адресу myserver.com/.well-known/acme-challenge, вы будете получать 403 ошибку (так как запрещено открытие файлов, начинающихся с точки)
Блок этот может выглядеть вот так:

location ~ /\. 
{
    deny all;
    access_log off;
    log_not_found off;
}

Данную настройку нужно повторить для всех ваших поддоменов!

3. Создадим файл для тестирования доступа к папке с challenge’ами:

# echo "Hello world" > /var/www/letsencrypt/.well-known/acme-challenge/index.html 
# chown www-data:www-data /var/www/letsencrypt/.well-known/acme-challenge/index.html

4. Перезапускаем nginx, и проверяем, открывается ли что-нибудь из этой папки:

Для проверки открываем адреса (домен конечно нужно подставлять ваш):
http://mihanentalpo.me/.well-known/acme-challenge/index.html
http://www.mihanentalpo.me/.well-known/acme-challenge/index.html
http://redmine.mihanentalpo.me/.well-known/acme-challenge/index.html
Вы должны увидеть «Hello world» в каждом из случаев. Также, надо проверить все остальные ваши домены, если хоть один из них не будет отдавать «Hello world», надо разобраться в чём дело, так как дальше продолжать будет невозможно.

Установим и запустим клиент letsencrypt

1. Установка
Из мануала quick start следует, что установить клиент пока (июнь 2016 года) можно только из гитхаба. (Для некоторых дистрибутивов уже собраны пакеты, но в нашем родном Debian’е всё происходит не так быстро)

Итак:

# cd /opt
# git clone https://github.com/letsencrypt/letsencrypt 
# cd letsencrypt 
# ./letsencrypt-auto

При первом запуске, команда letsencrypt-auto установит все пакеты, необходимые ей для работы, поэтому запускать её нужно либо от root’а, либо от имени пользователя, у которого настроено sudo, так как, программа, не найдя root-доступа, пытается запустить sudo.

2. Запуск процедуры получения сертификата:

Следующая команда запустит ручной процесс получения сертификата, в котором будут прописаны все эти указанные домены.

./letsencrypt-auto certonly \
    --webroot -w /var/www/letsencrypt \
    -d mihanentalpo.me -d www.mihanentalpo.me \
    -d redmine.mihanentalpo.me --rsa-key-size 4096

Параметр certonly значает, что нужно только получить сертификат, и никуда автоматически вкорячивать его не надо.
Ключ —webroot означает, что файлы для проверки будут складываться в папку, указанную с ключём «-w»
Ключ -w, за которым следует путь /var/www/letsencrypt, определяет, куда нужно положить файл проверки вашего веб-сервера. А точнее, какой каталог является «корневой», в ней скрипт попытается перейти в подкаталог .well-known/acme-challenge, и положить там файлы challenge (испытаний) для проверки того, что вы владелец сервера.
Ключ -d определяет имя домена, который нужно включить в сертификат. Указать нужно все ваши поддомены. Указывать маску «*» нельзя, только конкретные названия доменов. Первый надо указывать корневой домен, и лишь потом — поддомены.
Ключ —rsa-key-size определяет, насколько сложный ключ нужно формировать (чем сложнее, тем надёжнее, 4096 хватит ещё на 30 лет развития компьютерной техники)

После запуска этой команды, в консоли откроется интерфейс, который начнёт с вами общение.

1. Клиент спросит вашу почту — нужно указать ту почту, к которой вы хотите привязать сертификаты. На неё будут приходить уведомления, когда сертификат будет близок к устареванию.

2. Нужно согласиться с пользовательским соглашением

Прохождение процедуры проверки

1. Согласиться с логированием IP-адреса

2. …. А и всё! Если конечно всё настроено правильно. Раньше здесь была инструкция на 5 пунктов о том, как подкладывать файлы challenge вручную в режиме —manual, но поскольку сейчас мы делаем через —webroot, то и процесс весь проходит сам.

3. Далее вы получите примерно такое сообщение об успехе:

 IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at 
/etc/letsencrypt/live/mihanentalpo.me/fullchain.pem. Your cert will expire on 2016-03-15. 
To obtain a new version of the certificate in the future, simply run Let's Encrypt again. 
- If you like Let's Encrypt, please consider supporting our work by: 
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: 
https://eff.org/donate-le 

Это значит что файлы сертификатов получены (и лежат они по адресу, в моём случае, /etc/letsencrypt/live/mihanentalpo.me/), и теперь остаётся только подключить их к серверу.

Подключение сертификатов к серверу

Самый простой конфигурационный файл nginx для подключения SSL-шифрования и использования выданных сертификатов (приложение на php-fpm):

# Этот блок сервера для редиректов на https 
server 
{ 
    # Слушаем 80-й порт и перекидываем на https 
    listen *:80; 
    # Перенаправлять будем сайты с www и без www. 
    server_name mydomain.ru www.mydomain.ru; 
    # Собственно правильный редирект, чтобы не было нарушения работы ссылок
    return 301 https://$server_name$request_uri;
} 

# Основной блок сервера 
server 
{ 
    #имя сервера 
    server_name mihanentalpo.me www.mihanentalpo.me; 
    #Используем HTTPS(SSL) 
    listen *:443 ssl; 
    ssl on; 
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
    ssl_certificate /etc/letsencrypt/live/mihanentalpo.me/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/mihanentalpo.me/privkey.pem; 
    # Если разбираетесь в обычной настройке сервера nginx, 
    # то дальше можете не смотреть, пойдёт именно она. 

    # логи 
    access_log /mnt/data/logs/nginx/mihanentalpo.me-access.log; 
    error_log /mnt/data/logs/nginx/mihanentalpo.me-error.log; 
    
    # Индекс index index.php index.htm index.html; 
    # Папка 
    root /var/www/mihanentalpo.me; 

    # Это настройка позволяющая открывать статический контент с помощью НЕ-GET запросов 
    error_page 405 = $uri; 

    # Папка с челенджами для ACME 
    # (оставим её здесь как было, так как потом понадобится перевыпускать сертификат)
    location ~ /.well-known 
    { 
        location ~ /.well-known/acme-challenge/(.*) 
        {
            default_type "text/plain";
            root /var/www/letsencrypt;
        } 
    } 

    # Закрываем доступ к файлам начинающимся с точки 
    location ~ /\. 
    { 
        deny all; 
        access_log off; 
        log_not_found off; 
    } 
    # Включаем gzip-сжатие по всему серверу 
    gzip on; 
    gzip_comp_level 4; 
    # Отключаем логи для favicon и robots.txt 
    location = /favicon.ico 
    { 
        log_not_found off; 
        access_log off; 
    } 
    location = /robots.txt 
    { 
        allow all; 
        log_not_found off; 
        access_log off; 
    } 
    #Основной location 
    location / 
    { 
        try_files $uri $uri/ /index.php?$args; 
    } 
    # Передаём обработку PHP-скриптов PHP-FPM 
    location ~ \.php$ 
    { 
        try_files $uri =404; 
        fastcgi_pass 127.0.0.1:9999; 
        fastcgi_index index.php; 
        include fastcgi_params; 
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 
        fastcgi_ignore_client_abort off; 
        fastcgi_param APPLICATION_ENV master; 
    } 
} 

Если где-то есть другой 443-сервер для редиректа на 80-й порт, то может быть ошибка:

no «ssl_certificate» is defined in server listening on SSL port while SSL handshaking, client: xxx.xxx.xxx.xxx, server: 0.0.0.0:443

Подключить ssl таким образом нужно во всех поддоменах. В моём случае, для www подключение не понадобилось, так как домен с www у меня задан как алиас для основного имени, а вот для redmine потребовалось внести коррективы в конфиг-файл

Всё! Теперь, как несложно убедиться, когда вы находитесь на моём сайте, слева от его адреса нарисован замочек, чего и вашим сайтам желаю.

Проверка сертификата

Проверить сертификат, и узнать о нём максимум информации, можно с помощью различных онлайн-сервисов, таких как https://www.ssllabs.com/ssltest/. Там нужно ввести адрес вашего сайта, и можно получить массу полезной информации, касаемо не только вашего SSL-сертификата, но и того, правильно ли сделаны настройки сервера.

Обновление сертификата

Для выпуска нового сертификата, если у вас истёк предыдущий (а это будет происходить раз в несколько месяцев), нужно запустить команду

# cd /opt/letsencrypt
# ./letsencrypt-auto renew

поскольку скрипт помнит о том, как и для каких доменов вы получали сертификаты в прошлый раз, он просто повторит процедуру.

Если у вас добавились поддомены, вы можете выполнить команду, аналогичную представленной выше, добавив туда новый домен.
При этом клиент letsencrypt спросит вас «Сертификат для этого домен уже есть. Обновить его?», на что нужно ответить «да».
После обновления сертификата нужно перезагрузить веб-сервер

/etc/init.d/nginx restart

Решение проблем после обновления

После обновления сертификата и перезапуска Nginx у вас может возникнуть одна из следующих проблем:
(увидеть вы их можете, открыв свойства сертификата в браузере)
1) Дата истечения сертификата не изменилась
2) Дата истечения сертификата стала старше чем была
3) Сертификат вообще не работает

У этих проблем, как правило, одна причина: неверно создались симлинки на файлы сертификатов в папке /etc/letsencrypt/live/mysite.com (разумеется, путь должен быть с вашим именем сайта).

1) Проверяем куда ведут ссылки:

# cd /etc/letsencrypt/mysite.com
# ls -l

и видим что-то вроде этого (в моём случае):

lrwxrwxrwx 1 root root 55 Nov 23 07:01 ./fullchain.pem -> /etc/letsencrypt/archive/mysite.come/fullchain1.pem
lrwxrwxrwx 1 root root 53 Nov 23 07:00 ./privkey.pem -> /etc/letsencrypt/archive/mysite.com/privkey1.pem

2) Проверяем дату создания файлов по ссылкам:

ls -l /etc/letsencrypt/archive/mysite.com

и видим там что-то такое:

-rw-r--r-- 1 root root 1797 Dec 16  2015 cert1.pem
-rw-r--r-- 1 root root 1923 Aug 30 09:41 cert2.pem
-rw-r--r-- 1 root root 1923 Nov 23 06:54 cert3.pem
-rw-r--r-- 1 root root 1675 Dec 16  2015 chain1.pem
-rw-r--r-- 1 root root 1647 Aug 30 09:41 chain2.pem
-rw-r--r-- 1 root root 1647 Nov 23 06:54 chain3.pem
-rw-r--r-- 1 root root 3472 Dec 16  2015 fullchain1.pem
-rw-r--r-- 1 root root 3570 Aug 30 09:41 fullchain2.pem
-rw-r--r-- 1 root root 3570 Nov 23 06:54 fullchain3.pem
-rw-r--r-- 1 root root 1704 Dec 16  2015 privkey1.pem
-rw-r--r-- 1 root root 1704 Aug 30 09:41 privkey2.pem
-rw-r--r-- 1 root root 1704 Nov 23 06:54 privkey3.pem

Отсюда видно, что симлинки стоят на древние сертификаты, устаревшие ещё в 2015 году. Новые же сертификаты лежат под именами cert3.pem, chain3.pem, fullchain3.pem.
Пересоздадим симлинки:

# rm /etc/letsencrypt/live/mysite.com/fullchain.pem
# rm /etc/letsencrypt/live/mysite.com/cert.pem
# ln -s /etc/letsencrypt/mysite.com/fullchain3.pem /etc/letsencrypt/live/mysite.com/fullchain.pem
# ln -s /etc/letsencrypt/mysite.com/cert3.pem /etc/letsencrypt/live/mysite.com/cert.pem

И ещё раз перезагрузим nginx:

#/etc/init.d/nginx restart

P.S. Обновил запись, после того, как прочитал статью где меня же тыкают носом в —manual https://sohabr.net/habr/post/279695/


Оставить комментарий