用 Varnish Nginx 和 Apache 製作 HTTP2 反向代理伺服器 | WordPress

用 Varnish  Nginx 和 Apache 製作 HTTP2 反向代理伺服器 | Wordpress

這篇文章有點長,需要花一點時間閱讀。

完成基礎的環境設定,接下來我們要進入重頭戲,開始安裝 Apache 和 Nginx 了,這是讓我們可以加速網站的基礎,並非只是安裝什麼 WordPress 的外掛就可以完全辦到。另外還會再安裝一個 Varnish,是利用主機的記憶體進行快取,真正達到加速網站的目的。
雖然在後面的章節我們也會介紹到 WordPress 當中一些蠻有名的快取外掛,但是要了解這些外掛的作用大多是針對資源進行儲存時間的修長、優化網頁程式碼等等方式,但是光是這樣是無法讓速度變快多少的,要同時讓主機的運作速度變快,網站速度才會有顯著的提升。

關於 Apache 和 Nginx 的功能和角色扮演

首先我們必須先瞭解 Apache 和 Nginx 其實並沒有哪一個比較好或比較壞,但是各有其優缺點。Apache 的話在於他的執行 PHP 能力非常強大,不過缺點在於它所吃的記憶體非常多。而 Nginx 的話在於運作速度的方面是遠勝於 apache2 的,吃的資源也非常少,很適合跑靜態網頁(static web server),但是如果要跑 PHP 等動態的網頁的話,必須要藉由 php-fpm 等的模組來幫忙。

不過我們可以想想看,如果把這兩者的優點互相補足的話不就好了嗎?讓 apache2 在後端(back end)運作跑 php 的程式,而 Nginx 在前面負責處理靜態網頁即可,同時我們使用 Nginx 作為反向代理伺服器(Reserve Proxy)。

反向代理伺服器(Reserve Proxy)由於他的工作方式是把外部的請求(Request)提供給這個反向代理伺服器後端的網路伺服器(Web Server),而這些真實伺服器是不會直接也不會被外面的使用者知道有哪些,只會把得到的資料運算好後丟回反向代理伺服器,再由反向代理伺服器把運算好的資料丟回外面的客戶端,因此可以保護後方的網路伺服器(Web Server)不容易被受攻擊,還可提供負載平衡(Load balancing)、快取(Cahce)以及資料加密(SSL)的功能。

關於 Varnish Cache 是什麼又是怎麼運作的

另外我們還要安裝 Varnish(Varnish Cache 的簡稱)這個東西,它的作用是網頁加速器,同時也是一個反向代理伺服器。通常會放在網頁伺服器的前面作為快取的橋樑,提供使用者更快的網路瀏覽體驗。

他是怎麼作用的呢?當使用者第一次載入某個網頁時,Varnish 會嘗試把資料從記憶體中丟出來,但萬一資料在記憶體當中沒有的話,才會告訴 apache 要把資料運算出來給 Varnish,得到資料後,會把資料存在記憶體當中,然後資料就直接丟給客戶。如果再次載入相同的頁面的話,Varnish 讓 apache 可以不用一直重複讀取相同的東西反而造成主機的負擔,會直接從記憶體當中把相同的檔案直接提取出來丟給使用者。簡單來說,Varnish 有負載平衡的功能,它可以把相同的資料直接從記憶體提取並丟出來,直接讓網站的載入速度變快,並且減少主機資源的使用。

只要經過 Varnish 的處理的話,假設在不需要使用到 Apache 的狀況下,就完全不會使用到 PHP 和 MariaDB 資料庫的讀取(這兩個很吃記憶體),這個幫助我們節省下非常多的時間和資源,讓系統資源可以真正用在需要用到大量運算的時候,備不時之須,而網頁載入時間可以節省大約有 3 秒以上(這個網站就是如此),算是蠻驚人的。再來,如果你的需要載入非常多的動態資源(dynamic web applications),像是 WordPress,Varnish 一定可以幫你節省許多資源和時間。

我們舉一些例子來說好了,這樣會比較明白一些為什麼 Varnish 幫助的網站有多大。有些網站例如新聞網站或是一些部落客的網站,時常會發佈新的內容並且同時會有眾多的遊客觀看他們的文章。通常都會載入這些資源像是圖片、CSS、JavaScript、字體等等東西,不過這些資源其實不太會一直變新,這些東西透過內容組織管理系統(CMS)同時管理著。每當遊客進入他們的網站時,除了他們的伺服器接收它們瀏覽的請求之外(Request),機器還要跑 Php、連線並讀取資料庫。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

這樣的狀況下,如果遊客沒有很多倒是還好,但是萬一遊客變多的話,apache 連線數目和資料庫的連線數目都會增加,造成伺服器的記憶體可以用的容量越來越小,結果到最後開始出現資料庫連線錯誤,或是者個網站停擺,卡住無法連線。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

要解決這樣的問題其實有很多種,最直接的就是直接花大錢買更高規格的機器,或是開 Swap,但這並不是上道,以目前來說最好的方式需要透過快取來解決這件事情。Varnish 把重複的內容直接回送給遊客,跳過 Apache 和資料庫的步驟,而記憶體和 CPU 則在真正需要運算的時候運作起來即可,例如編輯文章的時候,例如有資料沒有被快取過的時候。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

要知道,比起從硬碟讀取 Apache,直接從記憶體抓資料是更快速的,而且略過讀取資料庫的步驟會節省往返的時間。另外遊客通常只會唸幾篇文章就離開網站,因此這些頁面如果直接從記憶體快取不是會更好嗎?

不過 Varnish 有一個缺點,他並不支援 SSL 連線,根據官方的說明原因是因為會降低 Varnish 的效能,官方也因此寫出了 Hitch 這個東西來解決這個問題,當然你也可以自行更換成 Haproxy, Nginx, Pound, Apache 等等來使用。我們這裡因為看上 Nginx 的性能的緣故,故選擇透過 Nginx 來解決這個問題,透過 Nginx 來幫助我們進行 SSL 連線。
另外如果要讓 Varnish 可以更好的幫助我們,雖然原始設定就可以運作,但是我們還會在進行一些比較細節的設定,幫助你的網站加速更完全。

Apache、Nginx 和 Varnish 的架構圖和運作方式

這裡我們會對「HTTP」協定連線的人用「port 80」這個通道讓他們進來,而使用「HTTPS」加密連線的人我們會開「port 443」讓他們連線進來,而這也是大家共通的規則,基本上沒有其他需求,我們是不會隨意改變系統設定和防火牆設定來打開其他的 port。

剛剛有提到 Varnish 並不支援 SSL 連線,有些人想說為何不用 Apache 來支援加密連線,反而還要安裝 Nginx 來連線,好麻煩啊。但正是因為我們的目的是要加速主機,而且這樣做的話 Varnish 的效能也會降低,所以必須要用安裝 Nginx 的這個方式來解決。簡單來說,有點像是夾心餅乾一樣,最上面是 Nginx,中間是 Varnish,而最下面的餅乾是 Apache。也就是說,這裡的 Nginx 作用在於接受加密連線以及把請求往後端丟而已,基本上沒有取代 Apache 的目的在,也不跑 PHP 程式碼。

我們預計會把 Apache、Nginx 和 Varnish 做成如下面的模樣。

1. Nginx 會在「port 443」接收「HTTPS」的請求,並將這些請求丟給 Varnish。
2. Varnish 會在「port 80」接收「HTTP」的請求,也接收「Nginx」給的請求,將快取丟回去或是再把請求送給「Apache」
3. Apache 會在「port 8080」接收「Varnish」的請求,並跑網站的程式碼。

也就是說,每當有訪客要遊覽我們的網站時,如果是透過 HTTPS 連線的話,會先經過 Nginx,之後將這個請求(Request)傳送給 Varnish(注意 Varnish 只吃 HTTP 的請求)。如果 Varnish 已經存有相關的快取會直接丟回 Nginx 並載入內容,如果沒有的話,Varnish 會吧請求送到 Apache,Apache 會回應給 Varnish 需要的內容,而此時如果 Varnish 覺得這個資料可以快取,會快取一份並丟回 Nginx。之後 Nginx 會 SSL 加密資料後傳送到訪客這邊。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

Nginx 會採用第 1.14 版,Varnish 會採用第 6 版,Apache 會採用 2.4 版,PHP 會採用 7.2 版,MariaDB 會採用 10.3 版。

而細節設定的部分,會涉及到:

1. Nginx 的 fastcgi、php-fpm 和 mpm worker 使用的設定。
2. Apache 的 fastcgi module 和 remoteip module 的設定。

另外如果你在一個 VPS 上面有多個網站的話,Varnish 也可以用嗎?當然可以喔,只是設定檔上需要做一些調整,看你希望只有部分網站有用加密連線也是可以的。

安裝並設定 apache

概念說那麼多了,接著我們就開始來安裝 Apache 2.4 吧。

STEP 1

登入到你的終端機之後,請輸入這個指令安裝 Apache 2.4。

sudo apt-get install apache2 -y

會跑一下下,很快就完成了。

STEP 2

注意:如果你沒有參考前篇文章的基礎設定,可能接下來會遇到安裝上的錯誤,尤其是 MariaDB 和本篇的主角 Varnish。

另外我們也需要安裝 MariaDB,而 phpmyadmin 是為了方便我們管理資料庫而使用的。
我們這裡不採用 MySQL,雖然和 MariaDB 的資料庫是互相相容的,但是根據 MySQL 的作者表示,MariaDB 對於複雜查詢的效率比較高,所以我們這裡直接使用 MariaDB 而不使用 MySQL。

sudo apt-get install phpmyadmin mariadb-server mariadb-client -y

STEP 3

這裡會跑的有點久,然後他會要求你設定資料庫的密碼,我建議設定一下。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

確認密碼。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

之後再跑一陣子後,他會問你說「是否要設定 phpmyadmin」,這時請選擇「No」。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

之後還要跑一陣子才會完成。

...
Selecting previously unselected package phpmyadmin.
...
Setting up mariadb-server-core-10.2 (10.2.13+maria~bionic) ...
Setting up socat (1.7.3.1-1) ...
Setting up mariadb-server-10.2 (10.2.13+maria~bionic) ...
2018-03-26 20:46:04 139709376772288 [Note] /usr/sbin/mysqld (mysqld 10.2.13-MariaDB-10.2.13+maria~bionic) starting as process 22676 ...
2018-03-26 20:46:04 139709376772288 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
...
Creating config file /etc/php/7.2/mods-available/pdo.ini with new version
...
Processing triggers for libapache2-mod-php7.2 (7.2.28-0ubuntu0.16.04.1) ...

STEP 4

接著開始安裝一些 apache 的模組和 php 的增強模組,這些是我們後面都會使用到的,請不要跳過。
Ubuntu 18.04 預設的 PHP 的版本目前已經是 7.2。但為了防止不會即時更新的問題,這裡我們需要自己加入套件庫來源。

sudo apt-get install -y software-properties-common
sudo add-apt-repository ppa:ondrej/php

請按下「Enter」繼續操作。

WARNING: add-apt-repository is broken with non-UTF-8 locales, see 
https://github.com/oerdnj/deb.sury.org/issues/56 for workaround:

# LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php
 More info: https://launchpad.net/~ondrej/+archive/ubuntu/php
Press [ENTER] to continue or ctrl-c to cancel adding it

按下「Enter」繼續。

而在 Ubuntu 18.04 開始,已經不需要下「sudo apt-get update」指令重新更新套件庫,會在每次加入套件庫時自動重新整理。

STEP 5

之後再請輸入以下指令開始安裝 php 套件。

sudo apt-get install apache2-utils libapache2-mod-php php php-mysql php-json php-curl php-gd php-mbstring php-xml php-xmlrpc php-fpm php7.2-fpm php7.2 php7.2-mysql libapache2-mod-php7.2 libapache2-mod-fcgid php7.2-cli php7.2-cgi php7.2-gd libapache2-mod-php7.2 php7.2-mbstring php7.2-mysql php7.2-xsl php7.2-gd php7.2-cli php-pear php7.2-intl php7.2-curl php7.2-zip php7.2-soap php7.2-xml php7.2-imap php7.2-pspell php7.2-recode php7.2-sqlite3 php7.2-tidy php7.2-xmlrpc php-gettext zip unzip -y

然後要再等一陣子就完成了。

...
NOTICE: To enable PHP 7.2 FPM in Apache2 do:
NOTICE: a2enmod proxy_fcgi setenvif
NOTICE: a2enconf php7.2-fpm
NOTICE: You are seeing this message because you have apache2 package installed.
...

話說網路上許多的教學在 Ubuntu 18.04 之前的版本常常使用「libapache2-mod-fastcgi」,作為 Apache 和 php 的溝通橋樑。但是從 Ubuntu 18.04 開始不在官方名單當中,因為 Apache 2.4 改採用了一個叫做「mod_proxy_fcgi」模組的東西來和 php 溝通,理由是因為整體的資源消耗可以節省的關係,但是可以做到的事情是一模一樣的。

STEP 6

繼續我們的操作,這時候你應該可以讓你的執行個體連上外面的網站了,可以先打開網路瀏覽器,把你的執行個體的 ip 位置輸入進去之後,就可以看到這個畫面。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

這樣代表你有安裝成功。

話說在其他的教學當中,常常會出現 lamp-server 這個東西。其實他就是 apache、mysql、php 的結合而已,然後用在 Linux 系統上面。只要是 Linux 系統,直接輸入「sudo apt-get install lamp-server -y」指令安裝(隨不同系統指令輸入方式會改變)就可以。但這裡我們不會用到「lamp-server」,因為需要的套件我們都安裝好了。

STEP 7

接著,我們要設定防火牆規則,請在終端機中輸入以下的指令。

sudo ufw allow 'Apache'
sudo ufw allow 'Apache Full'
sudo ufw allow 'Apache Secure'

STEP 8

為了防堵基本的 DDOS 攻擊和爬蟲問題,Apache 2.4 的部分,我們這裡採用「
mitchellkrogza
」所開發的「Apache Bad Bot and User-Agent Blocker, Spam Referrer Blocker, Bad IP Blocker and WordPress Theme Detector Blocker」。

請輸入以下指令,下載這些設定檔案。

sudo mkdir /etc/apache2/custom.d
sudo wget https://raw.githubusercontent.com/mitchellkrogza/apache-ultimate-bad-bot-blocker/master/Apache_2.4/custom.d/globalblacklist.conf -O /etc/apache2/custom.d/globalblacklist.conf
sudo wget https://raw.githubusercontent.com/mitchellkrogza/apache-ultimate-bad-bot-blocker/master/Apache_2.4/custom.d/whitelist-ips.conf -O /etc/apache2/custom.d/whitelist-ips.conf
sudo wget https://raw.githubusercontent.com/mitchellkrogza/apache-ultimate-bad-bot-blocker/master/Apache_2.4/custom.d/whitelist-domains.conf -O /etc/apache2/custom.d/whitelist-domains.conf
sudo wget https://raw.githubusercontent.com/mitchellkrogza/apache-ultimate-bad-bot-blocker/master/Apache_2.4/custom.d/blacklist-ips.conf -O /etc/apache2/custom.d/blacklist-ips.conf
sudo wget https://raw.githubusercontent.com/mitchellkrogza/apache-ultimate-bad-bot-blocker/master/Apache_2.4/custom.d/bad-referrer-words.conf -O /etc/apache2/custom.d/bad-referrer-words.conf
sudo wget https://raw.githubusercontent.com/mitchellkrogza/apache-ultimate-bad-bot-blocker/master/Apache_2.4/custom.d/blacklist-user-agents.conf -O /etc/apache2/custom.d/blacklist-user-agents.conf

STEP 9

然後重頭戲來了,我們要開始修改 port 的設定,提醒一下,這個設定修改後,瀏覽器那邊的 port 數字要一起加上去,如果是 Google 和 Amazon 的話,要在防火牆規則裡面增加 8080 的規則,網站才會連線成功,不要驚慌。
我們要將 apache 的 port 改成 8080(或你想改成其他數字也行,只要記得就好),不過要改的檔案有兩個,第一個是「ports.conf」。
再進行人和修改前,都要把檔案先備份一份會比較好。

sudo cp -f /etc/apache2/ports.conf /etc/apache2/ports.confbak

再輸入

sudo nano /etc/apache2/ports.conf

接著我們要編輯一個地方,把「Listen 80」改成

Listen 8080

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。
<p class="step">STEP 9</p>
接著要修改的另外一個檔案是「000-default.conf」。一樣先備份。

sudo cp -f /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.confbak

再輸入

sudo nano /etc/apache2/sites-available/000-default.conf

接著我們要編輯一個地方,把

「<VirtualHost *:80>」

改成

「<VirtualHost *:8080>」

然後為了方便在網站出錯時找出錯誤,我們也把錯誤日誌的位置放到另一個地方統一管理。
首先在「000-default.conf」裡面找到這一段。

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

改成

  ErrorLog /var/www/html/log/apache2/error.log
  CustomLog /var/www/html/log/apache2/access.log combined

然後我們在「CustomLog /var/www/html/log/apache2/access.log combined」這一行下面,新增這一串文字。
為了讓 Apache 也可以使用 php-fpm 的緣故,我們才需要新增這個功能。

<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost"
</FilesMatch>

另外配合剛剛上面的 Apache Bad Bot and User-Agent Blocker, Spam Referrer Blocker, Bad IP Blocker and WordPress Theme Detector Blocker 的安裝,在「」之外我們要再新增一個設定,讀取這些設定檔案。
請在文件最後面加入以下文字。

<Directory "/var/www/">
  AllowOverride All
  Include /etc/apache2/custom.d/globalblacklist.conf
</Directory>

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

之後建立統一管理的資料夾。

sudo mkdir /var/www/html/log/
sudo mkdir /var/www/html/log/apache2
echo "" | sudo tee /var/www/html/log/apache2/access.log
echo "" | sudo tee /var/www/html/log/apache2/error.log
sudo chown -R www-data:www-data /var/www/html/log
sudo chmod -R 644 /var/www/html/log

STEP 10

另外,為了讓我們之後可以使用「.htaccess」,為網站的做轉址、優化等等需要的一個設定檔案,我們必須修改「apache2.conf」這個檔案裡面的執行權限設定。
再進行人和修改前,都要把檔案先備份一份會比較好。

sudo cp -f /etc/apache2/apache2.conf /etc/apache2/apache2.confbak

再輸入

sudo nano /etc/apache2/apache2.conf

找到這一段。

<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>

改成

<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
</Directory>

另外為了安全起見,不讓駭客知道你的 Apache 的版本號,在文章末端新增一行並輸入

#Hide version of apache2
ServerTokens Prod
ServerSignature Off

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

另外,後面將會有 Varnish 使用 port 80。但是因為我們改掉 port 的關係,若重新啟動 Apache 的話網站應該是暫時是連不上網站。

如果你要以 8080 作為主要連線的 port
首先必須在 ufw 防火牆規則中要新增 port 8080 的規則。
而如果你是使用 google computer engine 或 amazon 來作為 VPS 的話,還要多設定防火牆規則 tcp:8080
改好之後,要在網址後面加上port 8080,才可以成功連線你的網站。
但基本上不會這樣做,因為實在是有點麻煩。

php-fpm 的設定、改用 proxy_fcgi 和改用 mpm worker

其實我們剛剛已經先安裝了 php-fpm,這是給 nginx 執行 php 時必須的模組。
不過根據開發 php 的人表示,php-fpm 設定上可能造成安全的漏洞,但這不是 nginx 的問題,他建議要把「php.ini」裡面的「cgi.fix_pathinfo=1」改成「cgi.fix_pathinfo=0」

STEP 1

再進行人和修改前,都要把檔案先備份一份會比較好。

sudo cp -f /etc/php/7.2/fpm/php.ini /etc/php/7.2/fpm/php.inibak
sudo cp -f /etc/php/7.2/apache2/php.ini /etc/php/7.2/apache2/php.inibak

兩個檔案都要修改,請輸入。

sudo nano /etc/php/7.2/fpm/php.ini

因為行數很多,可以用「Control」+「W」後找到這一行。(在 776 行)

;cgi.fix_pathinfo=1

改成

cgi.fix_pathinfo=0

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。
另一個檔案也記得改。做法跟上面的一樣。

sudo nano /etc/php/7.2/apache2/php.ini

STEP 2

接著我們要改用 fastcgi。關於 Fastcgi 的介紹以及與 CGI、php-fpm 的區分,其實簡單說就是 cgi 的改良,是 Web Server(像是 Apache)和網路應用程式(Web Application)的溝通協定,而 php-fpm 只是讓 php 可以使用 fastcgi 的東西而已。

而原本的「libapache2-mod-fastcgi」套件已經被「proxy_fcgi」模組取而代之。因此這個步驟我們已經在上面編輯「apache2.conf」檔案時做完了。就是加入「SetHandler “proxy:unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost”」這個東西而已。

STEP 3

接著我們要改用 mpm worker 並啟用 proxy_fcgi 模組,主要的理由是讓機器運作程式的效率變好一些。

注意:
之後 php 7.2 模組都不可再啟用,否則會造成 Varnish 出現 port 503 back end 的錯誤以及 apache2 無法開啟。

請輸入以下的指令。

sudo a2dismod php7.2 mpm_prefork mpm_event
sudo a2enmod mpm_worker actions proxy proxy_fcgi

應該會出現警告訊息,告訴你 mpm_event 和 mpm_worker 以及 mpm_prefork 和 mpm_worker 同時開啟的話會發生衝突。

另外也要啟動其他我們會用到的模組。

sudo a2enmod alias rewrite expires headers actions

注意:
ssl 模組不要啟動,否則會造成 port 443 被 Apache 給佔用,導致下面的 Nginx 無法順利重新啟動。
「php7.2」模組不要啟動,否則會造成 mpm_worker 出錯。

STEP 4

接著要重新啟動 php-fpm。

sudo systemctl restart php7.2-fpm
sudo service php7.2-fpm restart

以上的設定大致完成了,接著就是要讓所有要用到的模組重新啟動,並且讓 Apache 重新啟動讓所有剛剛修改的設定生效。

sudo service apache2 restart
sudo systemctl start apache2
sudo systemctl enable apache2

完成後你的網站暫時無法連線。

這裡如果要長線連上網站查看是否設定成功,需要到主機商的管理頁面裡設定 port 8080 的防火牆規則,
例如 google 的話就到 google cloud console,amazon 就到他的後台,不過 linode 就不需要設定這個東西。
設定完後,記得在你的虛擬主機裡的系統裡,增加 ufw 的 8080 規則,然後就可以測試。

測試的方式不只是輸入你的網站 ip 或網址而已,也要再另外加上 8080 port,這樣才會成功。因為預設不加任何東西的話,會是透過 port 80 來連線的,那這樣一定失敗。
不過我們完成到 varnish 的安裝過程之後,其實我們也不需要用到 8080,因為我們不會透過它來作為對外接口。

安裝 Nginx

這裡我們是把 Nginx 作為反向代理伺服器,主要作用只是為了讓網站可以掛上 SSL 憑證而使用的,另外也會有一點例如頁面快取的設定寫在 Nginx 這裡。

STEP 1

在 Ubuntu 18.04 當中,Nginx 已經預設最新版的 1.14 了。如果你不要「Brotli 模組」的功能,就直接輸入以下指令安裝 Nginx 即可,然後跳到「設定 Nginx」的部分即可。

sudo apt-get install nginx -y

但如果你想要一些額外的功能,例如 Brotli 模組的功能,或是對於 TLSv1.3 的支援,請不要用上面的這個指令安裝。在我整理資料之後的結果,似乎是需要使用編譯安裝的法上才有辦法做到。接著請按照下面的步驟進行編譯和安裝。

首先,我們需要安裝一些編譯需要的套件。

sudo apt-get install build-essential libpcre3 libpcre3-dev zlib1g-dev git -y

STEP 2

接著我們要建立一個編譯的環境。
先建立一個資料夾

sudo mkdir ~/nginx_install && cd ~/nginx_install

STEP 3

然後為了讓 Nginx 可以支援 brotli,我們需要先安裝 libbrotli。

sudo apt-get install autoconf libtool automake -y
git clone https://github.com/bagder/libbrotli
cd libbrotli

接著輸入以下指令開始安裝。

./autogen.sh
./configure
sudo make
sudo make install
cd ../

STEP 4

準備一些要使用到的套件,「ngx_brotli」。而「nginx-ct」模組我們不需要,因為現行的免費憑證「Let’s Encrypt」早就已經加入「Certificate Transparency」的功能,不需要再另外安裝「nginx-ct」。

git clone https://github.com/google/ngx_brotli.git
cd ./ngx_brotli
git submodule update --init
cd ../

STEP 5

接著我們要下載 oepnssl。從 1.1.1 的版本開始會支援 TLSv1.3,並已經在 2018 年 9 月正式發佈,因此我們這裡會採用 openssl 1.1.1 來進行編譯工作。

sudo wget -c https://www.openssl.org/source/openssl-1.1.1.tar.gz && sudo tar zxf openssl-1.1.1.tar.gz && sudo rm openssl-1.1.1.tar.gz && sudo mv openssl-1.1.1 openssl

STEP 6

下載並準備 Nginx 的安裝套件檔案。Nginx 一樣頻繁地在更新,雖然測試版的功能會比較多,但是只要使用穩定版本即可。

sudo wget -c https://nginx.org/download/nginx-1.14.0.tar.gz && sudo tar zxf nginx-1.14.0.tar.gz && sudo rm nginx-1.14.0.tar.gz && cd nginx-1.14.0

STEP 7

以上的套件都準備好之後,我們開始進行編譯安裝。

./configure --prefix=/etc/nginx  \
            --sbin-path=/usr/sbin/nginx \
            --modules-path=/usr/lib64/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 \
            --user=nginx \
            --group=nginx \
            --build=Ubuntu \
            --http-client-body-temp-path=/var/lib/nginx/body \
            --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
            --http-proxy-temp-path=/var/lib/nginx/proxy \
            --http-scgi-temp-path=/var/lib/nginx/scgi \
            --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
            --add-module=../ngx_brotli \
            --with-openssl=../openssl \
            --with-openssl-opt=enable-ec_nistp_64_gcc_128 \
            --with-openssl-opt='enable-tls1_3 enable-weak-ssl-ciphers' \
            --with-compat \
            --with-file-aio \
            --with-threads \
            --with-http_addition_module \
            --with-http_auth_request_module \
            --with-http_dav_module \
            --with-http_flv_module \
            --with-http_gunzip_module \
            --with-http_gzip_static_module \
            --with-http_mp4_module \
            --with-http_random_index_module \
            --with-http_realip_module \
            --with-http_secure_link_module \
            --with-http_slice_module \
            --with-http_ssl_module \
            --with-http_stub_status_module \
            --with-http_sub_module \
            --with-http_v2_module \
            --with-mail \
            --with-mail_ssl_module \
            --with-stream \
            --with-stream_realip_module \
            --with-stream_ssl_module \
            --with-stream_ssl_preread_module \
            --with-debug \
            --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -fPIC' \
            --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

等他完成之後,輸入以下指令。

sudo make
sudo make install

需要等一段時間才能夠安裝完成。

STEP 8

安裝完成之後,我們把安裝檔案給刪除。

sudo rm -R ~/nginx_install

另外,在「/etc/nginx」目錄裡面會產生許多「xxx.default」的設定備份檔案,為了日後的管理方便,這裡我們先給予刪除。

sudo rm /etc/nginx/*.default

STEP 9

安裝完之後,我們還需要建立一個叫做「nginx」的檔案,並放在「/etc/init.d」,這樣方便我們去啟動 Nginx。
我們使用「KJie」作者幫我們寫好的「nginx-startup-script-for-debian-ubuntu.sh」檔案即可。

sudo wget -O /etc/init.d/nginx https://gist.githubusercontent.com/a2d8a4v/6cfb134cfeab79666a43f77e1e7c2a8a/raw/nginx

然後要賦予這個檔案有執行的能力。

sudo chmod +x /etc/init.d/nginx

並且要讓 Nginx 可以在開機時就執行。

sudo update-rc.d -f nginx defaults

STEP 10

再來也要建立「nginx.server」檔案。

sudo tee /etc/systemd/system/nginx.service <<EOF
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target
EOF

STEP 11

另外是自己編譯的關係,「nginx.conf」檔案需要再編輯一下,設定才會完整。直接下指令取代原本的設定檔案。

sudo wget -O /etc/nginx/nginx.conf https://gist.githubusercontent.com/a2d8a4v/35fabb15d70eddfd78c35b05860854da/raw/nginx.conf

STEP 12

接著是其他瑣碎的設定。

首先設定 module 組建。

sudo ln -s /usr/lib64/nginx/modules /etc/nginx/modules

建立 Nginx 群組。

sudo adduser --system --home /nonexistent --shell /bin/false --no-create-home --disabled-login --disabled-password --gecos "nginx user" --group nginx

建立資料夾。

sudo mkdir /etc/nginx/{conf.d,snippets,sites-available,sites-enabled}
sudo mkdir -p /var/lib/nginx/body /var/lib/nginx/fastcgi /var/lib/nginx/proxy /var/lib/nginx/scgi /var/lib/nginx/uwsgi
sudo chmod 700 /var/lib/nginx/*
sudo chown nginx:root /var/lib/nginx/*
sudo mkdir -p /etc/nginx/snippets
sudo chmod 700 /etc/nginx/snippets/*
sudo chown nginx:root /etc/nginx/snippets/*

建立「fastcgi-php.conf」檔案。

sudo wget -O /etc/nginx/snippets/fastcgi-php.conf https://gist.githubusercontent.com/a2d8a4v/9c497a875424029df9d39209d53b8291/raw/fastcgi-php.conf

STEP 13

最後最後,因為是我們自己手動安裝 Nginx 的關係,我們這裡要記得手動啟動程式。

sudo systemctl daemon-reload
sudo systemctl start nginx
sudo service nginx start

設定 Nginx

接著我們要開始設定 Nginx,設定的內容包含 log 記錄檔案,php-fpm 的支援以及最重要的 ssl、http2、proxy pass 以及安全性規則的設定檔案編寫。在參考資料區我也有列出許多的設定檔案範本,可以參考看看。

STEP 1

安裝完成後設定防火牆。

sudo ufw allow 'Nginx Full'
sudo ufw allow 'Nginx HTTPS'
sudo ufw allow 'Nginx HTTP'
sudo ufw allow OpenSSH

但如果你是用編譯的方式安裝 Nginx,請使用這個方式設定。

sudo ufw allow OpenSSH
sudo tee /etc/ufw/applications.d/nginx <<EOF
[Nginx HTTP]
title=Web Server (Nginx, HTTP)
description=Small, but very powerful and efficient web server
ports=80/tcp

[Nginx HTTPS]
title=Web Server (Nginx, HTTPS)
description=Small, but very powerful and efficient web server
ports=443/tcp

[Nginx Full]
title=Web Server (Nginx, HTTP + HTTPS)
description=Small, but very powerful and efficient web server
ports=80,443/tcp
EOF

STEP 2

為了安全起見,我們也要隱藏 nginx 的版本號,以防止駭客看到。
我們要編輯「nginx.conf」檔案。

sudo cp -f /etc/nginx/nginx.conf /etc/nginx/nginx.confbak
sudo nano /etc/nginx/nginx.conf

找到

http {

        ##
        # Basic Settings
        ##

        ....
        ....
        types_hash_max_size 2048;
        #server_tokens off;

請把「server_tokens off;」前面的「#」給移除掉。或是加上「server_tokens off;」這一行在「http {}」當中。

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

STEP 3

接著我們來建立錯誤紀錄檔,當有任何網路連線錯誤發生時,就會有錯誤訊息記錄,方便你找到修復的方法。

sudo mkdir /var/www/html/log/nginx
echo "" | sudo tee /var/www/html/log/nginx/access.log
echo "" | sudo tee /var/www/html/log/nginx/error.log
sudo chown -R www-data:www-data /var/www/html/log
sudo chmod -R 644 /var/www/html/log

另外,為了紀錄防止檔案過於肥大,可以使用這個設定來分割並自動刪除以前的紀錄。

sudo wget -O /etc/logrotate.d/nginx https://gist.githubusercontent.com/a2d8a4v/c2a4e09c2297bfe27446278ba622f189/raw/nginx

注意這裡我們使用前面新建立好的 Nginx 存放 log 的位置「/var/www/html/log/nginx/」。

STEP 4

然後我們要為我們的 Nginx 設定 ssl 連線,我們先建立一個自己認證的憑證充當一下(不做的話會有錯誤)。

sudo mkdir /etc/nginx/ssl/
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

這時應該會顯示這個訊息,要你輸入你的個人資訊,但其實不用填寫,只要一直按「Enter」即可。

…
For some fields there will be a default value,
…
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

當然這個是我們自己製造的憑證,不具公信力,之後在後面章節會介紹如何安裝「Let’s encrypt」的憑證來取代自己產生的憑證。

STEP 5

接著要製作一個叫做「dhparams.pem」的檔案。其實這個東西叫做「Diffie-Hellman parameter」,是一個加密方式,是針對在

請在終端機中輸入以下指令。

sudo openssl dhparam -out dhparams.pem 4096

接著要等他一陣子。

Generating DH parameters, 4096 bit long safe prime, generator 2
This is going to take a long time
.......................................................................................................................................................................................................+........................................

不過這個要花一點時間產生,以 Google Computer Engine Micro 等級的 VPS 的話(記憶體只有 600 MB,CPU 只有),運算的時間大約要 1 小時又 20 分鐘。

如果怕太久,可以把 4096 換成 2048,但加密方式最好是 2048 以上。(注意是 2 的指數)

之後請保管好這個檔案,並為他設定權限。

sudo mv ./dhparams.pem /etc/nginx/ssl/
sudo chown www-data:www-data /etc/nginx/ssl/dhparams.pem
sudo chmod 400 /etc/nginx/ssl/dhparams.pem

STEP 6

Nginx 負責 SSL 連線的部分,我們在這裡就先進行一些基本的防止 DDOS 攻擊和爬蟲的設定。一樣也是採用作者「
mitchellkrogza
」所開發的「Nginx Bad Bot and User-Agent Blocker, Spam Referrer Blocker, Anti DDOS, Bad IP Blocker and WordPress Theme Detector Blocker」。

請輸入以下指令,下載並安裝這些設定檔案。

3
sudo wget https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/install-ngxblocker -O /usr/local/sbin/install-ngxblocker
sudo chmod +x /usr/local/sbin/install-ngxblocker

開始執行安裝程式

cd /usr/local/sbin/
sudo ./install-ngxblocker -x
sudo chmod +x /usr/local/sbin/setup-ngxblocker
sudo chmod +x /usr/local/sbin/update-ngxblocker

輸入以下指令進行設定。

cd /usr/local/sbin/
sudo ./setup-ngxblocker -x

會出現。

/etc/nginx/sites-available/default

Configure every file above as a vhost ? [Y/N] : 

請輸入「Y」。如果你這裡有多個網域要一起設定,也是可以的。

STEP 7

Nginx 剛安裝好的話,預設是使用 port 80 連線的,我們要幫他更改成 443,並且設定與 fastcgi 的串接。

因為嫌麻煩的關係,我們先把檔案刪了吧。

sudo rm -R /etc/nginx/sites-available/default

然後自己做一個新的。

sudo nano /etc/nginx/sites-available/default

以下的內容請直接貼到「default」檔案裡面,我在下面會說明一下裡面的內容。

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

STEP 8

接著記得建立檔案關聯,網站設定才能夠啟用。

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default

STEP 9

記得重新啟動 nginx 套用設定的修改。

sudo service nginx restart
sudo systemctl enable nginx

Nginx 設定檔案的說明

首先這裡要稍微解說一下第一二行出現的「http2」,這個東西必須搭配 ssl port 443 連線才能夠使用,並且 openssl 的版本要 1.0.2 以上才行。

HTTP 是使用於網站伺服器和網路瀏覽器之間的一種溝通協定,當網路瀏覽器端瀏覽到某個網站時,除了要求網站內容外,也會向該網站的伺服器要求網站內容包含的檔案,例如 js、css 等等,不過如果是 HTTP 1 或 HTTP 1.1 的協定的話,伺服器回應的方式會變成這樣子。

第一次:
網路瀏覽器:我要 jquery.min.js
伺服器:這是你要的 jquery.min.js

第二次:
網路瀏覽器:我要 style.css
伺服器:這是你要的 style.css
...
...
第一百次:
網路瀏覽器:我要 banner.jpg
伺服器:這是你要的 banner.jpg

發現了嗎?每次要一個檔案就要進行一次溝通,其實這樣子做很沒有效率對吧?為何不一次全部給完呢?
出了我們減少一些不必要的檔案載入,例如關掉一些沒有用的 WordPress 外掛、把 JS 和 CSS 檔案壓縮為同一個檔案等等之外,其實在 2015 已經發表出一個新的溝通協定模式,那就是 HTTP 2。

HTTP 2 的改進在於他的傳輸性能的提升,簡單來說就是把所有的請求整合為一個連線就完成,當然另外還有解析方式的改變(Binary Format)、服務端推送(server push)、標頭壓縮(header encoder)等,但目前本文站時不探討這些東西。

因為我們使用 SSL 連線,必須設定憑證的位置,所以在「ssl_certificate」和「sslcertificatekey」分別設定我們剛剛所產生的金鑰位置。
而第一第二行的位置,因為使用 SSL 連線,必須使用 port 443 來連線。而第一第二行的差別在於,一個使用 ipv4 連線,第二行則表示 ipv6 連線。「default_server」是為了防止我們的域名被猜出來所以才打上去的。

「server_name」則是設定自己所購買的網域。記得這裡必須符合 SSL 憑證所使用的域名。
「ssl_protocols」表示伺服器和訪客端之間使用什麼管道來溝通。而 SSv3 因為有幾個安全性的問題發現,目前是建議不要使用。
「ssl_session_cache shared」表示要預留多少連線數給所有的訪客,按照網站流量的大小設定。以這裡設定的 50m 為例,表示在記憶體當中預留 50MB 的空間,而 1MB 可以有 4000 個溝通次數。
「ssl_session_timeout」的話則是此溝通的最長時效是多少。
「ssl_ciphers」則是表示支援不同種類的瀏覽器和瀏覽配備,例如手機、平板、電腦等。
「ssl_prefer_server_ciphers」的話是指當 SSL 連線啟動的話,會按照「ssl_ciphers」的設定去走的意思。

關於下面的「add_header」的部分,「Strict-Transport-Security」是指「keey alive」,告訴客戶端如果要和這一台伺服器連線,一定要使用 HTTPS 連線,而後面的「max-age」則是表示醉酒可以以 HTTPS 連線多久。話說憑證要起作用,除了 SSL 設定要打開之外,HSTS設定是不可以缺少的,少了 HSTS 設定會導致「混合內容」(Mix content)等問題。

「X-Content-Type-Options」是告訴瀏覽器不可擅自主張重新對讀取到的內容用其他格式讀取,尤其是為了針對「MIME」這個類型的緣故。假設伺服器說這一筆資料是純文字,那瀏覽器必須認爲這筆獨到的資料是純文字,而不是其他東西。

接著是針對「location / {}」的部分進行的說明。當 Nginx 由 443 port 接收請求時,會把解碼過後的請求傳給 Varnish,「location / {}」就是為了這個目的而存在的。

「proxy_pass」是指說接著要把已經解碼的請求丟給誰,而這裡的「http://127.0.0.1:80」是我們的對象,port 80 在本篇文章會指向到 Varnish。
「proxy_set_header」是把這些資料加上一些「header」在這些請求的資料上,讓 SSL 可以識別他們。

HTTP_X_REAL_IP:顯示 Cloudflare DNS IP 位置。
HTTP_CF_CONNECTING_IP:顯示實際的 IP 位置。
HTTP_X_FORWARDED_FOR:顯示「127.0.0.1」、實際的 IP 位置以及 Cloudflare DNS IP 位置。

「access_log」和「error_log」就不用講了,就是指成功和失敗的紀錄,所以如果伺服器遇到錯誤,可以去這裡查查看到底出了什麼事情,會有比較詳細的說明。

而最後「fastcgi」的部分也不可以省略,為了要執行 PHP 溝通的緣故,必須透過「FastCGI」通道跟「PHP-FPM」提出請求。

另外關於 Brotli 的部分,如果沒有安裝就不要把這部分的設定寫進去。他的功能其實跟 Gzip 一樣,會幫助壓縮 HTML, CSS 和 JavaScript 檔案。注意 brotli 只有在 Https 連線時才會出現效果。然後,我們會習慣在 gzip 後面加上 brotli 的設定,兩者是可以同時存在的。

另外是他的設定參數說明。

「brotli_comp_level」是設定其壓縮程度,數值從 0 至 11,預設會是 6。
「brotli_window」是設定 Brotli windows size。有這些可以用:1k, 2k, 4k, 8k, 16k, 32k, 64k, 128k, 256k, 512k, 1m, 2m, 4m, 8m 和 16m。
「brotli_buffers」是讓 buffers 有一定的大小並控制其數量,這影響網站連線的速率極為重要。預設大小是 32 4k|16 8k.
「brotli_min_length」是設定讓至少有多少的資料長度才會進行壓縮。

使用 remoteip 模組

為了解決 Apache 無法透過 Nginx 獲取真實訪客的 ip 位置的緣故,必須透過 remoteip 來解決這個問題。
但這個方式是給安裝 Apache 2.4 以上版本的人使用。
在 Apache 2.4 當中,remoteip 模組已經安裝完成,不需額外安裝,只差設定上要做一點修正。

STEP 1

首先,請編輯「apache2.conf」檔案裡面的一行。

sudo nano /etc/apache2/apache2.conf

STEP 2

把以下這幾行加入「%a」變數。

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%a %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common

變成

LogFormat "%v:%p %h %a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %a %l %u %t \"%r\" %>s %O" common

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

STEP 3

接著要為 remoteip 建立一個設定檔案就大功告成。

sudo tee /etc/apache2/mods-available/remoteip.conf <<EOF
<IfModule remoteip_module>
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
</IfModule>
EOF

STEP 4

最後記得啟用 remoteip 模組,並重新啟動 Apache。

sudo a2enmod remoteip
sudo service apache2 restart

安裝並設定 Varnish 6

STEP 1

終於來到最後一關了,先下這行指令安裝 Varnish。

sudo apt-get install varnish -y

STEP 2

接著我們要編輯 Varnish 的設定檔案,要把他的 port 改成 80。

sudo nano /lib/systemd/system/varnish.service

STEP 3

檔案打開後,把以下這行裡面的 6081 port

ExecStart=/usr/sbin/varnishd -a :6081 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m

改成 port 80,並加上「-p feature=+http2」。

ExecStart=/usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,2048m -p feature=+http2

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

STEP 4

接著請編輯「/etc/default/varnish」這個檔案。

sudo nano /etc/default/varnish

首先確認是否有設定打開系統時自動啟動 Varnish。

# Should we start varnishd at boot?  Set to "no" to disable.
START=yes

檔案打開後,一樣把以下這行裡面的 6081 port

DAEMON_OPTS="-a :6081 \

改成 port 80,並在下一行加入「-p feature=+http2 \」

DAEMON_OPTS="-a :80 \
             -p feature=+http2 \

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。

STEP 5

最後要編輯 Varnish 的設定檔案,這裡會稍微複雜一點。
我們直接新建一個設定檔案會比較快,所以這裡先把預設的檔案給備份再刪除。

sudo cp /etc/varnish/default.vcl /etc/varnish/default.vclbak
sudo rm -R /etc/varnish/default.vcl
sudo nano /etc/varnish/default.vcl

打開新檔案之後,請輸入以下的內容。

注意,第一行的「vcl 4.0;」必須存在。從 Varnish 4.0 之後,設定檔案的寫法有所改變,因此必須先寫出這個來表示區別。

而看到「backend default{}」的部分,裡面的「.host = “127.0.0.1”;」和「.port = “8080”;」要特別注意,這裡的 port 要指向 8080,是 Apache 使用的 port。

另外當中有一個很重要的部分,就是把 HTTP 指向 HTTPS。這個需要在「sub vcl_recv {}」和「sub vcl_synth {}」寫設定。

sub vcl_recv {
    if ( req.http.X-Forwarded-Proto !~ "(?i)https" ) {
        set req.http.x-Redir-Url = "https://" + req.http.host + req.url;
        return ( synth( 750 ));
    }
}

這是說當收到 HTTP 的請求時導向到「750」狀態。之後用 301 導向到 HTTPS。

sub vcl_synth {
    if (resp.status == 750) {
    set resp.status = 301;
    set resp.http.Location = req.http.x-redir;
    return(deliver);
    }
}

另外有一個設定很重要,當你的 Apache 出問題時,Varnish 還可以透過快取來幫你顯示內容,而暫時不會出現「503 error」等的錯誤頁面。
這裡寫的設定可以用這幾個單位,例如秒(s)、分鐘(m)、小時(h)和天(d)。這裡設定的意思是說,會保留一天的快取量,並且提供一小時的快取時間使用。

sub vcl_backend_response {
    set beresp.ttl = 24h;
    set beresp.grace = 1h;
}

話說有一個設定請不要寫,我自己的測試是會造成 WordPress 的後台無法登入,因為這個設定是把 Cookie 給清除掉的設定。

sub vcl_backend_response {
    if (bereq.url !~ "wp-admin|wp-login|product|cart|checkout|my-account|/?remove_item=") {
    	unset beresp.http.set-cookie;
    }
}

最後一個很重要的部分是不要快取的東西以及啟動清楚快取的啟動器。

sub vcl_recv {
    if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") {
      return (pass);
    }
}

而啟動清除快取的部分,必須同時要寫入「acl purge{}」、「sub vcl_recv {}」和「sub vcl_purge {}」這些設定。

acl purge {
  "localhost";
  "127.0.0.1";
}

import std;

sub vcl_recv {
    if (req.method == "PURGE") {
      if (req.method == "PURGE") {
        if (std.ip(req.http.x-real-ip, "0.0.0.0") ~ purge) {
          return (purge);
        } else {
          return (synth(403));
        }
      }
    }
}

sub vcl_purge {
    set req.method = "GET";
    set req.http.X-Purger = "Purged";
    return (restart);
}

編輯完成後請按「Control」+「X」,按「Y」,再按「Enter」完成編輯。
另外網路上可以找到許多人建立的設定範本,可以自己參考之後,修改成符合自己網站所需的,我把這些資料放在下面的參考資料區。

STEP 6

記得重新啟動 varnish 以套用新的設定。

sudo systemctl daemon-reload
sudo service apache2 stop
sudo a2dissite 000-default.conf
sudo a2ensite 000-default.conf
sudo service apache2 restart
sudo service varnish restart
sudo systemctl enable varnish

到這裡應該可以重新連線上網站了,因為 port 80 已經由 Varnish 接管,這時應該可以正常拜訪你的首頁。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

另外可以出入以下指令,觀看各樣的模組運作狀況。
為了清理掉快取,我們先重新啟動 Varnish。

sudo service varnish restart

接著在網站的跟目錄「/var/www/html」建立檔案。

sudo tee /var/www/html/index.php <<EOF
<?php phpinfo(); ?>
EOF

接著再次拜訪你的網站,應該可以看到這個東西。

wp-ssl-ubuntu-lamp-nginx-varnish-redis-6
作者ヤンヤン編輯於 2018 / 3 / 26

這裡你可以看到我們之前設定的 fastcgi 已經在運作。如果你是用加密連線 port 的值會顯示 443。

如何知道 Varnish 有正常運作
如果你疑惑 Varnish 到底有沒有正確的在運做,可以在終端機中嘗試這兩個指令。

varnishd -V
sudo varnishd -C -f /etc/varnish/default.vcl

另外有網站也可以幫你測試 Varnish 是否在工作

請參考:
1. Is Varnish working? Find out for sure! - Sponsored by Cadre - Simply Solid Web Hosting

下一個章節會介紹關於設定資料庫 MariaDB 的帳號密碼,並開始安裝 WordPress。

參考資料區:
把 Nginx 設為 reserve 的參考資料
1. How To Configure Nginx as a Reverse Proxy for Apache | DigitalOcean
2. How To Migrate from an Apache Web Server to Nginx on an Ubuntu VPS | DigitalOcean
3. How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 14.04 Droplet | DigitalOcean

Reserve Proxy 的參考資料
4. 反向代理 - 维基百科,自由的百科全书
5. XYZ的筆記本: nginx 設定反向代理伺服器
6. Reverse Proxy Server ( 反向代理伺服器 ) 是什麼 ?
7. NGINX+APACHE2+MySQL負載平衡與反向代理 | Hello Santa web design, drupal and more

關於安裝 Apache Nginx Varnish 在一起的概念文章
8. HTTPS Everywhere With Nginx, Varnish And Apache — Smashing Magazine
9. How To Install Linux, Nginx, MySQL, PHP (LEMP stack) in Ubuntu 16.04 | DigitalOcean
10. How To Install Nginx on Ubuntu 16.04 | DigitalOcean
安裝 nginx 錯誤的話通常的問題所在
11. Error When Installing Nginx on Ubuntu 16.04 - Ask Ubuntu

若想要 SSL 連線
12. Fix Varnish Mixed Content Errors + CloudFlare Flexible SSL + WordPress
13. Varnish, CloudFlare and Apache: Real Client IP - Knowledgebase - Bitronic Technologies

Nginx 設定詳細教學
14. Strong SSL Security on nginx - Raymii.org
15. 本博客 Nginx 配置之安全篇 | JerryQu 的小站

Diffie-Hellman parameter
16. 用 nginx 建置一個 A+ 等級的 https 網頁伺服器 | Peter Dave Hello's Blog

Nginx 設定範例檔案:
17. Best nginx configuration for improved security(and performance). Complete blog post here http://tautt.com/best-nginx-configuration-for-security/ · GitHub
18. Getting Started with NGINX - Part 4: TLS Deployment Best Practices
19. Nginx 配置 HTTPS 服务器 | Aotu.io「凹凸实验室」
20. Nginx/nginx-log-logrotate.conf at master · KJieGitHub/Nginx
21. docker-nginx/nginx.conf at master · liudanking/docker-nginx

Nginx 1.14 對 TLSv1.3 的支援
22. Using TLS1.3 With OpenSSL - OpenSSL Blog
23. 本博客开始支持 TLS 1.3 | JerryQu 的小站
24. http2 | 行思錄 | Travel Coder
25. 从源代码编译 nginx docker 镜像开启 TLS 1.3
26. 让Nginx快速支持TLS1.3协议 - 简书
27. 初探nginx+TLS 1.3 | Canary Workshop | Whatever is worth doing at all is worth doing well
28. 本博客开始支持 TLS 1.3 | JerryQu 的小站
29. How to setup Let's Encrypt for Nginx on Ubuntu 18.04 (including IPv6, HTTP/2 and A+ SSL rating)
重點是 openssl 要 1.1.1 alpha 版以上才行、Nginx 要 1.13.0 以上才行

Nginx 上增加 brotli module
30. Nginx/nginx-script/nginx-startup at master · KJieGitHub/Nginx
31. Brotli support | Howtoforge - Linux Howtos and Tutorials
32. 本博客开始支持 TLS 1.3 | JerryQu 的小站
33. Using TLS1.3 With OpenSSL - OpenSSL Blog
34. Nginx 的编译安装 - DCC 的小窝
35. CertSimple | 'You can't use Brotli for dynamic content'
36. Nginx with Brotli on Debian Stretch – Stefan Wintermeyer – Medium
37. Install Brotli Compression on Nginx - Step by step tutorial
38. Improve your HTTP compression using Brotli
39. Serving up Brotli with Nginx (and Automating it with Jekyll) | A Faster Web
40. Debian/Ubuntu 環境下自行編譯及安裝 Nginx 網頁伺服器 | PcSetting Blog
41. How to enable Brotli with Rails and Nginx · hansottowirtz/sprockets-exporters_pack Wiki
目前發現 brotli module 要編譯安裝時才弄得進去
42. How to enable Brotli with Rails and Nginx · hansottowirtz/sprockets-exporters_pack Wiki
43. How to Build NGINX from source on Ubuntu 18.04 LTS
44. NGINX Docs | Installing NGINX Open Source

SSL chiphers 清單
45. Open SSL Ciphers
46. Logjam: PFS Deployment Guide

設置 Fastcgi
47. Fix Varnish Mixed Content Errors + CloudFlare Flexible SSL + WordPress
48. PHP-FPM: Configuration the Listen Directive | Servers for Hackers
49. php - Where is php7.0-fpm.sock located - Stack Overflow
50. php - NGINX: connect() to unix:/var/run/php7.2-fpm.sock failed (2: No such file or directory) - Stack Overflow
51. Install PHP7.2 NGINX and PHP7.2-FPM on Ubuntu 16.04

讓 Apache 切換到使用 php-fpm 的四種方式
52. Apache httpd 2.4.x 使用 mod_proxy_fcgi 和 PHP-FPM 的方式 | 水景一页
53. mod_proxy_fcgi - Apache HTTP Server Version 2.4
建議使用 SetHandler 的方式

詳細 Apache 切換到使用 php-fpm 設置教學
54. Using PHP-FPM with Apache on Ubuntu 16.04
55. Ubuntu 16.04 LTS : Apache2 : PHP + PHP-FPM : Server World
56. Ubuntu 16.04 Web Server with Apache, PHP, and MySQL
57. Setup PHP-FPM for Apache2 / Nginx on Ubuntu 17.04 / 17.10 – Website for Students
58. How to Run Apache2 with PHP7.2-FPM on Ubuntu 16.04 / 17.10 / 18.04 – Website for Students

Apache 切換到使用 php-fpm 設置教學,但是我認為他有寫錯
59. Install Apache, MariaDB and PHP7 (LAMP Stack) on Ubuntu 16.04 LTS

需要關閉 php7.2 module、要卡開 proxy proxy_fcgi module
60. Switching Apache2 to php-fpm for performance – rojtberg.net

因為 libapache2-mod-fastcgi 已經被移除的關係,所以PHP 無法執行
61. apache2 - PHP 7.2 fastcgi doesn't work on Ubuntu 18.04 server - Ask Ubuntu

比較  mod_fastcgi 和 mod_proxy_fcgi 的差別
62. apache 2.4 - Differences between mod_fastcgi and mod_proxy_fcgi - Server Fault

Apache 切換到使用 php-fpm 設置變簡單的演化史
63. Ubuntu 14.04 の Apache mod_proxy_fcgi で php 動かすのは厳しい話 - 誰かの役に立てばいいブログ

安裝 apache 和 mariadb 的參考資料
64. 如何在Ubuntu 14.04与SSL终止配置Varnish缓存4.0
65. LAMP Web Server 網頁伺服器快速建置入門,Peter Dave Hello's Blog,2016 / 3 / 1
66. 如何安装WordPress 4.6在Ubuntu 16.04使用LAMP
67. How to Setup Magento 2 With Varnish and Apache on Ubuntu 16.04
68. Debian / Ubuntu 安裝 Mariadb 10.1,Linux 技術手札,2016 / 4 / 2
69. 安装 WordPress with LAMP on Ubuntu Server – Binarization
70. Ubuntu 16.04 安裝 Apache2 + mod_fcgid + mpm_worker 跑 php 7.x | Mr
71. How to Change Apache, FTP, and SSH default port to a custom port – Part 1,ostechnix,2016 / 2 / 22
72. How To Install Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu 16.04 | DigitalOcean

關於更改 port 的參考資料
73. How to open a specific port such as 9090 in Google Compute Engine - Stack Overflow

關於 Fastcgi、php-fpm、mpm worker 的參考資料
74. 在Ubuntu 16.04上使用PHP-FPM和Apache
75. Apache 2.4 + PHP 7.1 + PHP-FPM install | Calos's Blog
76. How to install PHP 7.0 (PHP-FPM) on Ubuntu 16.04 LTS..
77. php - php7.0-fpm not working with apache2.4 on Ubuntu-16.04 - Server Fault
78. Run PHP7-FPM with Apache mpm_event on Ubuntu 16.04 | antrecu
79. Ubuntu 16.04 安裝 Apache2 + mod_fcgid + mpm_worker 跑 php 7.x | Mr
80. Ubuntu 16.04 安裝 Apache2.4 + mpm_worker + fastcgi + php7.0 | Mr
81. How to Install and Configure PHP 7.0 or PHP 7.1 on Ubuntu 16.04 - Vultr.com
82. php fpm - Trying to confirm is php7.0-fpm is working with apache on Ubuntu 16.04 - Server Fault
83. server - Configuring Apache 2.4 with FastCGI on Ubuntu 16.04 - What do I do with php7.0-fpm.conf? - Ask Ubuntu
84. Nginx + PHP CGI的一个可能的安全漏洞 | 风雪之隅

關於 Apache remoteip 模組的參考資料
85. Replace mod_rpaf with mod_remoteip after upgrading Apache from 2.2 to 2.4 – #!/bin/blog
86. Apache 2.4 mod_remoteip | Somsip Blog
87. Apache2 2.4+ not logging remote IP address using mod_remoteip | trick77.com
88. Apache通过mod_remoteip模块获取客户端IP地址 – 123admin
89. Replacing mod_rpaf with mod_remoteip in apache 2.4 Nginx Real_IP Problem Solution,Syslint,2013 / 1 / 10
90. 前端Nginx,后端Apache获取用户真实IP地址 | Linux运维笔记
91. [Apache] 用 mod_rpaf 來記錄 X-Forwarded-For IP - KnucklesNote板 - Disp BBS
92. Apache Module mod_remoteip,Apache,n.d.
93. load balancing - Apache mod_remoteip and access logs - Server Fault

關於 Apache rpaf 模組的參考資料
94. Juszeil Conception  BLOG 部落格 - Apache2 - mod-rpaf (X-Forwarded-For)
95. 如何设置nginx作为反向代理Apache2在Ubuntu 12.04
96. mod_rpaf (X-Forwarded-For) | 夢想家
97. Wrong hint for installing missing apache2 dependencies on Ubuntu 16.04 · Issue #1884 · phusion/passenger · GitHub
98. GitHub - gnif/mod_rpaf: reverse proxy add forward module for Apache
99. How to obtain the clients IP on the Apache Webserver :: X4B

此篇只說明 Apache 和 Varnish 的關聯,重點只放在 Varnish 的設定
100. Speed Up WordPress Using Redis And Varnish On Ubuntu | Unixmen

關於 libapache2-mod-fastcgi 不再套件庫名單的解決方式
101. How to Run Apache2 with PHP7.2-FPM on Ubuntu 16.04 / 17.10 / 18.04 – Website for Students
102. apt - 'libapache2-mod-fastcgi' has no installation candidate on Ubuntu 17.04 - Ask Ubuntu

此篇說明 Nginx 和 Apache 並存,Nginx 作為前端主機,Apache 作為反向代理伺服器
注意到關於 proxy_pass 的意義,其 Port 就是 Apache 的 port
103. How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 16.04 Server | DigitalOcean
104. WordPress admin, SSL, Apache + nginx – u wot?
105. Ubuntu 設定 Nginx 作為 Apache 的 Reverse Proxy Server
106. Reverse Proxy Server ( 反向代理伺服器 ) 是什麼 ?

因為把 Nginx 作為反向代理伺服器,要如何和 CloudFlare 結合
107. How to setup SSL for WordPress on a VPS (Nginx + CloudFlare + WordPress)

把 Nginx 和 Varnish 做結合了,並且使用 SSL 連線
108. Varnish, Nginx with SSL install under Ubuntu 16.04 | Konkretor Blog, IT Stuff and more
109. Use Varnish & NGINX to Serve WordPress over SSL & HTTP on Debian 8
110. HTTPS with Varnish | Konstantin Komelin
111. How To Configure Varnish Cache 4.0 with SSL Termination on Ubuntu 14.04 | DigitalOcean

把 Apache Nginx Varnish 合再一起
112. HTTPS Everywhere With Nginx, Varnish And Apache — Smashing Magazine
113. [Config] CLOUDFLARE + VARNISH + APACHE + NGINX | chevereto

把 Nginx 和 MariaDB 資料庫結合再一起
114. Install WordPress with Nginx and Memcached Support on Ubuntu 17.04 / 17.10 – Website for Students

單純說明 Varnish 是什麼
115. Varnish – Speed Up Your Mobile Website — Smashing Magazine

Varnish 已經預設加入 load balance
116. Varnish automagically adding load balancer IP to X-Forwarded-For header - Stack Overflow

在 Ubuntu 上面安裝 Varnish
117. Install Varnish Cache 5.1 for Apache on Debian 9 / Ubuntu 16.04
118. Install Varnish Cache 5.1 for Apache on Debian 9 / Ubuntu 16.04
119. Google Cloud Platform雲端主機!自架VARNISH快取主機,讓WordPress載入速度快10倍|梅問題.教學網

Varnish 範本
120. Varnish VCL for WP and W3 Total Cache  · GitHub
121. Example Varnish VCL Configuration e.g
122. varnish-4.0-configuration-templates/default.vcl at master · mattiasgeniar/varnish-4.0-configuration-templates · GitHub
123. 通过 Varnish 使 WordPress 静态化 | Leona+
124. 透過 Varnish 讓 WordPress 速度起飛 - 是阿不解釋
125. How to Put Varnish Cache on Your WordPress Site | pair Networks Blog
https://github.com/varnish/hitch/wiki/FAQ

Varnish purger 的設計
126. Purge and proxies, a love-hate affair
127. Purging and banning — Varnish version trunk documentation

PHP 7.2 的安裝
128. How to install PHP (7 or 7.2) on Ubuntu,ThisHosting.Rocks,2018 / 2 / 23
129. Ubuntu 18.04 (Bionic Beaver) LTS version ships with PHP 7.2

HTTP 1 和 1.1 以及 2 的差別
130. What is HTTP/2 and how do I enable it on WordPress? (2018) - CollectiveRay
131. WordPress and HTTP2: All Your Questions Answered - WPMU DEV
132. HTTP2.0的奇妙日常 | AlloyTeam
133. HTTP,HTTP2.0,SPDY,HTTPS你应该知道的一些事 | AlloyTeam

Openssl 必須要版本 1.0.2 以上才會支援 HTTP/2
134. Nginx上部署HTTPS + HTTP2-博客-云栖社区-阿里云 
135. Ubuntu Manpage:version - print OpenSSL version information

Nginx 啟用 HTTP/2,Nginx 的版本至少 1.9.5 以上
注意,只有使用 443 port 的 https 加密連線才能設定 HTTP/2
136. The HTTP/2 Module in NGINX
137. 或许是 Nginx 上配置 HTTP2 最实在的教程了-博客-云栖社区-阿里云 
138. Enable HTTP/2 on Nginx
139. 在 nginx 中啟用 HTTP/2 並提高 HTTPS 安全性與效能 | 老洪的 IT 學習系統
140. Introducing HTTP/2 Server Push with NGINX 1.13.9 | NGINX
141. How To Set Up Nginx with HTTP/2 Support – Grigor Khachatryan – Medium
142. How To Set Up Nginx with HTTP/2 Support on Ubuntu 16.04 | DigitalOcean
143. How to enable HTTP/2 support in NGINX - HTTP2.Pro
144. How to Enable HTTP/2 in Nginx on Ubuntu and CentOS | RoseHosting Blog
145. Configuring NGINX with SSL and HTTP/2 — Mattermost 4.10 documentation

關於 Content-Security-Policy
146. Content Security Policy (CSP) - HTTP | MDN
147. Content Security Policy CSP Reference & Examples
148. Content-Security-Policy - HTTP Headers 的資安議題 (2) | DEVCORE 戴夫寇爾

關於 HSTS
149. HTTP Strict Transport Security (HSTS) and NGINX - NGINX

設定 Varnish 5 支援 HTTP/2
150. How it's made: Varnish 5.0 and http/2
151. How to get started with Varnish Cache 5.0 with experimental HTTP/2 support

Varnish 有兩個地方要修改才會啟用 HTTP/2 的功能:varnish.service、varnish 這兩個檔案
152. HTTP/2 SSL Offloading with Hitch and Varnish • ISPIRE.ME
153. ブログ - Hitch 1.4とVarnish 5.2でHTTP/2なMagento環境を作る | Magentoと越境ECの総合サポート Principleworks
154. この blog を nginx + varnish で SSL + http/2 に対応した件

設定 Nginx 與 Varnish 並包含 HTTP/2
155. How to Configure HTTP/2 with Varnish Using Nginx :: 4devs - blog from developers for developers.
156. 使用Nginx来让Varnish支持HTTP/2 – Byte Overflow
157. Configure SSL Termination with Varnish Caching and HTTP/2 - Jeremy Pyne
158. HTTP/2 SSL Offloading with Hitch and Varnish • ISPIRE.ME

關於 Apache 2.4、Nginx 基礎防止 DDOS、網頁爬蟲等的問題
159. Apache Bad Bot and User-Agent Blocker, Spam Referrer Blocker, Bad IP Blocker and WordPress Theme Detector Blocker | The Ultimate Bad Bot, User-Agent and Spam Referrer Blocker for Apache Web Servers
160. Nginx Bad Bot and User-Agent Blocker, Spam Referrer Blocker, Anti DDOS, Bad IP Blocker and WordPress Theme Detector Blocker

關於 PHP 的安全性問題
161. Linux: 25 PHP Security Best Practices For Sys Admins - nixCraft
162. 15 Best Security Tips for LAMP Stack (Apache, MySQL and PHP) on Linux

頁首圖片版權
163. Designed by Freepik