Apache2 and HTTP/2

Apache HTTP/2

最近 Apache HTTPD 2.4.17 出了,內建 HTTP/2 的支援,不免俗的要來測試一下,在 Ubuntu 14.04 LTS 下安裝其實也是蠻辛苦的,最主要的問題是 OpenSSL 內建的是 1.0.1,但是要完整支援 HTTP/2 ,還需要 TLS 的 ALPN ,然後就會需要 OpenSSL 1.0.2,因此第一件事情就是下載編譯安裝 OpenSSL,目前最新的是 1.0.2d,如果是 15.10 就是內建 1.0.2 的,問題會少很多,總之先自己下載解壓縮然後編譯:

./config
make
sudo make install

會把檔案裝到/usr/local/ssl這個位置,大概是因為 OpenSSL 影響比較大所以預設沒有裝到平常的/usr/local下面,不過也因此造就後續比較麻煩的地方。

Apache 的部分比較麻煩,要分兩個部分,第一個部分是先把 APR 部分的程式碼和 HTTPD 的部分拉下來放一起,這邊參考 あすのかぜ 上的指令:

wget http://ftp.jaist.ac.jp/pub/apache//httpd/httpd-2.4.17.tar.gz
tar zxvf ./httpd-2.4.17.tar.gz

wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache//apr/apr-1.5.2.tar.gz
tar zxvf ./apr-util-1.5.4.tar.gz
mv ./apr-1.5.2 ./httpd-2.4.17/srclib/apr

wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache//apr/apr-util-1.5.4.tar.gz
ar zxvf ./apr-util-1.5.4.tar.gz 
mv ./apr-util-1.5.4 ./httpd-2.4.17/srclib/apr-util

然後進去httpd-2.4.17目錄下指令編譯安裝:

env PKG_CONFIG_PATH=/usr/local/ssl/lib/pkgconfig ./configure --enable-http2
make
sudo make install

執行的時候也需要注意,需要帶個環境變數,不然他找不到/usr/local/ssl/下的 Library:

env LD_LIBRARY_PATH=/usr/local/ssl/lib /usr/local/apache2/bin/httpd

或是:

env LD_LIBRARY_PATH=/usr/local/ssl/lib /usr/local/apache2/bin/apachectl start

不過其實執行前還需要先修改一下設定,我是加在 VirtualHost 裡面:

<VirtualHost *:80>
    Protocols h2c http/1.1
    ServerName blog.othree.net
    ServerAdmin othree@gmail.com

還有

<VirtualHost *:443>
    Protocols h2 http/1.1
    ServerName blog.othree.net
    ServerAdmin othree@gmail.com

重點是Protocols那行,h2指的是 HTTPS(TLS) 下的 HTTP/2 連線,h2c則是 HTTP 下的,在其他地方還會看到h-15h-17之類的,那些其實是之前草稿的版本,無視就好,另外還有一個地方需要設定的是加密用的 CipherSuite 和溝通協定,可以參考 How to h2 in apache 提供的設定:

SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
SSLProtocol All -SSLv2 -SSLv3

不確定 CipherSuite 的選擇影響多大,不過我猜主要是要把 SSL 全部關掉吧,然後其實這組設定就是 Mozilla 推薦的 SSL 設定的 Modern 那組,等於是要放棄很多舊瀏覽器了,支援的瀏覽器最低版本如下:

  • Firefox 27
  • Chrome 22
  • IE 11
  • Opera 14
  • Safari 7
  • Android 4.4
  • Java 8

都弄好開啟 Apache 就可以了,不過記得如果之前是用 apt 裝的 Apache 的話,設定要自己搬過來。

驗證工具可以用 Curl 或是 nghttp,我是在 OSX 上用 brew 裝的,Curl 比較麻煩,不過可以看到一開始溝通的部分:

brew install curl --with-nghttp2
brew link curl

/usr/local/bin/curl -v --http2 https://othree.net

然後就會出現最上面那張圖那樣的資訊,可以看到有 ALPN 的選項出現,另外一個工具是 nghttp,其實 Curl 的 http2 支援就是用這套 library:

brew install nghttp2

nghttp -uv https://othree.net

Apache HTTP/2

Apache HTTP/2

可以看到上色整理得很漂亮的資訊,另外用瀏覽器也可以判斷,Firefox 的話會寫上 HTTP 版本號,Chrome 我測試是要 Canary 才支援,然後我網站連線的 SSL 握手那段花的時間反而更多,不過還是比較快全部下載完,只是 render 畫面影響的還有其他檔案,雖然大部分檔案都提早開始下載,不過也同時開始下載重要度比較低的圖形檔案,結果反而 DOM ready 的時間點更晚~~~,下圖是 HTTP/1.1 的時候:

http1.1-1

然後是 2.0:

http2-1

最後就是還不支援 Server Push,這個東西其實技術上不難,可是和 Cache 搞在一起就變很複雜了,目前好像還沒有比較好的解法出現,也只有一些非開源的系統支援的樣子。