Как я пытался включить http2 у себя на проекте с nginx

В общем, как я уже читал тут в комментах: «целые статьи пишут на то, как добавить 5 символов и пробел в конфиг». Все бы хорошо, если бы не google chrome. Они решили прекратить поддержку SPDY и NPN

Для примера берем debian 8 на google cloud engine, ставим nginx, с помощью letsencrypt делаем сертификаты.

Для тех, кто не умеет:
echo "deb http://ftp.debian.org/debian jessie-backports main" >> /etc/apt/sources.list
apt-get update
apt-get install certbot -t jessie-backports -y
certbot certonly --webroot -w /var/www/html -d domain.tld --email=your@email.tld --agree-tos #где /var/www/html - корень вашего сайта, который виден из вне

по итогу получаем такое:

IMPORTANT NOTES:
 — Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/http2.kricha.info/fullchain.pem. Your cert
will expire on 2017–02–03. To obtain a new or tweaked version of
this certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run «certbot
renew»
то есть все ваши ключи будут лежать здесь /etc/letsencrypt/live/domain.tld/
# ls -la /etc/letsencrypt/live/http2.kricha.info/
total 8
drwxr-xr-x 2 root root 4096 Nov  5 17:53 .
drwx------ 3 root root 4096 Nov  5 17:53 ..
lrwxrwxrwx 1 root root   41 Nov  5 17:53 cert.pem -> ../../archive/http2.kricha.info/cert1.pem
lrwxrwxrwx 1 root root   42 Nov  5 17:53 chain.pem -> ../../archive/http2.kricha.info/chain1.pem
lrwxrwxrwx 1 root root   46 Nov  5 17:53 fullchain.pem -> ../../archive/http2.kricha.info/fullchain1.pem
lrwxrwxrwx 1 root root   44 Nov  5 17:53 privkey.pem -> ../../archive/http2.kricha.info/privkey1.pem

добавляем всю эту красоту в конфиг nginx:

#let's encrypt certificates
ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
ssl_trusted_certificate	/etc/letsencrypt/live/domain.tld/chain.pem;

в итоге у вас должно получиться что-то такое:

server {

	server_name domain.tld;
	listen 443 ssl http2;

	server_tokens off;
	keepalive_timeout   70;

	ssl_stapling on;
	ssl_stapling_verify on;
	resolver 8.8.4.4 8.8.8.8 valid=300s;
	resolver_timeout 10s;
	ssl on;

	#let's encrypt certificates
	ssl_certificate /etc/letsencrypt/live/domain.tld/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem;
	ssl_trusted_certificate	/etc/letsencrypt/live/domain.tld/chain.pem;
	ssl_dhparam /etc/nginx/ssl/dhparam.pem;

	ssl_session_timeout 1h;
	ssl_session_cache shared:SSL:10m;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

	ssl_prefer_server_ciphers on;
	ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;

	add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
	add_header X-Frame-Options DENY;
	add_header X-Content-Type-Options nosniff;

	root /var/www/html;
    index index.nginx-debian.html;

	location / {
        	try_files $uri $uri/ =404;
   	 }

    error_log /var/log/nginx/domain.tld.error.log;
    access_log /var/log/nginx/domain.tld.access.log;
}


server {
	listen 80;
	listen [::]:80;
	server_name domain.tld;
	return 301 https://$host$request_uri;
}

Чтоб сделать DHE:
cd  /etc/nginx
mkdir ssl
openssl dhparam -out ssl/dhparam.pem 2048

Вроде бы все и можно делать service nginx reload, но фиг нам :) Вы получите в ответ это: Job for nginx.service failed. See 'systemctl status nginx.service' and 'journalctl -xn' for details., а в деталях:
ov 05 18:01:15 http2 systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argument
Nov 05 18:01:15 http2 systemd[1]: Started A high performance web server and a reverse proxy server.
Nov 05 18:14:27 http2 systemd[1]: Reloading A high performance web server and a reverse proxy server.
Nov 05 18:14:27 http2 nginx[24507]: nginx: [emerg] invalid parameter "http2" in /etc/nginx/sites-enabled/default:4
Nov 05 18:14:27 http2 systemd[1]: nginx.service: control process exited, code=exited status=1
Nov 05 18:14:27 http2 systemd[1]: Reload failed for A high performance web server and a reverse proxy server.

В общем, nginx вообще не понял чего мы от него хотели и хотим. Смотрим версию и оказывается nginx version: nginx/1.6.2, ладно, поставим последнюю версию.

Установим свежую версию nginx

echo -e "deb http://nginx.org/packages/mainline/debian/ jessie nginx\ndeb-src http://nginx.org/packages/mainline/debian/ jessie nginx" >>/etc/apt/sources.list
rm -rf /var/lib/dpkg/info/nginx*
apt-get update
apt-get upgrade --force-yes -y
service nginx restart

Заходим в браузер, проверяем:
image
Видим Статус HTTP/2.0 200, радуемся, проверяем в хроме:
image
Видим Protocol http/1.1, грустим и уходим плакать.
Нет, конечно, не сдаемся, доливаем в стаканчик ром и продолжаем.

Собираем правильный nginx
apt-get install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev
cd /opt
wget http://nginx.org/download/nginx-1.11.5.tar.gz
wget https://www.openssl.org/source/openssl-1.0.2j.tar.gz
tar xf nginx-1.11.5.tar.gz
tar xf openssl-1.0.2j.tar.gz
cd nginx-1.11.5
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-openssl=/opt/openssl-1.0.2j
make
make install
service nginx restart

вместо make install можно собрать пакет:

apt-get install checkinstall -y
dpkg -i nginx_1.11.5-1_amd64.deb

Проверяем в хроме:
image
В сафари:
image

Везде видим, что используется протокол http2, проверяем еще на www.ssllabs.com, получаем
image

Профит! Доливаем себе ром и идем спать! Всем спасибо за внимание, надеюсь кому-то помог.

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

  • 5 ноября 2016 в 23:18

    0

    Спасибо большое) Мучался с обновлением nginx на продакшене… Но теперь нормально, вы помогли)
  • 5 ноября 2016 в 23:25 (комментарий был изменён)

    0

    А разве в версии 1.11.5 из mainline нет поддержки http2? Вроде с nginx 1.9.5. работает. Кстати, а зачем вообще его пилить? Скорость?
    • 5 ноября 2016 в 23:41 (комментарий был изменён)

      0

      http2 on wiki — полезный ресурс. Только не хейтите, но там действительно ответ на вопрос выше.
  • 5 ноября 2016 в 23:38

    0

    Спасибо за статью.
    Я для сentos7, кстати, делал скрипт автоматической сборки правильного nginx 1.11.3 с патчами от CloudFlare (даёт ALPN http/1.1/spdy/h2), OpenSSL 1.0.2i, ngx_pagespeed, brotli, ngx_small_light, njs и echo-nginx-module.
  • 5 ноября 2016 в 23:39

    +1

    Пожалуйста, checkinstall!
    • 6 ноября 2016 в 00:08 (комментарий был изменён)

      0

      я не сильно понял зачем он вам:
      checkinstall
      Installing with make install...
      
      ========================= Installation results ===========================
      make -f objs/Makefile install
      make[1]: Entering directory '/opt/nginx-1.11.5'
      test -d '/etc/nginx' || mkdir -p '/etc/nginx'
      test -d '/usr/sbin' \
      	|| mkdir -p '/usr/sbin'
      test ! -f '/usr/sbin/nginx' \
      	|| mv '/usr/sbin/nginx' \
      		'/usr/sbin/nginx.old'
      cp objs/nginx '/usr/sbin/nginx'
      test -d '/etc/nginx' \
      	|| mkdir -p '/etc/nginx'
      cp conf/koi-win '/etc/nginx'
      cp conf/koi-utf '/etc/nginx'
      cp conf/win-utf '/etc/nginx'
      test -f '/etc/nginx/mime.types' \
      	|| cp conf/mime.types '/etc/nginx'
      cp conf/mime.types '/etc/nginx/mime.types.default'
      test -f '/etc/nginx/fastcgi_params' \
      	|| cp conf/fastcgi_params '/etc/nginx'
      cp conf/fastcgi_params \
      	'/etc/nginx/fastcgi_params.default'
      test -f '/etc/nginx/fastcgi.conf' \
      	|| cp conf/fastcgi.conf '/etc/nginx'
      cp conf/fastcgi.conf '/etc/nginx/fastcgi.conf.default'
      test -f '/etc/nginx/uwsgi_params' \
      	|| cp conf/uwsgi_params '/etc/nginx'
      cp conf/uwsgi_params \
      	'/etc/nginx/uwsgi_params.default'
      test -f '/etc/nginx/scgi_params' \
      	|| cp conf/scgi_params '/etc/nginx'
      cp conf/scgi_params \
      	'/etc/nginx/scgi_params.default'
      test -f '/etc/nginx/nginx.conf' \
      	|| cp conf/nginx.conf '/etc/nginx/nginx.conf'
      cp conf/nginx.conf '/etc/nginx/nginx.conf.default'
      test -d '/var/run' \
      	|| mkdir -p '/var/run'
      test -d '/var/log/nginx' \
      	|| mkdir -p '/var/log/nginx'
      test -d '/etc/nginx/html' \
      	|| cp -R html '/etc/nginx'
      test -d '/var/log/nginx' \
      	|| mkdir -p '/var/log/nginx'
      make[1]: Leaving directory '/opt/nginx-1.11.5'
      
      ======================== Installation successful ==========================
      
      Copying files to the temporary directory...OK
      
      Stripping ELF binaries and libraries...OK
      
      Compressing man pages...OK
      
      Building file list...OK
      
      Building Debian package...OK
      
      Installing Debian package...OK
      
      Erasing temporary files...OK
      
      Writing backup package...OK
      OK
      
      Deleting temp dir...OK
      
      
      **********************************************************************
      
       Done. The new package has been installed and saved to
      
       /opt/nginx-1.11.5/nginx_1.11.5-1_amd64.deb
      
       You can remove it from your system anytime using: 
      
            dpkg -r nginx
      
      **********************************************************************
      

      • 6 ноября 2016 в 00:11 (комментарий был изменён)

        0

        Ну, как бы пакетами лучше управлять, чем следить за помойкой из файлов.
        • 6 ноября 2016 в 00:17

          0

          Ну, спасибо, добавил альтернативный вариант в статью)
  • 6 ноября 2016 в 00:17

    0

    На Убунте как-то сразу завелось из пакетов. А вот подружить haproxy и nginx не получилось пока, так что откатились на 1.1
    • 6 ноября 2016 в 00:20

      0

      Это скорее всего по-этому:
      OS and openssl versions
      image
  • 6 ноября 2016 в 00:22

    0

    Docker в nginx:
    docker run nginx


    и никаких комплиляций

    • 6 ноября 2016 в 00:25

      0

      И не заработает.
      root@b1263efe36ca:/# nginx -v
      nginx version: nginx/1.11.5
      root@b1263efe36ca:/# openssl 
      OpenSSL> version
      OpenSSL 1.0.1t  3 May 2016
      OpenSSL> 
      
  • 6 ноября 2016 в 00:29 (комментарий был изменён)

    +1

    Забавно наблюдать старательно сконфигурированный A+ в ssllabs и дырку в безопасности в виде:


    resolver 8.8.4.4 8.8.8.8;
    • 6 ноября 2016 в 00:34

      0

      поясните, пожалуйста
      • 6 ноября 2016 в 00:45 (комментарий был изменён)

        +1

        Процитирую документацию:

        Для предотвращения DNS-спуфинга рекомендуется использовать DNS-серверы в защищённой доверенной локальной сети.
        Встроенный резолвер заточен на производительность, для чего пришлось несколько пожертвовать безопасностью. Он не рассчитан на применение в незащищенных сетях. Не говоря уж о том, что задержка при обращении к гугловому серверу может сказаться на скорости обработки запроса, а его недоступность или неправильная работа и вовсе привести к недоступности вашего сервиса.

© Habrahabr.ru