В этом руководстве я бы хотел показать, как сгенерировать LetsEncrypt SSL сертификат для тестового сайта с минимальными трудозатратами. Я буду использовать Nginx в режиме reverse proxy в качестве web сервера.


Этот текст рассчитан для новичков в настройке Nginx и описанный способ настройки не подойдет для использования в production. Я решил написать это руководство потому что мне понадобилось быстро развернуть сайт с SSL, но я не нашел простого способа сделать это. В сети доступны Docker образы, которые позволяют добавить в инфраструктуру слой, отвечающий за обновление сертификатов, но эти решения требуют настройки.


Мы же будем использовать manual режим бота LetsEncrypt или сторонний сервис, который выполнит команду (в случае, если вы не дружите с консолью). Использование стороннего сервиса потенциально небезопасно, так как сервис может сохранить ваш приватный ключ у себя.


Получение ключа


В качестве отправной точки предположим у нас имеется сервис myserv.com на который Nginx перенаправляет HTTP запросы.


Конфигурация myserv.com:
upstream myserv{
    server myserv:80;
}

server {
    listen 80;
    listen[::]:80;

    index index.html index.htm index.nginx-debian.html;
    server_name myserv.com;

    location / {
        proxy_pass              http://myserv;
        proxy_http_version      1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection keep-alive;
        proxy_set_header        Host $host;
        proxy_cache_bypass      $http_upgrade;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;
        client_max_body_size    64m;
        proxy_connect_timeout   90;
        proxy_send_timeout      90;
        proxy_read_timeout      90;
    }
}

Для того чтобы ответить на запрос LetsEncrypt и подтвердить владение доменом мы должны отдать файл в поддиректории /.well-known. Для этого добавим следующий код в конфигурацию сервиса:


Конфигурация myserv.com с поддиректорий .well-known:
upstream myserv{
    server myserv:80;
}

server {
    listen 80;
    listen[::]:80;

    index index.html index.htm index.nginx-debian.html;
    server_name myserv.com;

    location /.well-known {
        root /var/www/ssl-proof/myserv/;
    }

    location / {
        proxy_pass              http://myserv;
        proxy_http_version      1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection keep-alive;
        proxy_set_header        Host $host;
        proxy_cache_bypass      $http_upgrade;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;
        client_max_body_size    64m;
        proxy_connect_timeout   90;
        proxy_send_timeout      90;
        proxy_read_timeout      90;
    }
}

Мы можем получить файлы валидации при помощи команды


sudo certbot certonly --manual --preferred-challenges http -d myserv.com

или инициализации процесса проверки домена на стороннем сервисе (например, SSL For Free или Zero SSL). Далее необходимо скопировать эти файлы в директорию /var/www/ssl-proof/myserv/.well-known. Если вы используете Docker, то вам придется или подключить эту директорию к контейнеру или пересобрать образ.


Теперь вы можете валидировать домен и получите файл сертификата, приватный ключ (если не указывали свой) и файл цепочки подписей (trust chain).


Настройка SSL


Для работы Nginx достаточно сертификата и приватного ключа. Большинство браузеров сами проверяют промежуточные сертификаты. Если же вы хотите обращаться к своему сервису с помощью веб клиента, то вам придется создать файл сертификата, который включает в себя информацию о промежуточных CA.


Вам нужно склеить файл сертификата с файлом промежуточных сертификатов:


cat myserv.crt bundle.myserv.crt >> chained.myserv.crt

Порядок важен, так как ключ будет применяться к первому сертификату. Если в конце первого сертификата отсутствует перевод строки — добавьте его.


Теперь мы можем обновить конфигурацию нашего сервиса:


Конфигурация myserv.com с поддержкой SSL:
upstream myserv{
    server myserv:80;
}

server {
    listen 80;
    listen [::]:80;

    server_name myserv.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443;

    index index.html index.htm index.nginx-debian.html;
    server_name myserv.com;

    ssl_certificate     /etc/letsencrypt/live/myserv/chained.myserv.crt;
    ssl_certificate_key /etc/letsencrypt/live/myserv/myserv.key;

    location /.well-known {
        root /var/www/ssl-proof/myserv/;
    }

    location / {
        proxy_pass              http://myserv;
        proxy_http_version      1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection keep-alive;
        proxy_set_header        Host $host;
        proxy_cache_bypass      $http_upgrade;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;
        client_max_body_size    64m;
        proxy_connect_timeout   90;
        proxy_send_timeout      90;
        proxy_read_timeout      90;
    }
}

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


Если ваши сервисы не используют директорию /.well-known, то можно не останавливаться на достигнутом и настроить автоматическое продление сертификатов. В моем случае /.well-known использовалась IdentityServer4 и мне пришлось отключить отдачу файлов валидации домена.


Я надеюсь, что эта статья поможет вам попробовать LetsEncrypt и начать использовать их сертификаты вместо self-signed сертификатов.


P. S.: судя по комментариям к посту мне следует еще раз объяснить назначение этого текста. Часто когда я спрашиваю людей, почему они не используют SSL, они говорят о сложностях настройки. Это минимальная инструкция не претендующая на полноту.

Комментарии (11)


  1. alexkuzko
    26.10.2017 18:48
    +2

    certbot очень тяжёлый… Я бы посоветовал посмотреть в сторону dehydrated, как примера очень легковесного acme клиента. Также стоит отметить что если у вас будет более одного сервера, стоит создать единый виртуальный хост для выдачи сертификатов, на который вы и будете делать редиректы с необходимых доменов.


    1. kvaps
      27.10.2017 02:54

      А мне acme.sh нравится.
      Лёгкий, простой и интуитивно понятный (по сути shell скрипт обычный), но все что нужно он умеет.


    1. questor
      27.10.2017 16:01

      Можно подробнее про единый виртуальный хост?


      1. alexkuzko
        27.10.2017 16:39

        Смотрите. Когда у вас 2 и более серверов ЛИБО прокси-сервера (CDN-подобные) либо DNS Round Robin фронты, то вам требуется один и тот же сертификат установить на всех звеньях. А т.к. вы не знаете на какой из них дойдет реальный запрос верификации (говорим про Domain Validation через http(s) к .well-known, а не через DNS), то на офф.сайте рекомендуют использовать 301 редиректы на некую единую точку, которую вы авторизуете ответить с подтверждением.

        Пример на пальцах: domain1 + domain2, на каждом из них для локации (location) .well-known делаем Rewrite/Redirect на acme.domain3, тем самым мы можем валидировать домены domain1 и domain2 на сервере acme.domain3.

        Далее, когда у нас уже есть редирект, мы можем всю процедуру выдачи, сохранения и заливки сертификатов перевести на единый хост (он тоже может быть кластеризирован, но сейчас не об этом). Хотите, можете использовать certbot, хотите dehydrated, хотите acme.sh, хотите — поиграйтесь с Docker и dockerletsencryptmanager + (опционально) le-git-sync.

        Это крайне удобно. Представьте, вам надо выдать сертификат на почтовик, а на него ставить ничего нельзя? Никаких клиентов, ничего. Тогда в зависимости от наших возможностей проброса 80-го порта для хостнейма этого почтовика, мы можем сделать редирект на наш acme.domain3 и все делать на нем, включая заливку сертификата на почтовик и его перезапуска. Аналогично и для всех прокси-серверов. Теперь мы можем обновленные сертификаты деплоить на все наши сервера (например, через Ansible, или просто через rsync/scp+ssh).


  1. spxnezzar
    27.10.2017 12:31

    Я немного не понял. А чем это от стандартного мануала letsencrypt отличается? А где запись в кроне на обновление сертификатов или вы ручками каждые три месяца ходить по серверам планируете?


  1. grossws
    27.10.2017 19:38

    Здесь уже были довольно бездарные статью по использованию le, но вы старались пробить дно, судя по всему. Про отсутствие автоматического перевыпуска сертификатов вам уже написали. Ещё стоит сказать, что настройка tls/ssl в nginx'е выполнена абсолютно бездарно. Рекомендую проверить настроенный таким образом сервер с помощью Qualys SSL Server Test, а потом ознакомиться с guide'ом от Mozilla.


    1. Michael_SL Автор
      27.10.2017 21:17

      Отсутствие перевыпуска сертификата связано с тем, что приложение отдаёт другие данные по /.well-known. Если вы можете предложить простой способ настройки маршрутизации запросов, я с удовольствием добавлю его в пост.
      Вот проверка сайта настроенного таким образом: image


      1. grossws
        27.10.2017 21:21

        location /.well-known/acme-challenge { ... }, остальное в /.well-known форвардите вторым location'ом. Естественно, имеет смысл настраивать и для http, и для https, чтобы обеспечить и бутстрап, и штатное обновление.


        Если вы хотите вставить картинку, то рекомендуется её положить в спойлер и воспользоваться habrastorage.org.


  1. maxwell
    27.10.2017 21:12
    +1

    image


  1. rt3879439
    27.10.2017 21:12
    -1

    Сначала возмущаешься зачем же люди пишут простенькие howto на хабре, коих и так у же по данной теме предостаточно даже на хабре, а потом смотришь полезные комментарии и успокаиваешься.


    1. grossws
      27.10.2017 21:23

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