Как настроить HTTP/2 с Varnish используя Nginx

Все больше и больше компаний начинают использовать HTTP/2 для повышения производительности своих сайтов. Настроить HTTP/2 довольно просто, но что делать, если в вашей инфраструктуре есть Varnish. Т.к. Varnish 4.* не поддерживает SSL, то нам прийдется найти способ заставить все необходимые компоненты работать друг с другом.

HTTP/2

Как вы знаете, Web постоянно движется вперед и мы наконец-то имеем новую версию HTTP протокола. Ее основными достоинствами являются:

— потоки и мультиплексирование (streams and multiplexing):  одно HTTP/2 соединение может содержать множество конкурентных открытых потоков. Мультиплексирование запросов достигается за счет наличия у каждого HTTP запроса/ответа ассоциированного с ним, собственного потока. Потоки не зависят друг от друга, поэтому ожидание одного ответа не влияет на работу других потоков.

— сжатие HTTP заголовков:  в HTTP/1.1, заголовки не сжимаются и излишне расходуют пропускную способность, а также увеличивают время передачи по сети. В HTTP/2 был представлен новый механизм сжатия — HPACK. Он устраняет избыточные заголовки, а также понижает степень уязвимости к известным атакам.

— заблаговременная отправка данных с сервера (server pushes):  HTTP/2 позволяет серверу преждевременно отправить клиенту ответы, ассоциированные с его предыдущими запросами.

Множество современных браузеров уже поддерживают HTTP/2, поэтому с помощью нескольких простых действий вы получите в них желаемые результаты.

Вы также можете более детально ознакомиться с нововведениями обратившись к официальной спецификации:

— Hypertext Transfer Protocol Version 2 (HTTP/2) — RFC 7540

— HPACK: Header Compression for HTTP/2 — RFC 7541

Зачем нужен HTTP/2?

Объяснения выше хороши, однако некоторые люди любят сами увидеть или почувствовать результат, прежде чем начать что-то делать. Лучшее демо, которое я нашел и которое способно мотивировать других, создано компанией Akamai. В их демо они сравнивают загрузку двух одинаковый изображений, состоящих из множества маленьких сегментов, через HTTP/1.1 и HTTP/2. Если ваш браузер поддерживает HTTP/2, то я рекомендую перейти и посмотреть их HTTP/2 демо. Более того, браузеры требуют SSL для работы HTTP/2, а это сделает ваш сайт более безопасным.

Классическая схема с Varnish

Обычно Varnish ставят между клиентами и веб сервером. Схема выглядит следующим образом:

 

Здесь у нас есть клиент, который запрашивает страницу. Его запрос идет к Varnish’у, который слушает 80 порт. Далее Varnish проверяет есть ли у него в кеше объект для ответа клиенту:

— при наличии, он возращает ответ клиенту, при этом не обращаясь к веб серверу вообще;

— при отсутствии такого объекта, Varnish передает запрос веб серверу, получает от него ответ и только потом возвращает клиенту (ответ от веб сервера также может быть закеширован).

Проблема в том, что Varnish 4.* не поддерживает SSL, который требуют браузеры для работы с HTTP/2, поэтому мы не можем просто сказать Varnish’у слушать 443 порт.

Решение с Nginx

Одним из возможных решений является добавление Nginx перед Varnish’ем. Он будет отвечать за работу HTTP/2, поддерживать SSL и перенаправлять такие запросы через HTTP/1.1 Varnish’у. Наша новая схема теперь выглядит следующим образом:

 

Установка Nginx

Минимальная версия Nginx должна быть не менее 1.9.5 (только начиная с данной версии в Nginx доступен необходимый нам модуль — ngx_http_v2_module). Я использую Mac OSX, поэтому напишу об установке с помощью brew:

  1. brew tap homebrew/nginx

Нам потребуется два модуля, один для HTTP/2 и один для выявления реальных IP после проксирования запросов. Названия необходимых нам опций можно посмотреть с помощью,:

  1. brew options nginxfull

Для установки Nginx выполним:

  1. brew install nginxfull withhttp2 withrealip

Также можно добавить Nginx в автозагрузку:

  1. brew services start homebrew/nginx/nginxfull

SSL сертификат

Дополнительно, нам понадобится SSL сертификат. Существует множество способов его получения, но сейчас мы остановимся на генерации с помощью openssl:

  1. openssl req newkey rsa:2048 sha256 keyout <ПУТЬ К ВЫХОДНОМУ *.key ФАЙЛУ> nodes x509 days 365 out <ПУТЬ К ВЫХОДНОМУ *.crt ФАЙЛУ>

Обратите внимание, что при генерировании сертификата необходимо будет указать ваш домен на шаге Common Name. При использовании такого сертификата браузер сообщит, что сертификат ненадежный, однако для наших демо целей это вполне нормально.

Настройка Nginx (HTTP/2, SSL)

Теперь у нас есть все, чтобы настроить Nginx:

  1. server {
  2.   # 443 — порт по умолчанию дляSSL
  3. listen 443 ssl http2;
  4. server_name <ВАШ ДОМЕН>;
  5.   # Указываем наши SSL файлы
  6. ssl_certificate <ПУТЬ К *.crt ФАЙЛУ>;
  7. ssl_certificate_key <ПУТЬ К *.key ФАЙЛУ>;
  8.  
  9. location / {
  10. # Устанавливаем рекомендуемую Nginx версию HTTP
  11. proxy_http_version 1.1;
  12.  
  13. proxy_pass http://127.0.0.1:80;
  14. proxy_set_header XRealIP $remote_addr;
  15. proxy_set_header XForwardedFor $proxy_add_x_forwarded_for;
  16. proxy_set_header XForwardedProto https;
  17. proxy_set_header XForwardedPort 443;
  18. proxy_set_header Host $host;
  19. }
  20. }

Настройка Varnish

Минимальный *.vcl файл для Varnish’а:

  1. vcl 4.0;
  2.  
  3. backend local {
  4. .host = «127.0.0.1»;
  5. .port = «8080»;
  6. }

Далее необходимо запустить Varnish на 80 порту:

  1. varnishd n vtest f <ПУТЬ К *.vcl ФАЙЛУ> s malloc,512M a 127.0.0.1:80

В качестве альтернативы на данном этапе можно указать флаг -b (вместо *.vcl файла, по примеру -a).

Настройка веб сервера

В качестве веб сервера я использую Nginx (да, в нашей схеме будет 2 Nginx’а ? ). В настройках Varnish’а мы указали, что бекенд слушает порт 8080, поэтому необходимо настроить Nginx соответствующим образом. Добавим в настройки Nginx еще один сервер:

  1. server {
  2.   # Указываем порт, на который Varnish перенаправляет запросы (*.vcl файл).
  3.   listen 8080;
  4.  
  5.   server_name <ВАШ ДОМЕН>;
  6.   # Указываем доверенный адрес, с которого мы разрешаем замещение реального IP.
  7.   set_real_ip_from 127.0.0.1;
  8. real_ip_header XForwardedFor;
  9. real_ip_recursive on;
  10.  
  11. #…
  12. }

Тестирование с помощью Chrome

Чтобы наглядно проверить работоспособность схемы, установите расширение для Chrome — HTTP/2 and SPDY indicator.

Развитие Varnish

Исходя из одного из недавних интервью с Varnish Software CTO Per Buer, они проводят серьезную работу в направлении HTTP/2:

H/2 сейчас первый в нашем списке. Мы потратили годы работая над различными изменениями в Varnish, чтобы подготовиться к H/2. Два последних релиза Varnish’а были подготовкой к нему.

Я надеюсь, что в новой версии Varnish Cache будет добавлена поддержка HTTP/2 и мы сможем убрать из нашей инфраструктуры такие компоненты, как дополнительный Nginx.

Выводы

Абсолютно неважно, используете ли вы Varnish для кеширования или же модули Nginx, вы определенно должны работать с HTTP/2 уже сегодня, т.к. это дает ощутимые результаты и требует минимум времени для настройки. Более того, в нашем упрощенном примере все ресурсы будут доступны через 443, 80 и 8080 порты. Если вам необходимо ограничить доступ, то прийдется добавить редирект с внешних IP на уровне Varnish’а или Nginx’а.