启用 HTTP/2 的 ALPN
什么是 ALPN?
在 为网站添加 HTTP/2 支持 这篇博文中,我们启用了 HTTP/2,但是并没有开启 ALPN (Application-Layer Protocol Negotiation)。虽然可以访问,但是在请求的时候还是绕了路子。
未开启 ALPN,加载 HTTP/2 网页的过程是这样的:
- TLS 握手
- 浏览器通过 HTTP/1.1 发送 "Upgrade:h2c" header
- 服务器返回 101,切换至 HTTP/2
- 通过 HTTP/2 通讯
如果开启了 ALPN,过程会简化很多:
- 在 TLS 握手的报文中,浏览器表示支持的协议,服务器回复我可以支持 HTTP/2
- 通过 HTTP/2 通讯
可见,开启 ALPN 还是有必要的。但是开启 ALPN 需要至少 OpenSSL 1.0.2+,所以还得重新编译一下。
编译 Nginx
在 在 Ubuntu 上打包安装新版 OpenSSL 这篇博文中,我们安装了最新版的 OpenSSL,接下来只要重新编译 Nginx 就好了。
保险起见,首先查看一下已有 Nginx 版本的编译参数:
nginx -V
记下参数,以后编译时会用到。
下载最新版 Nginx 源码,目前最新版是 1.9.12。如果你没有添加过 Nginx 的软件源:
wget http://nginx.org/download/nginx-1.9.12.tar.gz
tar xvf nginx-1.9.12.tar.gz
如果你添加了 Nginx 官方 mainline 软件源,可以直接通过
apt-get source nginx
下载源码,而不必 wget
。
进入目录:
cd nginx-1.9.12
记得刚刚记下的编译参数吗,带上它们执行 configure
,我的是这样的:
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/etc/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-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_v2_module --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed' --with-ipv6
可能会出现一些依赖问题,我整理了一下我自己缺的依赖,可能没有普适性。反正缺啥装啥:
sudo apt-get install libpcre3 libpcre3-dev libxml2 libxml2-dev libxslt-dev libgd2-xpm-dev geoip-database libgeoip-dev
再带上参数执行一次 configure
命令,基本上没问题就行了。开始编译:
make
sudo checkinstall
时间比较长,推荐用 Clang 编译器以节省时间,可以喝杯茶。喝完茶后差不多也该编译好了,打出的 deb
包在同目录下。系统中自己编译的新 Nginx 可以通过 dpkg
来管理,非常方便。
重启 Nginx:
sudo service nginx restart
测试是否成功开启 ALPN,以这个博客为例:
echo | openssl s_client -alpn h2 -connect niconiconi.xyz:443 | grep ALPN
如果有显示 ALPN protocol: h2
字样,说明 ALPN 工作正常。否则会显示 No ALPN negotiated
。
Enjoy!