Настройка Nginx для TLS и HTTP2 + HTTP3

Добавляем SSL-сертификаты и включаем новые версии HTTP


Ликбез по TLS и SSL

TLS и SSL — криптографические проколы, обеспечивающие шифрование при передаче данных по сети

Оба протокола предназначены для передачи трафика при использовании HTTPS, и являются промежуточным уровнем между:

Для работы протоколов TLS и SSL нужны SSL сертификаты, где каждый сертификат — это пара двух ключей:

Схемы взаимодействия для TLS

Обычно только сервер подтверждает свою подлинность, а клиент может быть любым:

Схема взаимодействия для TLS 1.3
Схема взаимодействия с сервером для TLS 1.3

Намного реже используется mTLS (mutual TLS), и в этом случае клиент тоже предоставляет серверу сертификат для подтверждения своей подлинности. Обычно mTLS используют для взаимного подтверждения двух бэкенд-сервисов:

Схема взаимодействия для TLS 1.3
Схема mTLS с сервером для TLS 1.3

Откуда берутся SS сертификаты

Откуда клиенту известны публичные ключи и почему он им доверяет?

  1. SSL сертификаты формируют цепочку сертификатов, где каждый следующий сертификат подписан предыдущим
  2. Корневые SSL сертификаты выдаются удостоверяющими центрами, число которых ограничено
    • в России есть один удостоверяющий центр — Минцифры РФ — и его публичный ключ поставляется в российских браузерах и может быть установлен отдельно, но отсутствует в поставках зарубежных браузеров и ОС
    • подробнее см. Поддержка работы сайтов с российскими сертификатами
  3. В каждой операционной системе поставляется набор корневых SSL сертификатов, и этот набор можно дополнить вручную

Самоподписанный сертификат для локального окружения

TLS является неотъемлемой частью протоколов HTTP2 и HTTP3, и для локального тестирования HTTP2 / HTTP3 можно использовать самоподписанный сертификат.

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

Создание сертификата в Linux

Используйте утилиту OpenSSL, например:

# Сертификат на localhost
openssl req -x509 -newkey rsa:4096 -keyout localhost.key -out localhost.crt \
  -sha256 -days 3650 -nodes -subj '/CN=localhost' \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

# Сертификат на atdd.lan и поддомены *.atdd.lan
openssl req -x509 -newkey rsa:4096 -keyout atdd-lan.key -out atdd-lan.crt \
  -sha256 -days 3650 -nodes -subj '/CN=atdd.lan' \
  -addext "subjectAltName=DNS:atdd.lan,DNS:*.atdd.lan,IP:127.0.0.1"

Если вы планируете использовать приватный домен, отличный от localhost, не забудьте добавить его в файл hosts:

  1. Откройте файл hosts в любом редакторе, например, в nano: sudo nano /etc/hosts
  2. Добавьте строку и сохраните: 127.0.0.1 atdd.lan

Создание сертификата в Windows

Можно использовать утилиту New-SelfSignedCertificate в PowerShell


# Создание сертификата на localhost с альтернативным именем 127.0.0.1
$params = @{
    Subject = 'localhost'
    TextExtension = @('DNS=localhost&IPAddress=127.0.0.1&IPAddress=::1')
}
New-SelfSignedCertificate @params

# Создание сертификата на atdd.lan
$params = @{
    DnsName = 'atdd.lan', 'www.atdd.lan'
    CertStoreLocation = 'Cert:\LocalMachine\My'
}
New-SelfSignedCertificate @params

Если вы планируете использовать приватный домен, отличный от localhost, не забудьте добавить его в файл hosts:

  1. Откройте файл hosts в любом текстовом редакторе с правами администратора, путь к файлу: C:\Windows\system32\drivers\etc\hosts
  2. Добавьте строку и сохраните: 127.0.0.1 atdd.lan

Добавление сертификата в доверенные

Yandex Browser

  1. Откройте в браузере ссылку browser://settings/certificates
  2. Переключитесь на вкладку "Центры сертификации"
  3. Импортируйте сгенерированный ранее файл *.crt, указав опцию "Доверять этому сертификату при идентификации сайтов"
Схема взаимодействия для TLS 1.3
Диалог опций импорта сертификата в Yandex Browser

Google Chrome

  1. Откройте в браузере ссылку chrome://settings/certificates
  2. Переключитесь на вкладку "Центры сертификации"
  3. Импортируйте сгенерированный ранее файл *.crt, указав опцию "Доверять этому сертификату при идентификации сайтов"
Схема взаимодействия для TLS 1.3
Диалог опций импорта сертификата в Google Chrome

Включение SSL в nginx

Копирование сертификата

Следует скопировать самоподписанный сертификат в какой-либо каталог, доступный nginx.

При использовании docker-compose можно положить их в каталог src/nginx/ssl проекта и смонтировать в каталог /etc/nginx/ssl в docker контейнере, как показано ниже:

version: '3'

services:
  atdd-ru-ingress:
    container_name: atdd-ru-ingress
    image: nginx:1.27.3
    volumes:
      - ./public:/app/public:ro
      - ./src/nginx/conf.d:/etc/nginx/conf.d:ro
      - ./src/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./src/nginx/ssl:/etc/nginx/ssl:ro
    ports:
      - "127.0.0.1:80:80"
      - "127.0.0.1:443:443"

Включение TLS и подключение SSL сертификата

В конфигурации nginx внесите два изменения:

Пример:

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

    ssl_certificate /etc/nginx/ssl/atdd-lan.crt;
    ssl_certificate_key /etc/nginx/ssl/atdd-lan.key;
}

Редирект на HTTPS

Для сайта с поддержкой TLS имеет смысл полностью отказаться от нешифрованного трафика.

Пример:

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

    server_name atdd.ru atdd.lan;

    location / {
        return 301 https://$host$request_uri;
    }
}

Настройка версий TLS

По умолчанию nginx включает только актуальные версии TLS — подробности см. в документации Configuring HTTPS servers.

Менять эти параметры следует осознанно — если вы не понимаете целей и последствий вносимых изменений, то надо оставить значения по умолчанию.

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

server {
    # ... другие параметры
    
    # Ниже значения по умолчанию по состоянию на февраль 2025
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
}

Включение HTTP2 и HTTP3

Включение HTTP2 и HTTP3 возможно только после настройки TLS, потому что TLS встроен в HTTP2 и HTTP3 как обязательный элемент. Другими словами, при использовании схемы http:// протоколы HTTP2 и HTTP3 просто не включатся.

Зачем это делать:

Пример настройки nginx:

server {
    # ... другие директивы

    http2 on;
    http3 on;
    quic_gso on;
    quic_retry on;
}

Проверить факт включения HTTP2 или HTTP3 можно в DevTools браузера — используемый для каждого HTTP запроса протокол отображается на вкладке "Сеть" / "Network"

Документация: