Тема сборки Nginx для поддержки ALPN избита и изъезжена уже неоднократно, казалось бы что тут нового можно рассказать ?
Как правило во всех статьях для включения ALPN на Nginx предлагают сразу же его пересобрать с нужной версией OpenSSL, но возможно есть другой путь ?
Давайте разберемся как же лучше поступить, обновить ОС, пересобрать Nginx из исходников, найти готовый пакет или использовать Docker ?
(Статья актуализирована 23.10.2018)
Я не буду повторяться и рассказывать что такое HTTP/2, про это есть неплохая статья на Habrahabr от Selectel.
Что нужно знать ?
А то, что в мае 2016 года Google выпустил Chrome 51, исключив поддержку SPDY и NPN в пользу HTTP/2 и ALPN. Отключение поддержки NPN в Google Chrome привело к тому, что сайты которые не поддерживают ALPN стали открываться по HTTP/1 вместо HTTP/2. На тот момент можно было перейти на другой браузер, где поддержка NPN сохранилась и все было бы хорошо. Однако к середине 2017 года все самые популярные поставщики браузеров, кроме Safari (версия 10), отказались от поддержки NPN, начиная со следующих версий:
Теперь все зависит от администраторов Web-серверов, это они должны обновить ПО Web-серверов до той версий, которые поддерживают ALPN и HTTP/2. Nginx поддерживают протокол HTTP/2 с сентября 2015 года (начиная с версий Nginx 1.9.5 и Nginx Plus R7).
Более значительная проблема заключается в том, что операционная система, на которой работает Web-сервер, должна содержать версию OpenSSL, которая поддерживает ALPN. Для OpenSSL это версия 1.0.2 или новее.
Nginx собирается со статической версией OpenSSL и это дает ему независимость от версии OpenSSL в операционной системе.
В таблице ниже приводиться информация о версиях OpenSSL в разных дистрибутивах ОС Linux, а так же поддержка этими версиями ALPN и NPN по состоянию на сентябрь 2017 года.
Операционная система | Версия OpenSSL | Поддержка ALPN/NPN |
---|---|---|
CentOS/Oracle Linux/RHEL 6.5+, 7.0–7.3 | 1.0.1e | NPN |
CentOS/Oracle Linux/RHEL 7.4+ | 1.0.2k | ALPN и NPN |
Debian 7.0 | 1.0.1e | NPN |
Debian 8.9 | 1.0.1t | NPN |
Debian 9.2 | 1.1.0f | ALPN и NPN |
Ubuntu 12.04 LTS | 1.0.1 | NPN |
Ubuntu 14.04 LTS | 1.0.1f | NPN |
Ubuntu 16.04 LTS | 1.0.2g | ALPN и NPN |
Что Вы можете сделать ?
Вы можете проверить, какая версия OpenSSL используется в Вашем Nginx, запустив nginx -V:
# nginx -V nginx version: nginx/1.13.7 built by gcc 4.9.2 (Debian 4.9.2-10) built with OpenSSL 1.0.1t 3 May 2016 TLS SNI support enabled
У Вас есть три варианта, если вы хотите, чтобы посетители вашего сайта обращались к сайту через HTTP/2:
1. Обновите свою операционную систему.
Как показано в таблице выше, некоторые дистрибутивы ОС поставляются с OpenSSL, которые поддерживают ALPN. Другие поставщики, скорее всего, будут поддерживать ALPN в своих будущих выпусках с долгосрочной поддержкой.
2. Перекомпилируйте Nginx из исходников и используйте для сборки OpenSSL 1.0.2 или новее.
Nginx поддерживает OpenSSL 1.0.2 и более поздние версии, поэтому Вы можете перекомпилировать Nginx с опцией —with-openssl.
Однако разработчики Nginx не рекомендуют такой подход, т.к. в этом случае Вы берете на себя бремя мониторинга OpenSSL на предмет возможных уязвимостей в нем и такую сборку Nginx придется перекомпилировать каждый раз, когда выдается важное обновление для OpenSSL. Вы можете установить Nginx из репозитария Вашей ОС или из официального репозитария Nginx, но тут кроется несколько подводных камней, к примеру для Debian 8 (Jessie) в официальный Nginx собирается до сих пор с OpenSSL 1.0.1t, что не позволяет использовать ALPN. Для Debian 9 (Stretch) ситуация получше, там Nginx собирается с OpenSSL 1.1.0f, что позволяет нам использовать ALPN.
3. Запускайте Nginx в контейнере Docker.
В некоторых случаях Вы можете поместить свой Nginx или Nginx Plus в контейнер Docker, основанный на ОС, которая содержит OpenSSL 1.0.2 или новее. Это не потребует полного обновления ОС и является разумным ходом, только если Вы уже используете Docker в своем окружении. Если же Docker у Вас не используется, то такой вариант будет слишком сложным и повлечет дополнительных затрат времени на поддержание инфраструктуры Docker-контейнеров.
Какой вариант следует выбрать и в каких случаях ?
1. Вариант с обновлением ОС.
К сожалению обновление ОС не всегда возможно по ряду причин, к примеру с Debian 8 до Debian 9 целесообразно проводить обновление если у Вас Nginx используется в качестве балансировщика нагрузки или прокси. Если на Debian 8 у Вас используется PHP-FPM 5.6, то Вы сталкиваетесь с проблемой того, что в официальных репозитариях Debian 9 уже нет PHP-FPM 5.6, а есть только PHP-FPM 7.0 и Вам придется использовать сторонние репозитарии для установки PHP-FPM 5.6 на Debian 9.
Если же приград для обновления ОС на новую нет, то я рекомендую выполнить переход на новую версию ОС.
2. Вариант с перекомпиляции Nginx из исходников с нужными опциями.
Наверно самый популярный, т.к. это сделать довольно быстро и в случае с Nginx достаточно безболезненно.
Но и тут есть подводные камни в виде пересборки Nginx каждый раз при выходе новой версии Nginx или новой версии OpenSSL.
Решение 1: Использование репозитария Debian Backports для установки Nginx с поддержкой ALPN.
К счастью для Debian 8 (Jessie) есть решение проще, в Debian Backports есть nginx 1.10.3 с нужной версией OpenSSL и поддержкой ALPN, давайте заменим Nginx без ALPN из официального репозитария Nginx Inc. на Nginx из Deban Backports.
Исходные данные: Debian 8.9 Jessie (amd64) + nginx 1.10.3 (official Nginx Inc. repo)
Найдем в каком файле конфигурации репозитариев у нас прописан официальный репозитарий Nginx Inc.:
# find /etc/apt/ -type f -exec grep "nginx.org" {} ';' -print deb http://nginx.org/packages/debian/ jessie nginx deb-src http://nginx.org/packages/debian/ jessie nginx /etc/apt/sources.list.d/nginx.list
Удалим файл /etc/apt/sources.list.d/nginx.list
rm -f /etc/apt/sources.list.d/nginx.list
Добавим репозитарий jessie-backports:
echo "deb http://deb.debian.org/debian jessie-backports main contrib non-free" >/etc/apt/sources.list.d/backports.list echo "deb http://deb.debian.org/debian jessie-backports-sloppy main contrib non-free" >>/etc/apt/sources.list.d/backports.list
Обновим список пакетов:
apt-get update
Сделаем резервную копию каталога /etc/nginx
cp -r /etc/nginx/ ~
Удалим Nginx который был установлен из официального репозитария Nginx Inc., а так же ВНИМАНИЕ! удалим все файлы настроек из /etc/nginx:
apt-get remove nginx-* --purge
Установим Nginx:
apt-get -t jessie-backports install nginx-full
Посмотрим версию Nginx:
# nginx -V nginx version: nginx/1.10.3 built with OpenSSL 1.0.2l 25 May 2017 TLS SNI support enabled
Отлично, Nginx собран с OpenSSL 1.0.2l, а это значит, что ALPN будет работать.
Теперь скопируем наши сохраненные файлы конфигурации Nginx, в моем случае потребуется восстановить файлы:
cp ~/nginx/nginx.conf /etc/nginx/ cp ~/nginx/conf.d/default.conf /etc/nginx/conf.d/ cp ~/nginx/conf.d/fallback.conf /etc/nginx/conf.d/ cp ~/nginx/sites-available/mysite.ru.vhost /etc/nginx/sites-available/
И создать симлинк:
ln -s /etc/nginx/sites-available/mysite.ru.vhost /etc/nginx/sites-enabled/100-mysite.ru.vhost
Проверим конфигурацию Nginx:
# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Все отлично, теперь перезагрузим конфигурацию:
nginx -s reload
Теперь мы можем воспользоваться сервисом тестирования SSL от SSLLabs или от от High-Tech Bridge и убедиться, что ALPN у нас работает.
Дополнительно мы можем открыть инструменты разработчика в Google Chrome (горячая клавиша F12), на вкладке Network включить отображение столбца Protocol и открыть наш сайт и убедиться, что загрузка происходит по протоколу HTTP/2 (H2).
К сожалению у решения с репозитарием Debian Backports есть пара недостатков:
1. Nginx версии 1.10.3, то есть считается устаревшим, смотрим официальный сайт.
2. Отсутствует модуль nginx-njs (NginScript), если он Вам будет нужен, то увы, в Debian Backports его нет.
Поэтому для меня Решение 1 увы не подходит и мы переходим к Решению 2.
Решение 2: Пересборка Nginx из исходников.
Исходные данные: Debian 8.9 Jessie (amd64) + nginx 1.15.5 без ALPN (official Nginx Inc. repo)
В предыдущей статье: Базовая установка и настройка Nginx на Debian 8 мы установили Nginx из официального репозитария Nginx Inc., но как я писал выше, для Debian 8 он собран с OpenSSL 1.0.1t, а значит без поддержки ALPN.
Процедура пересборки Nginx довольно простая:
1. Проверка наличия добавленного на наш сервер репозитария Nginx Inc.
Проверяем наличие файла /etc/apt/sources.list.d/nginx.list со следующими записями:
deb http://nginx.org/packages/mainline/debian/ jessie nginx deb-src http://nginx.org/packages/mainline/debian/ jessie nginx
Если файла нет, то проверьте наличие этик строк в файле /etc/apt/sources.list
Если упоминания репозитария нет, то добавим его:
wget --quiet -O - http://nginx.org/keys/nginx_signing.key | apt-key add - echo "deb http://nginx.org/packages/mainline/debian/ $(lsb_release -sc) nginx">/etc/apt/sources.list.d/nginx.list echo "deb-src http://nginx.org/packages/mainline/debian/ $(lsb_release -sc) nginx">>/etc/apt/sources.list.d/nginx.list apt-get update
2. Создание временного каталога для сборки, скачивание нужной версии OpenSSL:
mkdir -p /usr/src/nginx cd /usr/src/nginx wget https://www.openssl.org/source/openssl-1.0.2p.tar.gz tar zxf openssl-1.0.2p.tar.gz
3. Подготовим системные зависимости для сборки и скачаем исходники Nginx из официального репозитария Nginx Inc.:
apt-get build-dep nginx apt-get source nginx
4. Изменение параметров сборки DEB-пакета (файл rules):
vi /usr/src/nginx/nginx-1.15.5/debian/rules
Находим строку начинающуюся с
CFLAGS=""
и после опции
--with-stream_ssl_preread_module
добавляем:
--with-pcre-jit --with-openssl=/usr/src/nginx/openssl-1.0.2p --with-openssl-opt="threads -fPIC"
Что это значит?
а) Опция —with-pcre-jit — мы будем собирать Nginx cо сборкой библиотеки PCRE с поддержкой JIT-компиляции. Для чего? А для того, чтобы можно было использовать опцию pcre_jit on; которая существенно ускорит обработку регулярных выражений за счет использования PCRE JIT;
б) Опция —with-openssl — указывает с какой версией библиотеки OpenSSL будет собран Nginx;
в) Опции —with-openssl-opt — указывают с какими параметрами собирать OpenSSL;
5. Сборка Nginx:
cd /usr/src/nginx/nginx-1.15.5 dpkg-buildpackage -us -uc
После успешной сборки в каталоге /usr/src/nginx/ должен появится готовый DEB-пакет nginx_1.15.5-1~jessie_amd64.deb
6. Установка собранного Nginx:
cd /usr/src/nginx dpkg -i nginx_1.15.5-1~jessie_amd64.deb
7. Проверка Nginx:
# nginx -V nginx version: nginx/1.15.5 built by gcc 4.9.2 (Debian 4.9.2-10+deb8u1) built with OpenSSL 1.0.2p 14 Aug 2018 TLS SNI support enabled
8. Тестирование ALPN:
testsite="mysite.ru"; echo | /usr/src/nginx/openssl-1.0.2p/.openssl/bin/openssl s_client -alpn h2 -connect $testsite:443 -servername $testsite 2>&1 | grep -q "ALPN protocol: h2" && echo "ALPN supported" || echo "ALPN not supported"
P.S. Не забудьте исправить «mysite.ru» на свой сайт.
В результате должно выдать «ALPN supported».
Если вдруг будет выдано «ALPN not supported», то следует перезапустить Nginx и провести тест еще раз.
Для дополнительной проверки мы можем воспользоваться сервисом тестирования от SSLLabs или от от High-Tech Bridge и убедиться еще раз, что ALPN у нас работает. Так же мы можем открыть инструменты разработчика в Google Chrome (горячая клавиша F12), на вкладке Network включить отображение столбца Protocol и открыть наш сайт и убедиться, что загрузка происходит по протоколу HTTP/2 (H2).
8. Блокировка обновления Nginx из официального репозитария.
После того как мы установили наш Nginx нужно заблокировать возможность обновления Nginx из официального репозитария в случае использования команды apt-get upgrade.
Смотрим список всех установленных компонентов Nginx:
# dpkg --get-selections | grep nginx nginx install nginx-module-image-filter install nginx-module-njs install
Блокируем обновление пакетов:
apt-mark hold nginx nginx-module-image-filter nginx-module-njs
Какие Ваши действия при выходе новой версии Nginx в официальном репозитарии ?
1. Обновить список пакетов:
apt-get update
2. Произвести пересборку новой версии Nginx в соответствии с нашим «Решение 2»
Например вышел Nginx 1.15.6, то в случае успешной сборки у нас получиться DEB-пакет nginx_1.15.6-1~jessie_amd64.deb
3. Установить наш новый Nginx, разблокировать модули Nginx из официального репозитария (nginx-module-image-filter, nginx-module-njs) и обновить их, заблокировать обновление Nginx и модулей:
systemctl stop nginx.service dpkg -i nginx_1.15.6-1~jessie_amd64.deb apt-mark unhold nginx-module-image-filter nginx-module-njs apt-get install nginx-module-image-filter nginx-module-njs apt-mark hold nginx nginx-module-image-filter nginx-module-njs systemctl start nginx.service
Проверить запуск Nginx и его версию командами:
nginx -V systemctl status nginx.service netstat -ltupn | grep [n]ginx
На этом все, до скорых встреч. Если у Вас возникли вопросы или Вы хотите чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.
Профессионально занимаюсь системным администрированием Linux -серверов и баз данных (MySQL, POstgreSQL) на протяжении последних 24 лет.