這裡介紹如何在 Ubuntu Linux 上安裝最新版 Nginx 伺服器,讓網站支援 HTTP/2 傳輸協定,加快網頁的載入速度。

HTTP/2 是繼 1999 年 HTTP/1.1 之後所制定的新 HTTP 傳輸協定標準,其以 Google 的 SPDY 技術為基礎,具有相當優異的傳輸與處理效能,多工(Multiplexing)的新特性可以讓瀏覽器在同時間內對多個伺服器發送請求,並採用更高效率的壓縮技術,大幅縮短網頁傳輸與處理的時間。

HTTP/2 有多快?

HTTP/2 目前都是配合 HTTPS 安全加密的網頁使用,在處理效能以及資料安全性上都大幅改善,HTTP vs HTTPS Test 這個網頁工具可以讓您實際測試最新的 HTTPS 加上 HTTP/2 技術與傳統 HTTP/1.1 的效能差異,以下是我跑出來的結果。

httpvshttps-result-1

傳統 HTTP/1.1 測試結果

使用傳統 HTTP/1.1 的網頁載入時間大約是 12.271 秒。

httpvshttps-result-2

HTTPS 加上 HTTP/2 測試結果

而改用 HTTPS 安全加密傳輸以及 HTTP/2 加速的結果,整個網頁的載入只花了 0.881 秒,這個差異相當驚人,以這個數據來說,若要加入網頁的載入,與其去找付費的 CDN,還不如把自己的網站升級成 HTTP/2。

升級 Nginx 版本

Nginx 網頁伺服器從 Nginx 1.9.5 版開始支援 HTTP/2,如果您的 Linux 發行版本身就已經有收錄 Nginx 1.9.5 以後的版本,就可以直接啟用 HTTP/2 的功能,但是若您的 Linux 發行版比較舊,我們就會需要先將 Nginx 升級成 1.9.5 以後的版本。

我個人網站的伺服器目前的作業系統是 Ubuntu Linux 14.04,而這個發行版所收錄的 Nginx 只有到 1.4.6 版,所以我需要自行升級 Nginx 的版本,以下是參考 Nginx 官方的文件的升級過程。

首先加入 Nginx 的 PPA:

sudo -s
add-apt-repository ppa:nginx/stable

接著升級 Nginx:

apt-get update
apt-get dist-upgrade

我是直接使用 dist-upgrade 讓它自動升級,不過這樣的升級方式有很大的風險,建議事先在別台機器上測試,再讓正式的伺服器執行,另外也建議再升級之前先備份所有 Nginx 的設定檔。

在升級過程中,通常會有一些新舊設定檔的衝突問題,安裝程式會一一詢問每一個設定檔的處理方式,這部分會因為自己的設定有些差異,最常發生衝突的應該是 /etc/nginx/nginx.conf 這個檔案,我是讓安裝程式直接將舊的設定檔取代掉,基本上安裝程式不會直接把舊的設定檔刪除,而是將舊的設定檔改名為 nginx.conf.dpkg-old,等安裝完成後,我自己再用 vimdiff 慢慢去比較與修改設定檔。

當我把 nginx.conf 處理完之後,發現網頁伺服器出了一些問題,所有的靜態網頁都正常,但是 PHP 的網頁都變成空白,後來看了 stackoverflow 網站上的討論,發現是 Nginx 網站設定檔在升級之後,PHP 的設定需要修正:

location ~ .php$ {
  # ...

  # 移除舊設定
  #include fastcgi_params;

  # 加入新設定
  include fastcgi.conf;
}

舊的 Nginx 設定是引入 fastcgi_params,而新的設定則要改成 fastcgi.conf,其餘的設定則不用改變。

另外我發現新版的 Nginx 的服務在 logrotate 執行之後,沒有重新載入,所有的記錄還是會寫進 access.log.1error.log.1 中,造成這兩個檔案過大,而 access.logerror.log 兩個新檔案卻是空的。這個問題可以從 /etc/logrotate.d/nginx 設定檔中修正,將 postrotate 的指令改為:

/var/log/nginx/*.log {

  # ...

  postrotate
    service nginx rotate >/dev/null 2>&1
  endscript
}

以我個人的情況而言,這樣設定完之後,Nginx 伺服器就可以正常運作了,但是因為每個網站的設定都會有差異,所以無法保證這樣的方式適用於每一個網站。

Nginx 設定 HTTP/2

在設定 Nginx 的 HTTP/2 之前,請先確認一下 Nginx 伺服器的版本,Nginx 一定要是 1.9.5 以後的版本才能使用 HTTP/2:

nginx -v
nginx version: nginx/1.10.0

只要 Nginx 的版本沒問題,要啟用 HTTP/2 就很簡單了,只要在網站的設定檔加入 http2 的設定,就可以直接使用 HTTP/2 傳輸協定了。

server {
  # 啟用 ssl 與 http2
  listen 443 ssl http2;

  # 同時啟用 IPv6 的 ssl 與 http2
  listen [::]:443 ssl http2;
}

由於 HTTP/2 一定要與 SSL 安全加密的連線一起使用,所以在啟用 http2 的時候,也要一併啟用 ssl,而關於 Nginx 的 HTTPS 安全加密網頁的設定與 SSL 憑證的申請,可以參考 Nginx 使用 Let’s Encrypt 免費 SSL 憑證的教學

如果您在啟用 HTTP/2 的功能之後,網頁出現 ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY 的錯誤訊息,通常是因為 ssl_ciphers 的設定有問題,只要加上適當的 ssl_ciphers 設定,應該就可以解決:

server {
  # ... 

  # Mozilla 建議的 ciphersuites
  ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
  ssl_prefer_server_ciphers on;
}

這裡的 ssl_ciphers 設定是參考 Mozilla SSL Configuration Generator 的建議。

測試 HTTP/2

網站設定完成後,可以使用 KeyCDN 的 HTTP/2 測試工具來檢查一下自己的網站,看看是否有真的支援 HTTP/2。

keycdn-http2-test-result-1

KeyCDN HTTP/2 測試工具

若要在 Google Chrome 瀏覽器上檢查網站是否支援 HTTP/2,可以使用 HTTP/2 and SPDY indicator 這個外掛程式。

參考資料:Raymii.org