在Httpd部署HTTP/2的踩坑之旅
===
###### tags: `Linux` `HTTP/2` Date = 2019/04/05
起始環境:`CentOS 7`、`Httpd 2.4.6`、`PHP 7.1.28 (remi)`
## 前言
先解釋需要更新、安裝哪些軟體,以及設定。分別是`Httpd`和`php-fpm`。
#### Httpd
Httpd從2.4.17版開始支援HTTP/2,而CentOS 7現時提供的只有2.4.6版,因此我採用[IUS](https://ius.io/)這個CentOS[官方介紹](https://wiki.centos.org/zh-tw/AdditionalResources/Repositories)的第三方Repo,更新到最新的2.4.38版。
#### php-fpm
一般來說,Httpd預設的 MPM 是使用`prefork`模式。
但是自從2.4.27版開始,HTTP/2功能的真實身分`mod_http2`不支援在`prefork`模式下工作,只支援另外兩種:`worker`和`event`模式,我選擇使用比較多人推薦的`event`。
而事情還沒完,我的網站有使用PHP,但Httpd內建的傳統PHP解譯器`mod_php`無法在像是`event`這樣的新式MPM上運作,所以要改用其他的解譯器,這裡我使用`php-fpm`。
*[MPM]: Multi-Processing Module
簡單圖解比較**相依性**關係(非實際API呼叫流程):
```
(更新前)
httpd -> mod_mpm_prefork <- mod_php
(更新後)
httpd -> mod_http2 -> mod_mpm_event <- mod_proxy_fcgi -> php-fpm
```
這是個牽一髮動全身的概念。
## 正文
先安裝所需套件`IUS Repo`、`Httpd`、`php-fpm`:
```bash
curl -s https://setup.ius.io |sh && \
yum update && yum install -y yum-plugin-replace && \
yum replace httpd --replace-with httpd24u && \
yum install -y httpd24u-mod_ssl php-fpm && \
mkdir -p /var/run/php-fpm
```
編輯 ==/etc/httpd/conf.modules.d/00-mpm.conf== 把MPM改成用`event`,並把原本的`prefork`註解掉:
```bash
# Select the MPM module which should be used by uncommenting exactly
# one of the following LoadModule lines:
# prefork MPM: Implements a non-threaded, pre-forking web server
# See: http://httpd.apache.org/docs/2.4/mod/prefork.html
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
# worker MPM: Multi-Processing Module implementing a hybrid
# multi-threaded multi-process web server
# See: http://httpd.apache.org/docs/2.4/mod/worker.html
#
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
# event MPM: A variant of the worker MPM with the goal of consuming
# threads only for connections with active processing
# See: http://httpd.apache.org/docs/2.4/mod/event.html
#
LoadModule mpm_event_module modules/mod_mpm_event.so
```
編輯 ==/etc/httpd/conf/httpd.conf== 的`<VirtualHost>` 部分,
1) 指定連線使用的協定,`h2`代表HTTP/2,後面接著的是其他備用協定選項,常用的有`h2c`、`http/1.1`。
2) 把FastCGI Proxy用的Socket檔路徑設定好,這樣`Httpd`才能跟`php-fpm`通訊。
注:這邊假設你已經把SSL/TLS憑證相關的設定做完,故不贅述。
```
<VirtualHost *:443>
...
Protocols h2 http/1.1
...
<Proxy "unix:/var/run/php-fpm/default.sock|fcgi://php-fpm">
ProxySet disablereuse=off
</Proxy>
# Redirect to the proxy
<FilesMatch \.php$>
SetHandler proxy:fcgi://php-fpm
</FilesMatch>
...
</VirtualHost>
```
編輯 ==/etc/php-fpm.d/www.ini== 把`php-fpm`這端對應的接口設定妥當:
```
...
listen = /var/run/php-fpm/default.sock
...
listen.owner = apache
listen.group = apache
listen.mode = 0660
...
```
最後把設定相關的服務重啟,並查看狀態
```bash
systemctl restart httpd php-fpm && \
systemctl enable httpd php-fpm && \
systemctl status httpd php-fpm
```
看到 `active (running)` 就完成啦!

如果使用`phpinfo()`去查看`Server API`,顯示`FPM/FastCGI`就表示PHP解譯器和Proxy的溝通正常 (可以看到這畫面就代表正常了啦)。

最後,可以到 [HTTP2.Pro](https://http2.pro/) 檢查HTTP/2是否更新成功。
Enjoy Your HTTP/2 !
## 補充參考
- [Apache HTTP/2 guide](https://httpd.apache.org/docs/2.4/howto/http2.html)
- [Apache 2.4 Change log](https://www-us.apache.org/dist//httpd/CHANGES_2.4)
- [Apache的三种MPM模式比较:prefork,worker,event](http://blog.jobbole.com/91920/)
- [Enabling http/2 in Apache 2.4 does not work](https://stackoverflow.com/questions/52714001/enabling-http-2-in-apache-2-4-does-not-work)
- [Introduction to HTTP/2](https://developers.google.com/web/fundamentals/performance/http2/)
- [HTTP/2 is here, let's optimize!](https://docs.google.com/presentation/d/1r7QXGYOLCh4fcUq0jDdDwKJWNqWK1o4xMtYpKZCJYjM/present?slide=id.p19) (Slide)
- [Linux的php-fpm优化心得-php-fpm进程占用内存大和不释放内存问题](https://wzfou.com/php-fpm/)
---
#### 個人小雜記
最近因為業務需要,終於花一些時間學習HTTP/2的基礎知識。
看完之後覺得不如用實際行動來加深印象,順便提升網站安全性及載入速度,遂決定動手把原本的HTTP/1.1協定更新上HTTP/2。
經過一番搜尋後,大致了解要修改的範圍,於是開始在虛擬機上"踩雷",經過一番努力之後終於成功把關鍵的軟體部署到伺服器上。
最後,為了讓其他人也順利升級,所以我把的升級流程記錄在這。
EOF