Настройка SSL-сертификата на Nginx, установка TLS и виртуальный хост для HTTPS

Настройка SSL-сертификата на Nginx

Как установить и настроить SSL-сертификат для серверов на nginx. Разбираем получение сертификата Let’s Encrypt® или работу со своим для настройки HTTPS-соединения.

Введение

В современном интернете безопасность — необходимость, а не опция. Без шифрования данные пользователей (логины, пароли, платежная информация) могут быть перехвачены в незащищенных сетях. Протокол TLS (ранее известный как SSL) решает эту проблему, переводя сайт на HTTPS и тем самым: 

  • шифрует данные, 
  • подтверждает подлинность сервера,
  • защищает от подмены информации. 

Помимо прочего, HTTPS повышает доверие пользователей и улучшает позиции сайта в поисковой выдаче.

В инструкции разберем, как настроить SSL/TLS в nginx. Для этого потребуются установленный nginx и два файла: сертификат и ключ для него. Если ключа нет — создадим с помощью Let’s Encrypt®.

В отдельном тексте рассказали, как работают HTTP и HTTPS и в чем их ключевая разница.

Установка SSL-сертификата

Загрузка файлов на сервер

Если у вас уже есть сертификат и ключ, в первую очередь скопируйте их на сервер. Для объяснений ниже используем директорию /var/www/ssl. 

1. Скопируем в каталог строку:


      rsync -Pvh {privkey.pem,cert.pem} root@SERVER-IP:/var/www/ssl

2. Проверим, что ключ обладает корректными правами доступа и доступен для чтения только root-пользователю:


      chown root:root /var/www/ssl/privkey.pem
chmod 400 /var/www/ssl/privkey.pem

Сертификат (cert.pem) можно оставить с обычными правами, так как он публичный и все равно передается браузеру на каждый запрос.

3. Проверьте синтаксис ключа и сертификата:


      openssl x509 -in cert.pem -text -noout
openssl rsa -in privkey.pem -check

А также проверьте соответствие ключа и сертификата:


      openssl x509 -in cert.pem -pubkey -noout -outform pem | openssl md5
openssl rsa -in privkey.pem-pubout -outform pem | openssl md5

Установка и настройка

Базовая настройка SSL в nginx — простой процесс. Достаточно в директиву server добавить директивы ssl_certificate и ssl_certificate_key, а listen 80 изменить на listen 443 ssl. Конфиг будет выглядеть примерно так:


      server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /var/www/ssl/cert.pem;
    ssl_certificate_key /var/www/ssl/privkey.pem;
    location / {
    ...
    }
}

После этого сайт уже будет использовать SSL/TLS, однако для повышения безопасности и производительности важно настроить дополнительные параметры SSL-сессий.

Настройка параметров SSL-сессий

Для выбора подходящих значений можно использовать ресурс Mozilla, где собраны лучшие практики и рекомендации по настройке SSL. Подойдет для большинства серверов, включая web и nginx в частности. 

Страница Mozilla.
Главная страница SSL Configuration Generator.

Для удобства приведем готовый вариант для TLS 1.3. Это самая современная версия на момент написания статьи, а также она поддерживает только безопасные шифры и не требует ручной настройки ssl_ciphers:


      server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /var/www/ssl/cert.pem;
    ssl_certificate_key /var/www/ssl/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;
    add_header Strict-Transport-Security max-age=15768000;
    location / {
        ...
    }
}

Для сайтов, ориентированных на мобильные устройства, рекомендуем ограничиться выбором TLS 1.2, так как некоторые мобильные провайдеры блокируют TLS 1.3.

Отключение небезопасных протоколов и настройка шифров

Если планируется использование TLS 1.2, то нужно настроить ssl_ciphers и ssl_ecdh_curve, поскольку версия протокола 1.2 допускает использование небезопасных шифров. С такой настройкой этого не произойдет:


         ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ecdh_curve X25519:prime256v1:secp384r1;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;

Не рекомендуем использовать версии (SSL SSLv2, SSLv3), а также TLS 1.0 и TLS 1.1 — они небезопасны и давно сняты с поддержки. 

TLS 1.2 активно внедрялся с 2008, а проблемы с его поддержкой могут возникнуть разве что в Internet Explorer Windows 2000. TLS 1.3 же допускает использование исключительно безопасных протоколов, а дополнительный тюнинг ему не нужен.

Приоритеты серверных шифров

Директива ssl_ciphers не только задает список допустимых шифров, но и определяет их приоритет: чем раньше указан шифр, тем выше его приоритет. Nginx выберет первый шифр из списка, который поддерживает клиент.

Но порядок можно изменить. Например, если nginx будет запущен на старом устройстве без поддержки аппаратного ускорения AES, то для повышения производительности лучше поместить вперед алгоритмы с шифром CHACHA20. Если вы переживаете за возможность атак с использованием квантовых суперкомпьютеров, размещаем AES256 перед AES128, а SHA384 — перед SHA256.

Усиление безопасности: параметры Диффи — Хеллмана

Для TLS 1.2 рекомендуется сгенерировать уникальные параметры Диффи — Хеллмана, чтобы повысить стойкость обмена ключами. Сделать это просто: генерируем их с помощью openssl и добавить в конфигурацию директиву ssl_dhparam. 

1. Генерируем: 


      openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

2. Добавляем директиву:


      ssl_dhparam /etc/ssl/certs/dhparam.pem;

3. Безопасный конфиг для TLS 1.2 готов и выглядит примерно так:


      server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /var/www/ssl/cert.pem;
    ssl_certificate_key /var/www/ssl/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;
    add_header Strict-Transport-Security max-age=15768000;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ecdh_curve X25519:prime256v1:secp384r1;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    location / {
        ...
    }
}

Получение сертификата SSL/TLS с  Let’s Encrypt®

Если у вас нет сертификата, его можно получить с помощью Let’s Encrypt®. Это центр сертификации, который предоставляет бесплатные SSL/TLS-сертификаты всем желающим.

Установка клиента для Let’s Encrypt® и получение сертификата

Один из самых простых способов работать с сертификатами Let’s Encrypt® — использовать утилиту CertBot c плагином certbot-nginx. Этот набор поможет автоматически выпустить сертификат, а также пропишет его в конфиг и настроит автоматическое обновление сертификата. Все, что нужно для работы с CertBot — установленный nginx и корректная А-запись домена. 

1. Устанавливаем CertBot:


      apt install certbot python3-certbot-nginx

2. Запускаем:


      certbot --nginx -d example.com -d www.example.com

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

4. Соглашаемся с условиями пользования, отказываемся делиться email с партнерами (опционально) и радуемся результату. В последнем сообщении CertBot выведет пути до сертификата (fullchain.pem) и ключа (privkey.pem). Рекомендуем в конфигурационном файле использовать именно эти пути и не производить лишних копирований — так CertBot сможет обновлять сертификаты автоматически.

Перенаправление с 80 на 443

Теперь можно завершить настройку, добавив редирект с 80 на 443 порт (или с HTTP на HTTPS). Для этого добавим еще одну директиву — server:


      server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

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

Проверка работы

В финале важно проверить, что настройка nginx выполнена корректно.

1. Проверяем синтаксис конфигурации:


      nginx -t

2.Чтобы увидеть финальный вариант конфига со всеми include, используйте следующую команду:


      nginx -T

3. Если все корректно, применяем изменения:


      systemctl reload nginx

4. Теперь, подставив нужный домен, проверяем, какой сертификат отдает nginx и какие шифры используются для соединения:


      openssl s_client --connect example.com:443

5. Проверяем, что сертификат доверенный:


      curl -IL https://example.com/