Подключаем HTTPS к Nginx за счёт Let’s Encrypt

Development21 mar 2016

Небольшая заметка про подключение letsencrypt на сайт с nginx сервером. За основу взял хабра-статью от @questor-а. Наша задача добавить поддержку https на сайт малой кровью. letsencrypt позволяет нам это сделать, взяв на себя всю чёрную работу по подготовке, выдаче, загрузке и обновлению сертификатов (подробнее). Всё нижеописанное я привожу для linux debian-like систем.

Принцип работы

Для подключения HTTPS необходимы сертификаты (для шифрования и аутентификации). Причём эти сертификаты должны быть выданными доверенными серверами, список которых вшит в браузеры. Обычно это дело было платным, но с недавних пор, появилось несколько доступных и бесплатных альтернатив. Одна из которых это Let’s Encrypt.

Let’s Encrypt выпускает сертификаты бесплатно и в автоматическом режиме на 3 месяца. Для работы с ним подготовлено ПО с открытым кодом и есть открытое API для взаимодействия вручную. Мы воспользуемся готовым рекомендованным ПО.

Принцип работы этого ПО заключается в том, что сервер запрашивает у letsencrypt-центра выпуск новых сертификатов для указанных доменным имён. Для этого letsencrypt-центр ломится на ваш сервер по конкретным URL-ам с этими доменными именами, и убеждается в том, что они принадлежат вам. Затем выпускает новые сертификаты и передаёт их на сервер сайта. ПО складирует их в указанной директории. Вам остаётся лишь подключить их к nginx и настроить автоматическое обновление по cron-у.

Подготовка

Создаём nginx-шаблон:

touch /etc/nginx/templates/letsencrypt.conf

Добавляем его в раздел server нашего nginx-конфига:

server {
  include template/letsencrypt.conf;
  listen 443 ssl;
  # ...
}

Заодно подключаем TLS по 443 порту. Записываем в letsencrypt.conf:

location ~ ^/(.well-known/acme-challenge/.*)$ {
  proxy_pass http://127.0.0.1:9999/$1;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $http_host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

По сути этот location пробрасывает обработку .well-known… запросов на 127.0.0.1:9999, где на краткое время letsencrypt-auto будет держать свой web-server и учинять всю шаманскую магию по проверке вашего домена и не только. Обратите внимание на то, что letsencrypt будет ломиться на ваш домен именно по http протоколу (по понятным причинам), так что без listen 80 (http) не обойтись.

Перегружаем nginx:

service nginx reload

К генерации сертификатов готовы.

Подключение

Загружаем letsencrypt с github-а:

git clone https://github.com/letsencrypt/letsencrypt & cd letsencrypt

Запускаем:

./letsencrypt-auto \
  --agree-tos \
  --renew-by-default \
  --standalone \
  --standalone-supported-challenges http-01 \
  --http-01-port 9999 \
  --server https://acme-v01.api.letsencrypt.org/directory certonly \
  -d {domain1} -d {domain2}

Где для каждого домена нужно указать -d my-domain.ru. Минут пять скрипт качал зависимости. Если всё прошло гладко, то letsenscrypt-auto сообщает:

 Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/{domain}/fullchain.pem. Your cert will expire on 2016-06-19.

Т.е. сертификаты готовы. Смотрим в эту /etc/letsencrypt/live/{domain}/ и видим файлы: cert.pem, chain.pem, fullchain.pem, privkey.pem. Нас интересуют: privkey.com и fullchain.pem. В настройках nginx в разделе server прописываем (не забудьте заменить {domain} на ваш путь):

ssl                 on;
ssl_certificate     /etc/letsencrypt/live/{domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{domain}/privkey.pem;

Перезагружаем nginx. Проверяем в браузере. Получаем заветное . CN: Let’s Encrypt Authority X1.

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

Т.к. сертификат выдаётся всего на 3 месяца, его необходимо обновлять. Для этого можно вызвать ./letsencrypt-auto renew. Проверяем.

$:/root/letsencrypt/letsencrypt-auto renew
Checking for new version...
Requesting root privileges to run letsencrypt...
   /root/.local/share/letsencrypt/bin/letsencrypt renew
Processing /etc/letsencrypt/renewal/{doman}.conf

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/{domain}/fullchain.pem (skipped)
No renewals were attempted.

Если всё прошло без ошибок, то добавляем команду в cron (crontab -e). К примеру вот так:

0 4 * * * /root/letsencrypt/letsencrypt-auto renew > /dev/null 2>&1

Эту часть статьи я пока на собственном опыте не проверял. Через 3 месяца будет виднее.

Ссылки