Nginx是一個免費開源且穩定高效的Web伺服器程式,擁有反向代理以及負載平衡的功能,經常作為最前端的伺服器。當它用作反向代理伺服器或是PHP網頁伺服器時,無論是proxy_pass
還是fastcgi_pass
,均有提供快取的功能。然而,免費版本的Nginx並沒有內建刪除快取的機制(早期Nginx免費版本可以使用proxy_cache_purge
、fastcgi_cache_purge
命令來清除快取,只不過後來這功能要在商業版本上才能使用了),在沒有額外腳本或程式的幫助下,我們大概也只能用rm
等Linux指令來手動刪除快取目錄中的檔案,十分不方便,而且有一定的危險性。
如果您不知道如何在Ubuntu Server架設Nginx伺服器,也不知道怎麼使用proxy_pass
的快取功能的話,可以先參考這篇文章:
如果您是架設PHP網站的話,可以再參考這篇文章來了解fastcgi_pass
的快取功能:
Nginx Cache Purge
「Nginx Cache Purge」是一個高效Nginx快取清除工具,是解決免費版本的Nginx不能使用proxy_cache_purge
和fastcgi_cache_purge
命令的替代方案。
GitHub:
安裝和解除安裝Nginx Cache Purge
透過Cargo
如果系統環境中有安裝「Cargo」的話,可以直接使用以下指令來下載「Nginx Cache Purge」的原始碼專案,並進行編譯安裝。
cargo install nginx-cache-purge
若要解除安裝,執行以下這個指令即可:
cargo uninstall nginx-cache-purge
透過GitHub
(適用於Linux x86_64)
執行以下指令,將最新的Nginx Cache Purge執行檔從GitHub上下載下來,並移動到/usr/local/bin
目錄中。
curl -fL "$(curl -fsS https://api.github.com/repos/magiclen/nginx-cache-purge/releases/latest | sed -r -n 's/.*"browser_download_url": *"(.*\/nginx-cache-purge_'$(uname -m)')".*/\1/p')" -O && sudo mv nginx-cache-purge_$(uname -m) /usr/local/bin/nginx-cache-purge && sudo chmod +x /usr/local/bin/nginx-cache-purge
若要解除安裝,執行以下這個指令即可:
sudo rm /usr/local/bin/nginx-cache-purge
使用Nginx Cache Purge
命令列介面
Nginx Cache Purge有提供CLI(命令列介面),指令用法如下:
CACHE_PATH
是使用Nginx的proxy_cache_path
或是fastcgi_cache_path
命令時所設定的快取儲存目錄路徑。LEVELS
是使用Nginx的proxy_cache_path
或是fastcgi_cache_path
命令時所設定的目錄和目錄檔名結構,格式為x[:y[:z]]
。KEY
是使用Nginx的proxy_cache_key
或是fastcgi_cache_key
命令時所設定的快取鍵值。
建議把快取的鍵值以Nginx的$request_uri
為結尾,因為Nginx Cache Purge還有Wildcard清除功能。KEY
中可以使用星號*
來表示任意數量的任意字元。
如果想避開清除到某些快取,可以使用一個或多個-e
參數再加上要保留的快取的鍵值,同樣支援Wildcard匹配。
Nginx + Nginx Cache Purge
啟動Nginx Cache Purge服務
Nginx Cache Purge自帶HTTP服務,可以用來處理清除快取的請求。使用以下指令可以啟動該HTTP服務:
以上指令會使Nginx Cache Purge啟動自帶的HTTP服務,並監聽/tmp/nginx-cache-purge.sock
,這個是UDS (Unix Domain Socket)。
要讓Nginx Cache Purge的服務在Linux開機之後自動啟動,可以先參考以下這篇文章了解:
以下是參考用的Systemd Unit檔案和啟用指令:
[Unit]
Description=Nginx Cache Purge
After=network.target
[Service]
# same as the user/group of the nginx process
User=www-data
Group=www-data
ExecStart=/usr/local/bin/nginx-cache-purge start
Restart=always
RestartSec=3s
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl start nginx-cache-purge
sudo systemctl status nginx-cache-purge
sudo systemctl enable nginx-cache-purge
有了Nginx Cache Purge服務後,就可以在Nginx設定檔中將HTTP請求導給Nginx Cache Purge服務處理。我們在指定的location
區塊中,或是location
區塊內的if
區塊中,去呼叫Nginx Cache Purge的服務。
至於要在哪個location
區塊中或是if
區塊中去執行Nginx Cache Purge,其實也沒有一定的標準,大致上有兩種作法。
HTTP的PURGE
請求方法
在有使用到proxy_cache
或是fastcgi_cache
命令的區塊中,可以去判斷客戶端的請求方法是不是PURGE
。雖然PURGE
請求方法並不在HTTP標準中,但許多人會用它來當作清除快取的請求方法,有點約定俗成的感覺。
若要用這個方式來清除快取,可以在/etc/nginx/conf.d
目錄中,新增purge.conf
檔案,檔案內容如下:
map $request_method $is_purge {
default 0;
PURGE 1;
}
以上的map
命令,可以去判斷客戶端的請求方法是不是PURGE
,如果是的話,$is_purge
變數的值就是1
,否則是0
。
接著就是在location
區塊內使用if
命令判斷$is_purge
變數,並在if
區塊中使用content_by_lua_block
命令執行Lua腳本。假設Nginx Cache Purge的執行檔路徑是/usr/local/bin/nginx-cache-purge
,設定方式如下:
http {
...
map $request_method $is_purge {
default 0;
PURGE 1;
}
proxy_cache_path /tmp/cache levels=1:2 keys_zone=my_cache:10m;
proxy_cache_key $scheme$request_uri;
server {
...
location / {
if ($is_purge) {
set $my_cache_key $scheme$request_uri;
proxy_pass http://unix:/tmp/nginx-cache-purge.sock;
rewrite ^ /?cache_path=/tmp/cache&levels=1:2&key=$my_cache_key break;
}
proxy_cache my_cache;
proxy_pass upstream;
include proxy_params;
}
}
}
不過當然,我們還需要加入自己的存取驗證機制,避免隨便一個陌生人都可以連到我們的伺服器上清除快取。
以上的設定若成功,
- 發送
PURGE /path/to/abc
請求,表示要清除GET /path/to/abc
產生的快取。 - 發送
PURGE /path/to/*
請求,表示要清除GET /path/to/**/*
產生的快取,像是GET /path/to/
、GET /path/to/abc
、GET /path/to/123/456?a=bc
。 - 發送
PURGE /path/to/*/foo/*/bar
請求,表示要清除GET /path/to/**/foo/**/bar
產生的快取,像是GET /path/to/123/foo/456/bar
、GET /path/to/a/foo/b/c?e=bar
。
專門用來清除快取的location
區塊
如果不想把清除快取的功能和proxy_cache
或是fastcgi_cache
命令放在同一個location
區塊,並使用PURGE
請求方法來切換功能。也是可以另外再建立出location
區塊,設定一個專門用來清除快取的端點,不過快取鍵值中$request_uri
的部份就會需要在服務的請求查詢中加上remove_first
欄位來移除多出來的網址部件。
例如:
http {
...
proxy_cache_path /tmp/cache levels=1:2 keys_zone=my_cache:10m;
proxy_cache_key $scheme$request_uri;
server {
...
location / {
proxy_pass upstream;
include proxy_params;
}
location /purge/ {
set $my_cache_key $scheme$request_uri;
proxy_pass http://unix:/tmp/nginx-cache-purge.sock;
rewrite ^ /?cache_path=/tmp/cache&levels=1:2&remove_first=/purge&key=$my_cache_key break;
}
}
}
如果HTTP服務有清除到快取,就會回傳200
狀態碼;如果沒有要清除的快取,就會回傳202
狀態碼。
讓某些快取避免被清除
在服務的請求查詢中加上一個或多個exclude_keys
欄位,可以設定要排除的快取鍵值,同樣支援Wildcard匹配。
不要HTTP服務
我們可能會想要直接在Nginx中搭配lua-nginx-module
來呼叫Nginx Cache Purge的CLI介面。那麼我們可以在編譯Nginx Cache Purge時關閉其service
特色,以此得到更小的執行檔。
可以使用以下指令來安裝沒有自帶HTTP服務的Nginx Cache Purge: