|
|||||||
Let's Encrypt и nginx: настройка в Debian и Ubuntu
Время создания: 13.07.2018 15:31
Автор: Алексей alexkbs
Текстовые метки: letsencrypt nginx certbot debian ubuntu apache2
Раздел: SSL
Запись: Velonski/mytetra-database/master/base/1517374959vp7wiab8qd/text.html на raw.githubusercontent.com
|
|||||||
|
|||||||
Если вдруг вся эта история прошла мимо вас, Let's Encrypt — центр сертификации от некоммерческой организации ISRG, существующий при поддержке EFF и многих компаний, взявшей на себя миссию дать людям бесплатные SSL/TLS сертификаты для сайтов и серверов. Сертификаты от Let's Encrypt уже используются на более чем 10 миллионах доменов . Кроме очевидной бесплатности у сертификатов от Let's Encrypt есть особое, отсутствующее у любых других коммерческих сертификационных центров, достоинство: если вы однажды получили сертификат от Let's Encrypt, то, при прочих равных, это навсегда. Не нужно раз в год-два вручную обновлять сертификаты. Не нужно вообще вспоминать что сертификаты где-то есть. Получил, настроил и забыл! Внимательный читатель сразу захочет возразить: как же так, ведь известно что сертификаты выдаются со сроком действия в три месяца? Всё дело в автоматическом обновлении сертификатов, которое возможно при полном отсутствии действий со стороны человека. Организации автоматического обновления сертификатов в статье уделено пристальное внимание, с тем чтобы вы могли в полной мере оценить это принципиальное преимущество Let's Encrypt. На сайте EFF есть краткие инструкции по использованию Certbot , рекомендуемой программы для получения сертификатов, но они скорей рассчитаны на тех, кто заходит на свой сервер по SSH лишь по острой необходимости. Более подробная документация тоже есть , но пока всю ее прочитаешь и найдешь всё то, что действительно нужно знать… К тому же, в ней не рассмотрены некоторые важные стратегические вопросы использования сертификатов. Очевидно, нужна короткая и понятная инструкция для тех, кто привычен к серверной консоли, но хочет во всём разобраться без излишних трат времени. Из этой статьи вы узнаете...
Всё знаете про SNI? Читайте сразу про установку. В инструкциях ниже я исхожу из того что ваши сайты будут использовать SNI. Это расширение протокола TLS позволяет браузерам сообщить желаемое имя сайта до получения и проверки SSL сертификата от сервера. Благодаря SNI вы можете разместить сколько угодно сайтов за HTTPS на одном IP. Но не всё так просто — иначе бы зачем я об этом писал? Есть ряд старых браузеров в принципе не поддерживающих SNI. В их число входят любые версии IE в уже заброшенном Windows XP , встроенный браузер в Android 2.3 и 2.2 из 2010 года , а также некоторые другие более экзотические браузеры и библиотеки типа Java версии 1.6 и Python до версии 2.7.9 . Если вы всё-таки хотите чтобы ваш сайт открывался в IE в Windows XP, то одним отказом от SNI эта проблема не решается. Нужно специальным образом подбирать шифры , уже отказываясь от forward secrecy и рискуя получить низкую оценку от SSL Labs . Как можно догадаться, этот вопрос заслуживает отдельного обсуждения хотя бы потому что пользователям IE под XP можно посочувствовать — у них уже не открывается половина интернета! Еще год назад от перехода на SNI вас могла бы удержать ограниченная поддержка этой технологии некоторыми поисковыми ботами типа Bing, но сейчас, с появлением десятков сайтов с бесплатными сертификатами от Cloudflare, что без SNI не открываются, бот Bing (что легко проверить ), и боты других основных поисковиков , пришли в согласие с реальностью. Сейчас за это можно не волноваться. Отмечу, что у Googlebot таких проблем не было никогда. Другим поводом для волнений могут быть различные средства доступа к API вашего сайта. Если у вас давно есть API, то есть небольшой шанс что среди ваших клиентов есть какие-то, использующие устаревшие версии Java или Python. Если у вас таких нет, то не о чем переживать. Если же есть — мои соболезнования. Почему лучше рассчитывать на SNI?
Например, так можно посмотреть домены в сертификате Тематических Медиа: true | openssl s_client -showcerts -connect habrahabr.ru:443 2>&1 |
openssl x509 -text | grep -o 'DNS:[^,]*' | cut -f2 -d:
На момент написания статьи эта команда выведет подробный список всевозможных доменов ТМ: habrastorage.org
api.geektimes.ru
api.habrahabr.ru
geektimes.ru
habrahabr.ru
id.tmtm.ru
lab.geektimes.ru
m.geektimes.ru
m.habrahabr.ru
special.geektimes.ru
special.habrahabr.ru
www.geektimes.ru
www.habrahabr.ru
Никакой секретности и никаких тайн. Вы этого хотите? Если вы читаете этот текст из будущего, когда Certbot уже есть в Debian stable и Ubuntu без обиняков и оговорок, то всё просто: apt-get install certbot
Либо используйте aptitude или другой пакетный менеджер вашего дистрибутива. Если у вас еще в ходу актуальный на конец 2016 года Debian stable "jessie", то всё лишь немного сложнее.
deb http://ftp.debian.org/debian/ jessie-backports main contrib non-free
apt-get update
apt-get install certbot -t jessie-backports
(Раздел актуален пока только stretch не стал stable.) Ubuntu версий ниже 16.10 (yakkety) sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install --upgrade letsencrypt
Дальше везде вместо certbot используйте letsencrypt. Если у вас какой-то другой дистрибутив, то дополнительные инструкции по установке есть на официальном сайте Certbot . Если обходиться без пакетного менеджера, то обычно установка сводится к... wget -O /usr/local/bin/certbot-auto https://dl.eff.org/certbot-auto
chmod +x /usr/local/bin/certbot-auto
ln -s /usr/local/bin/certbot-auto /usr/local/bin/certbot
Везде ниже вместо команды certbot можно использовать команду certbot-auto. Мы будем получать сертификаты по методу webroot без перенастройки или остановки веб-сервера, под которым подразумевается nginx. Нам нужен какой-то каталог, в который certbot будет писать свои файлы, и какой должен быть доступен из сети удостоверяющему серверу согласно протокола ACME . Чтобы не писать каждый раз длинную строку из опций, а еще лучше — не вспоминать о них, запишем основные настройки в файл конфигурации, который certbot ожидает найти в /etc/letsencrypt/cli.ini: authenticator = webroot
webroot-path = /var/www/html
post-hook = service nginx reload
text = True
Последняя директива нужна чтобы избавить нас от прелестей и красивостей ncurses, что нужно чтобы вы могли сравнить вывод команд здесь, в этой статье, и у себя. Также нам нужно мягко перезагрузить nginx (без перерыва в обслуживании) при успешном обновлении сертификатов. Ничего не мешает в этот же момент перезапускать и другие сервисы вроде Postfix, использующие полученные сертификаты. Команды указываются через точку с запятой. Если точка с запятой вызывает ошибку Ожидается что certbot будет создавать необходимые для проверки прав на домен файлы в подкаталогах ниже по иерархии к указанному. Вроде таких: /var/www/html/.well-known/acme-challenge/example.html
Эти файлы должны будут быть доступны из сети на целевом домене по крайней мере по HTTP: http://www.example.com/.well-known/acme-challenge/example.html
Для следующих проверок создадим какой-то такой файл: mkdir -p /var/www/html/.well-known/acme-challenge
echo Success > /var/www/html/.well-known/acme-challenge/example.html
Регистрацию нужно сделать только один раз: certbot register --email me@example.com
Здесь ничего сложного. Подготовим nginx к получению сертификатов В общем случае для получения сертификата необходимо во всех блоках server добавить следующий блок до других блоков location: location /.well-known {
root /var/www/html;
}
Понятно, что вписывать для каждого сайта такой блок явно — это моветон, потому создадим файл /etc/nginx/acme с содержанием блока выше. # cat /etc/nginx/acme
location /.well-known {
root /var/www/html;
}
Затем для каждого домена и поддомена, для которых нужно получить сертификаты, в блоке server перед всеми блоками location укажем: include acme;
Хосты-редиректоры (например, с голого домена на www) можно пропустить. ACME сервер обязан учитывать стандартную переадресацию. Подробней об этом ниже. Перезагрузим nginx и проверим что наш тестовый файл виден: # service nginx reload
# curl -L http://www.example.com/.well-known/acme-challenge/example.html
Success
После проверки лучше удалить тестовый файл — certbot любит удалять за собой всё лишнее, а такой файл будет мешать и вызывать сообщение об ошибке (Unable to clean up challenge directory). rm /var/www/html/.well-known/acme-challenge/example.html
Теперь у нас всё готово чтобы получить наш первый сертификат . О переадресации с кодами 301 и 302 Как было уже сказано, ACME сервер Boulder учитывает переадресацию с кодами 301 и 302 . В этом смысле не имеет значения где, в конечном счете, находятся файлы, требуемые для прохождения проверок. Переадресация возможна даже на нестандартные порты , без ограничений по конечному протоколу HTTP или HTTPS. Сами Let's Encrypt рекомендуют использовать переадресацию для создания единой точки проверки прав на домены . Если вы можете получить эти файлы с помощью curl с ограничением в десять переадресаций, то и Boulder эти файлы увидит. Не должно быть никаких ограничений по IP адресам . curl --location --max-redirs 10 http://example.com/.well-known/acme-challenge/example.html
Это удобно если у вас сложная структура переадресаций между разными версиями сайтов. Должно быть достаточно подключить тот блок с location только на основном сайте для получения сертификатов для всех остальных. $ curl --head --silent --location --max-redirs 10 http://somewhere.example.net/... | grep ^HTTP
HTTP/1.1 301 Moved Permanently
HTTP/1.1 301 Moved Permanently
HTTP/1.1 200 OK
Проверка всегда начинается с запроса по протоколу HTTP на 80 порту. Если у вас уже всё зашифровано... Если у вас уже все сайты работают по HTTPS, то вся схема будет работать если у вас настроен переадресующий сервер на 80 порту, сохраняющий $request_uri в ответе. Другое дело что можно сократить путь и подключить наш блок с location в умолчальном сервере для 80 порта, который делает переадресацию на HTTPS. Тогда не нужно будет ничего дописывать в конфиги отдельных сайтов. Пример конфигурации такого переадресующего всё-подряд-на-HTTPS сервера: server {
listen server.example.com:80 default_server;
include acme;
location / {
return 301 https://$host$request_uri;
}
}
Такой конфиг стоит определить в /etc/nginx/conf.d/default.conf, в стороне от конфигов конкретных сайтов. Сервер запускаем явно на внешнем IP чтобы не перенастраивать Apache на другой порт. Если для вас это не проблема, то указание имени сервера в директиве listen можно пропустить. Если нужно получить сертификат для домена без сайта... Типичный пример — сертификат для выделенных под SMTP или IMAP серверов, на которых вообще нет каких-то сайтов. Либо используйте универсальный переадресатор что выше, либо... server {
server_name smtp.example.com imap.example.com;
listen server.example.com:80;
include acme;
location / {
return 404;
}
}
К сожалению, протокол ACME требует чтобы такой сервер был доступен во время каждой проверки. Это практически эквивалентно постоянной доступности, ввиду требования получения и обновления сертификатов без перезагрузки сервера. Не удаляйте такой конфиг после получения сертификата. Если у вас Apache2, а перейти на всеми любимый nginx возможности нет, то… Добавьте следующие строчки в /etc/apache2/conf-available/certbot.conf: Alias /.well-known/ /var/www/html/.well-known/
<Directory /var/www/html/.well-known/>
Satisfy any
</Directory>
Затем a2enconf certbot
mkdir -p /var/www/html/.well-known
service apache2 reload
И обязательно проверьте, так: mkdir -p /var/www/html/.well-known/acme-challenge
echo Success > /var/www/html/.well-known/acme-challenge/example.html
curl -L http://localhost/.well-known/acme-challenge/example.html &&
rm /var/www/html/.well-known/acme-challenge/example.html
Существует много причин почему такая схема может у вас в Apache2 не заработать. Пары экранов текста не хватит чтобы описать их все. Не серчайте — статья про nginx. У Let's Encrypt есть лимиты на количество обращений за сертификатами , потому сначала попробуем получить необходимый сертификат в режиме для тестов: certbot certonly --dry-run -d example.com -d www.example.com
В конце программа должна отчитаться об успешной работе: The dry run was successful.
Теперь можно смело получать сертификат уже в самом деле. Не забудьте явно указать все необходимые поддомены, такие как www. # certbot certonly -d example.com -d www.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
http-01 challenge for www.example.com
Using the webroot path /var/www/html for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0001_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0001_csr-certbot.pem
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.com/fullchain.pem. Your cert will
expire on 2017-04-01. To obtain a new or tweaked version of this
certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run "certbot
renew"
Ура! С получением сертификата закончено! Если нужно добавить поддомен или домен в сертификат Если вы вдруг забыли указать поддомен www, или вам нужно добавить другой домен или поддомен в сертификат (которых может быть до 100 в одном сертификате ), то это легко сделать после получения сертификата. Просто запустите команду еще раз, добавив требуемое имя: certbot certonly -d example.com -d www.example.com -d shop.example.com
Вам будет безальтернативно предложено добавить этот домен в сертификат. Если хочется избежать вопросов, то можно сразу указать одобряющий такое поведение ключ: certbot certonly --expand -d example.com -d www.example.com -d shop.example.com
Операцию можно повторять. Проверим полученный сертификат Убедимся что полученный сертификат — именно тот, что нам нужен: # openssl x509 -text -in /etc/letsencrypt/live/example.com/cert.pem
Certificate:
Signature Algorithm: ...
Validity
Not Before: Jan 3 06:00:00 2017 GMT
Not After : Apr 3 06:00:00 2017 GMT
X509v3 extensions:
...
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com
Или, если подробности вам не нужны: cat /etc/letsencrypt/live/*/cert.pem | openssl x509 -text |
grep -o 'DNS:[^,]*' | cut -f2 -d:
Команда должна вывести список доменов в сертификате. Установка и использование сертификатов Certbot не перезаписывает сертификаты, а заменяет их ссылками на самые актуальные варианты сертификатов в определенном каталоге, одноименном с первым доменом сертификата (т.е. CN). Давайте посмотрим что за файлы у нас есть: # find /etc/letsencrypt/live/ -type l
/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/chain.pem
/etc/letsencrypt/live/example.com/privkey.pem
/etc/letsencrypt/live/example.com/cert.pem
С этим знанием мы можем задать настройки SSL для nginx: ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
Как видите, cert.pem нигде в конфиге не используется, и это не ошибка. Для nginx он не нужен. Полный рабочий пример конфига: server {
server_name www.example.com;
listen www.example.com:443 ssl; # default_server;
# выше можно добавить default_server для клиентов без SNI
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 8.8.8.8;
# исключим возврат на http-версию сайта
add_header Strict-Transport-Security "max-age=31536000";
# явно "сломаем" все картинки с http://
add_header Content-Security-Policy "img-src https: data:; upgrade-insecure-requests";
# далее всё что вы обычно указываете
#location / {
# proxy_pass ...;
#}
}
Конфиг для переадресации с голого домена без www: server {
server_name example.com;
listen example.com:443 ssl;
access_log off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 8.8.8.8;
add_header Strict-Transport-Security "max-age=31536000";
expires max;
return 301 https://www.example.com$request_uri;
}
Подразумевается что вы используете какой-то локальный сервер для кеширования DNS запросов. Если это не так, то 127.0.0.1 в директиве resolver нужно заменить на IP используемого DNS сервера. Настройки шифров и прочее подобное (ssl_dhparam, ssl_session_cache) лучше держать вне конфигов отдельных серверов. Если вы переживаете что Certbot может утащить ключи от вашего сертификата не смотря на открытые исходные коды , а значит, в теории, какие-то злодеи смогут расшифровать весь трафик, то спешу вас успокоить. Если для соединения с вашим сайтом используются шифры из семейств DHE и ECDHE , то утечка ключа не позволит расшифровать трафик. В этих шифрах ключ сертификата используется только для подтверждения подлинности, и не используется в качестве ключа для шифрования. Все современные браузеры поддерживают эти шифры. Если для ECDHE на эллиптических кривых ничего не нужно делать, то для DHE можно было бы использовать усиленные параметры. Лучше всего будет отключить DHE вообще. Если по какой-то причине без DHE вы не можете обойтись Сертификаты выдаются на три месяца. Не на полгода, не на год, а лишь на три месяца. Естественно это вызывает вопросы. Нужно ли проходить всю эту процедуру через три месяца? Нужно ли это делать всегда до искончания веков? Может стоит всё-таки вложиться в платный сертификат чтобы забыть об этом всем и не воспоминать пару лет? Но нет, не спешите искать платежные средства! Как и было обещано в начале статьи, с обновлением сертификатов проблем нет. Если у вас Debian, то нужно лишь дописать к вызову certbot в /etc/cron.d/certbot ключ --allow-subset-of-names: # последняя строка в /etc/cron.d/certbot
# было certbot -q renew, а надо
certbot -q renew --allow-subset-of-names
Если у вас Debian и systemd, то посмотрите эти инструкции . Если у вас не Debian или нет файла, то добавим в crontab от root одну лишь строчку (sudo crontab -e): 42 */12 * * * certbot renew --quiet --allow-subset-of-names
Согласно рекомендаций Let's Encrypt следует пытаться обновить сертификаты два раза в день. Делать это нужно в случайным образом выбранную минуту того часа, а значит вам нужно заменить 42 в этой строке на другое число в диапазоне между 0 и 59. Либо вы можете поступить так как это делается в /etc/cron.d/certbot. В этой команде ключ --allow-subset-of-names нужен чтобы Certbot пытался получить сертификаты для частичного набора доменов. Например, были у вас на сервере были сайты www.example.com и shop.example.com, проходящие под одним сертификатом, но потом вы перенесли shop.example.com на другой сервер. Если такой ключ не указать, то Certbot упадет с ошибкой при попытке подтвердить владение shop.example.com, не получив для вас вообще никакого сертификата. Сертификат истечет и ваш сайт уйдет в оффлайн. С этим ключом вы всё же получите сертификаты хотя бы для частичного набора доменов, оставив ваши сайты в сети. Если вам близки по духу tee и sed, то есть гораздо более короткая инструкция по настройке связки Let's Encrypt и nginx , при условии корректно настроенного hostname. Только копируй команды и вставляй. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|