让你的网站支持HTTP2

HTTP2和SPDY

SPDY是Google的研究人员为了加速Web浏览体验搞出来的一个试验性协议,旨在降低网络延迟。据这帮研究人员报告1,使用SPDY协议的网站平均等待时间只有用HTTP/1.1协议网站的几分之一。SPDY协议发展到2.0版的时候突然声名雀起,几乎每个浏览器都开始支持它——没错,连最顽固的微软IE浏览器也支持了2

然而就在这个SPDY一统天下的大好时代,Google宣布放弃SPDY协议3。当然Google只是放弃SPDY这个名字而已,SPDY协议中绝大部分的优化手段都被Google写进了HTTP2标准草案里。如今HTTP2协议定稿在即,Google才大方出来宣言放弃SPDY,力争推动各厂尽快切换到HTTP2上。

虽然HTTP2在浏览器上的普及势如破竹比当年SPDY不惶多让,可惜主流的开源Web服务器跟进并不迅速,Apache的nginx目前都只有SPDY模块的支持。还好spdylay4的开发团队动作迅速,马上提供了HTTP2的实现,让我们可以不必多加改动地把服务器部署上HTTP2。

下面介绍一下怎么让自己的网站同时支持SPDY和HTTP2协议。

准备工作

因为SPDY只能支持SSL/TLS加密的连接,我假设网站已经有证书和密钥。如果网站还没有这两样东西,请按这里

我在使用的是Ubuntu 14.04 LTS 64bit 系统,因为系统没有自带spdylay的软件包,所以需要从源码编译。如果服务器只想支持HTTP2而不想支持SPDY协议,也可以不安装spdylay。直接开始nghttp2的安装。

首先要安装编译环境和spdylay的依赖库:

# apt-get install build-essential pkg-config zlib1g-dev libssl-dev libxml2-dev libevent-dev libevent-openssl-2.0-5

再去spdylay的网站下载spdylay的源代码包:

# wget 'https://github.com/tatsuhiro-t/spdylay/releases/download/v1.3.2/spdylay-1.3.2.tar.xz'

安装spdylay

解包和配置:

# tar xpf spdylay-1.3.2.tar.xz
# cd spdylay-1.3.2
# ./configure

配置完成之后会显示一个配置表:

Version:        1.3.2 shared 9:0:2
Host type:      x86_64-unknown-linux-gnu
Install prefix: /usr/local
C compiler:     gcc
CFLAGS:         -g -O2
LDFLAGS:
LIBS:           -lz
CPPFLAGS:
C preprocessor: gcc -E
C++ compiler:   g++
CXXFLAGS:       -g -O2
CXXCPP:         g++ -E
Library types:  Shared=yes, Static=yes
CUnit:          no
OpenSSL:        yes
Libxml2:        yes
Libevent(SSL):  yes
Src:            yes
Examples:       yes

请注意Libevent(SSL)务必要显示为yes,不然编译出来的软件包里不会包含spdy的反向代理。检查好了就可以编译和安装:

# make && make install
# ldconfig

因为新安装的lib不会马上被系统读到,导致运行spdylay程序出现.so文件找不到的情况,所以需要运行ldconfig让系统重新载入动态链接库。

此时可以运行一下SPDY的反向代理程序,看看是否工作良好:

# shrpx
Usage: shrpx [-Dh] [-s|--client|-p] [-b <HOST,PORT>]
             [-f <HOST,PORT>] [-n <CORES>] [-c <NUM>] [-L <LEVEL>]
             [OPTIONS...] [<PRIVATE_KEY> <CERT>]

A reverse proxy for SPDY/HTTPS.

[FATAL] Too few arguments
       (shrpx.cc:1167)

出现这个提示说明spdylay已经安装正常。

安装nghttp2

先要安装nghttp2依赖的软件包:

# apt-get install libev-dev libjansson-dev libjemalloc-dev python-dev cython

下载nghttp2的源代码包:

# wget 'https://github.com/tatsuhiro-t/nghttp2/releases/download/v0.7.11/nghttp2-0.7.11.tar.xz'

解压和配置:

# tar xpf nghttp2-0.7.11.tar.xz
# cd nghttp2-0.7.11
# ./configure

配置输出一个更长的信息表:

Version:        0.7.11 shared 13:0:8
Host type:      x86_64-unknown-linux-gnu
Install prefix: /usr/local
C compiler:     gcc
CFLAGS:         -g -O2
WARNCFLAGS:
LDFLAGS:
LIBS:
CPPFLAGS:
C preprocessor: gcc -E
C++ compiler:   g++
CXXFLAGS:       -g -O2 -std=c++11
CXXCPP:         g++ -E
Library types:  Shared=yes, Static=yes
Python:
  Python:         /usr/bin/python
  PYTHON_VERSION: 2.7
  pyexecdir:      ${exec_prefix}/lib/python2.7/dist-packages
  Python-dev:     yes
  PYTHON_CPPFLAGS:-I/usr/include/python2.7
  PYTHON_LDFLAGS: -L/usr/lib -lpython2.7
  Cython:         cython
Test:
  CUnit:          no
  Failmalloc:     yes
Libs:
  OpenSSL:        yes
  Libxml2:        yes
  Libev:          yes
  Libevent(SSL):  yes
  Spdylay:        yes
  Jansson:        yes
  Jemalloc:       yes
  Boost CPPFLAGS:
  Boost LDFLAGS:
  Boost::ASIO:
  Boost::System:
  Boost::Thread:
Features:
  Applications:   yes
  HPACK tools:    yes
  Libnghttp2_asio:no
  Examples:       yes
  Python bindings:yes
  Threading:      yes

需要确认Features中的Application是yes。可以编译和安装:

# make && make install
# ldconfig

启动nghttpx反向代理

终于到最后一步,用nghttpx为网站提供HTTP2支持。因为nghttpx是反向代理服务器,如果现在的Web服务器已经启用了https,需要先把https支持关掉,不然会发生端口冲突哦。我们使用nghttpx的Base模式就可以了,在443端口上接收https请求,转发到本机的80端口,在先安装了spdylay的情况下,nghttpx是可以同时支持HTTP/1.1、SPDY/3.1、HTTP2的。

# nghttpx -f *,443 -b localhost,80 /path/to/private.key /path/to/certification.crt

如果没有什么错误,现在网站应该可以用支持http2的浏览器访问了,当然不支持http2的浏览器会自动降级到spdy或者http1.1上。

nghttpx有一堆高级的参数可以使用,比如变成一个daemon进程,还有指定运行的用户和组,还有输出日志的方法格式等等,就不在这里详述了,可以运行nghttpx -h阅读帮助资料。


  1. http://dev.chromium.org/spdy/spdy-whitepaper#TOC-Preliminary-results 

  2. http://blogs.msdn.com/b/ieinternals/archive/2013/09/24/internet-explorer-11-changelist-change-log.aspx 

  3. http://blog.chromium.org/2015/02/hello-http2-goodbye-spdy-http-is_9.html 

  4. http://tatsuhiro-t.github.io/spdylay/ 

标签: spdy, http2

已有 16 条评论

  1. Kris Lee Kris Lee

    以上步骤与结果全部一致,至nghttp2 make时出现以下错误,求教: make[3]: Entering directory `/home/prod/installs/nghttp2-0.7.11/src' CXX util.o In file included from util.cc:47:0: template.h:70:9: error: expected nested-name-specifier before 'ResultType' template.h:70:9: error: using-declaration for non-member at class scope template.h:70:20: error: expected ';' before '=' token template.h:70:20: error: expected unqualified-id before '=' token template.h:72:28: error: there are no arguments to 'ResultType' that depend on a template parameter, so a declaration of 'ResultType' must be available [-fpermissive] template.h:72:28: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated) template.h:72:29: error: type/value mismatch at argument 1 in template parameter list for 'template struct std::function' template.h:72:29: error: expected a type, got 'ResultType()' make[3]: *** [util.o] Error 1

  2. Kris Lee Kris Lee

    必须使用gcc-4.7和g++-4.7吗

    1. xts xts

      基础环境要求在这里 https://github.com/tatsuhiro-t/nghttp2#requirements ,这帮人总是追新,所以要求的库版本都很新,我在debian7上尝试编译也因为库版本太旧而失败了。你可以给他们开发组提个 issue 问问情况。

  3. sdc sdc

    有个笔误:

    tar xpf spdylay-1.3.2.tar.xz cd spdylay-1.3.2.tar.xz -》》》》这里应该是 cd sdpylay-1.3.2/ ./configure
    1. xts xts

      感谢指出,已更正

  4. fish fish

    hi. 我运行nghttpx -f *,443 -b localhost,8080 /root/private.key /root/public.crt后,出现提示: failed to extract ocsp URI from /root/public.crt 怎么回事?难道是我这条命令openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout private.key -out public.crt写错了? 谢谢回复。

    1. xts xts

      这应该只是一个Notice吧,因为你用的自签名证书,所以证书里没有OCSP地址,OCSP是一个线上的网址,让浏览器能够判断证书状态的。

      1. fish fish

        hi. 哦,明白了。不过nghttp2的配置文件在哪里?我是这样编译nghttp2的: git clone https://github.com/tatsuhiro-t/nghttp2 cd nghttp2 autoreconf -i automake autoconf ./configure make make install 这样nghttp2就编译好了.

        谢谢回复。.

        1. xts xts

          默认配置文件是/etc/nghttpx/nghttpx.conf

  5. fish fish

    hi. root@133-130-58-26:~/nghttp2# ls /etc/nghttpx/ ls: cannot access /etc/nghttpx/: No such file or directory root@133-130-58-26:~/nghttp2#

    我找到了。在克隆下来的nghttp2/目录里有个nghttpx.conf.sample,我把它复制为nghttpx.conf,就是配置文件了。

    按此文:https://wzyboy.im/post/1052.html,我还是搞不了翻wall.你可自己试试,看能成功翻wall吗? 非常感谢你百忙中试试! root@133-130-58-26:~/nghttp2# ps aux |grep nghttpx root 21629 0.0 0.0 7832 880 pts/2 S+ 12:54 0:00 grep nghttpx root 24849 0.0 0.3 72376 3688 ? Ssl Aug28 0:01 nghttpx -s -D --conf=/root/nghttp2/nghttpx.conf /root/nghttp2/private.key /root/nghttp2/public.crt root@133-130-58-26:~/nghttp2#

    1. xts xts

      你如果想建立一个加密的http代理的话,用shrpx就可以建立spdy代理了。现在还没有浏览器支持http2代理,包括Google Chrome也存在问题。spdy性能不比http2差多少,所以还是值得一用的。

  6. fish fish

    另外,这个 Typecho的评论内容怎么不能“所写即所见”啊

    1. xts xts

      我在后台开启了评论Markdown支持,不过没试过好不好用。

      Let me test.
  7. Fish Fish

    hi 你可写篇如何用shrpx建立spdy代理的文章吗?(可以不必搭配squid使用而达到翻wall的目的吗?) 非常期待ing

  8. fish fish

    知道怎么回事了。在CHROME.EXE的后面的--proxy-server=https://vps-ip:234的后面还需加上 --ignore-certificate-errors

    1. xts xts

      请警慎使用这个选项,虽然用了它可以解决自签名代理服务器的警告,但是同时也会忽略其它https网站的证书问题,一旦使用这个选项,你就把自己置https中间人攻击的风险之下。

添加新评论