天天看點

Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite

靜态資源web服務

Nginx作為儲存靜态資源的web服務,對靜态資源直接做出響應。減少後端伺服器的負載壓力。

基礎配置

配置實踐

# 先把上一節的配置備份下來
cd /etc/nginx/conf.d
mv auth_basic.conf auth_basic.conf.bak
# 從備份目錄恢複一個初始配置并改名
cp /opt/backup/default.conf static.conf
# 修改配置
vi static.conf
           
# 配置如下
server {
    ...
    
    # 開啟sendfile,提高網絡包的傳輸效率
    sendfile on;
    
    # 配置圖檔資源的路徑
    location ~ .*\.(jpg|gif|png)$ {
        root /opt/app/code/images;
    }

    # 配置txt|xml資源的路徑
    location ~ .*\.(txt|xml)$ {
        root /opt/app/code/doc;
    }
    # 配置html網頁資源路徑
    location ~ .*\.(html|htm)$ {
        root /opt/app/code;
    }

}
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 重載配置
systemctl reload nginx.service
           
# 我們準備了一個圖檔資源
[[email protected] conf.d]# cd /opt/app/code/images
[[email protected] images]# ls
react.jpg
           

驗證結果

Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite

開啟壓縮

開啟壓縮,可以加快資源響應速度,同時節省網絡帶寬資源。

配置實踐

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
           
# 配置如下
server {
    ...
    
    #開啟sendfile,提高網絡包的傳輸效率
    sendfile on;
    
    #配置圖檔資源的路徑
    location ~ .*\.(jpg|gif|png)$ {
        #開啟壓縮
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types image/jpeg image/gif image/png;
        root /opt/app/code/images;
    }

    #配置txt|xml資源的路徑
    location ~ .*\.(txt|xml)$ {
        #開啟壓縮
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 1;
        gzip_types text/plain application/xml;
        root /opt/app/code/doc;
    }
    # 配置html網頁資源路徑
    location ~ .*\.(html|htm)$ {
        root /opt/app/code;
    }

}
           
# 驗證配置,先不重載配置
nginx -tc /etc/nginx/nginx.conf
           

相比圖檔,用檔案來示範壓縮,壓縮效果會更好:

cd /opt/app/code/doc
# 直接把nginx通路日志拷貝到靜态資源目錄
cp /var/log/nginx/access.log access.txt
chmod 777 access.txt
           

在重載配置之前,我們先通路一次http://39.104.93.171/access.txt

# access.log輸出如下:
39.104.93.171 115.198.157.60 - admin [03/Feb/2018:21:51:23 +0800] "GET /access.txt HTTP/1.1" 200 20626 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
           

可以看到傳輸内容大小是20626。

# 然後我們重載配置
systemctl reload nginx.service
           

浏覽器清空緩存(避免304影響)後再次通路http://39.104.93.171/access.txt

# access.log輸出如下:
39.104.93.171 115.198.157.60 - admin [03/Feb/2018:21:58:56 +0800] "GET /access.txt HTTP/1.1" 200 1895 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
           

可以看到傳輸資料大小已經被壓縮到隻有1895了。

跨域通路

浏覽器基于安全考慮,采用同源政策,限制了跨域通路。然而企業内部站點之間通常會有跨域通路的需求。尤其是現在前後端分離的方式,前端采用諸如React或Vue等MVVM架構開發純Ajax的SPA應用時,頁面間的路由是前端控制,前端同學往往要求相關伺服器開放跨域通路。

我準備了另外一台伺服器:39.104.116.91,有如下頁面,通過ajax跨域請求本nginx伺服器的html資源:

<!DOCTYPE HTML>
<html >
<head>
    <title>測試ajax跨域通路</title>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
    <script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>
    $(document).ready(function(){
        $.ajax({
            type: "GET",
            url: "http://39.104.93.171/someone.html",
            success: function(data) {
                alert("跨域通路成功!");
            },
            error: function(data) {
                alert("跨域通路失敗!");
            }
        });
    });
</script>
</head>
<body>測試跨域通路</body>
</html>
           

那麼,我們要在目前nginx伺服器上,配置允許39.104.116.91的跨域通路。

配置參考

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
           
# 配置如下
server {
    ...
    
    #開啟sendfile,提高網絡包的傳輸效率
    sendfile on;
    
    #配置圖檔資源的路徑
    location ~ .*\.(jpg|gif|png)$ {
        #開啟壓縮
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types image/jpeg image/gif image/png;
        root /opt/app/code/images;
    }

    #配置txt|xml資源的路徑
    location ~ .*\.(txt|xml)$ {
        #開啟壓縮
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 1;
        gzip_types text/plain application/xml;
        root /opt/app/code/doc;
    }
    # 配置html網頁資源路徑
    location ~ .*\.(html|htm)$ {
        #允許http://39.104.116.91跨域通路
        add_header Access-Control-Allow-Origin http://39.104.116.91;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        root /opt/app/code;
    }

}
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 重載配置
systemctl reload nginx.service
           

防盜鍊

防盜鍊,簡單來說就是你可以直接通路該資源,但是不能将我的資源連結放到你自己的伺服器上讓别人通路,尤其是圖檔或視訊這種比較大的檔案,容易導緻伺服器響應很慢,并且影響帶寬。

配置實踐

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
           
# 配置如下
server {
    ...
    
    #開啟sendfile,提高網絡包的傳輸效率
    sendfile on;
    
    #配置圖檔資源的路徑
    location ~ .*\.(jpg|gif|png)$ {
        #開啟壓縮
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types image/jpeg image/gif image/png;
        # 防盜鍊
        valid_referers none blocked *.zhutx.com server_names ~\.google\. ~\.baidu\.;
        if ($invalid_referer) {
            return 403;
        }
        root /opt/app/code/images;
    }

    ...

}
           

valid_referers指定了合法的來源'referer', 他決定了内置變量$invalid_referer的值。

valid_referers文法

valid_referers none | blocked | server_names | string ...;
           
參數 說明
none “Referer” 來源頭部為空的情況
blocked “Referer”來源頭部不為空,但是裡面的值被代理或者防火牆删除了,這些值都不以http://或者https://開頭
server_names “Referer”來源頭部包含目前的server_names(目前域名)
arbitrary string 任意字元串,定義伺服器名或者可選的URI字首。主機名可以使用*開頭或者結尾,在檢測來源頭部這個過程中,來源域名中的主機端口将會被忽略掉
regular expression 正規表達式

是以,我們的防盜鍊配置,在以下情況下可以合法通路圖檔:

  1. 直接在浏覽器輸入你的圖檔位址。符合none這個規則;
  2. 來自*.zhutx.com的通路;
  3. 來自谷歌和百度的通路(SEO優化);

如果不合法,那麼$invalid_referer等于1,會在if語句中傳回一個403給使用者。

網頁緩存

配置實踐

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
           
# 配置如下
server {
    ...
    
    location ~ .*\.(html|htm)$ {
        # 協商用戶端,應答時維護Cache-Control和Expires頭資訊
        expires 24h;
        add_header Access-Control-Allow-Origin http://39.104.116.91;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        root /opt/app/code;
    }

    ...

}
           

代理服務

正向代理

正向代理即用戶端代理。用戶端通過主動設定代理服務,進而将對目标的通路委托給有權通路的代理伺服器去通路。翻牆就是這種場景。

Nginx可以做正向代理伺服器

配置參考

# 先将上節内容備份下來
cd /etc/nginx/conf.d
mv static.conf static.conf.bak
# 從備份目錄恢複初始配置并改名
cp /opt/backup/default.conf zx_proxy.conf
# 修改配置
vi zx_proxy.conf
           
# 配置如下
server {
    ...
    # 可能會涉及到DNS域名解析
    resolver 8.8.8.8;
    location / {
        # 原封不動的讓自己轉發用戶端的請求
        proxy_pass http://$http_host$request_uri;
    }
}
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 重載配置
systemctl reload nginx.service
           

驗證結果

我的chrome浏覽器,安裝了SwitchySharp插件,配置Nginx代理如下:

Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite

接下來我通路了http://www.ttlsa.com/

通路正常,觀察Nginx的access.log的輸出日志:

www.ttlsa.com 115.198.157.60 - - [04/Feb/2018:11:13:40 +0800] "GET http://www.ttlsa.com/ HTTP/1.1" 200 18758 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
           

可見,我們對目标網站的通路,已經由Nginx代理了。

反向代理

反向代理即服務端代理。對用戶端隐藏真實伺服器位址。

配置參考

# 先把之前的配置備份下來
cd /etc/nginx/conf.d
mv zx_proxy.conf zx_proxy.conf.bak
# 從備份目錄恢複一個原始配置并改名
cp /opt/backup/default.conf fx_proxy.conf
# 編輯配置
vi fx_proxy.conf
           
# 配置如下
#我們增加這個server,端口8080,充當示範Real Server
server {
    listen 8080;
    server_name localhost;

    location / {
        root /opt/app/code;
    }
}
server {
    location / {
        #把請求代理到本機8080端口
        proxy_pass http://127.0.0.1:8080;
        #引入代理相關通用配置
        include proxy_params;
    }
}
           
# 其他代理通用配置獨立出去,友善複用
vi /etc/nginx/proxy_params
           
# default就可以了。除非傳回301的場景,可能需要改寫
proxy_redirect defalut;

#配置header資訊,讓Real Server了解實際用戶端資訊
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;

#一些代理逾時設定
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

#代理緩沖區設定
proxy_buffer_size 32k;
proxy_buffering on;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 由于這次增加了一個server端口要啟動,是以重新開機nginx服務
systemctl restart nginx.service
           
# 驗證8080端口已啟動
netstat -lnp | grep 8080
           
# 顯示如下
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      22091/nginx: master
           

驗證結果

# 建立反向代理結果示範頁面
cd /opt/app/code
vi test_fx_proxy.conf
           
<!DOCTYPE HTML>
<html >
<head>
    <title>反向代理測試</title>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
</head>
<body>反向代理通路成功了</body>
</html>
           

然後通路:

Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite

以下是本次通路的access.log輸出:

39.104.93.171 127.0.0.1 - - [04/Feb/2018:11:37:12 +0800] "GET /test_fx_proxy.html HTTP/1.0" 200 235 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
39.104.93.171 115.198.157.60 - - [04/Feb/2018:11:37:12 +0800] "GET /test_fx_proxy.html HTTP/1.1" 200 235 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
           

可以看到2次請求,先是80端口的server收到使用者請求,經反向代理後,Real Server收到了這個請求。

代理WebSocket的配置

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server 127.0.0.1:8010;
}

server {
    listen 8020;
    access_log /var/log/nginx/test_websocket.access.log main;
    location / {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}
           

負載均衡服務

負載均衡技術可讓多個後端伺服器共同分擔請求壓力,解決大量并發通路服務問題。

參考配置

# 先備份反向代理配置
cd /etc/nginx/conf.d
mv fx_proxy.conf fx_proxy.conf.bak
# 從備份目錄恢複一個初始配置并改名
cp /opt/backup/default.conf load_balance.conf
# 修改配置
vi load_balance.conf
           
#配置如下
server{
    listen 8001;
    server_name localhost;

    location / {
        root /opt/app/code/server_8001;
    }
}

server{
    listen 8002;
    server_name localhost;

    location / {
        root /opt/app/code/server_8002;
    }
}

server{
    listen 8003;
    server_name localhost;

    location / {
        root /opt/app/code/server_8003;
    }
}

server{
    listen 8004;
    server_name localhost;

    location / {
        root /opt/app/code/server_8004;
    }
}
upstream backend {
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004 backup;
}
server {
    ...
    location / {
        # 代理到upstream組
        proxy_pass http://backend;
        include proxy_params;
    }
}
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 重載服務
systemctl reload nginx.service
           
# 可以看到4個端口都已就緒
[[email protected] conf.d]# netstat -lnp | grep 8001
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      22091/nginx: master
[[email protected] conf.d]# netstat -lnp | grep 8002
tcp        0      0 0.0.0.0:8002            0.0.0.0:*               LISTEN      22091/nginx: master
[[email protected] conf.d]# netstat -lnp | grep 8003
tcp        0      0 0.0.0.0:8003            0.0.0.0:*               LISTEN      22091/nginx: master
[[email protected] conf.d]# netstat -lnp | grep 8004
tcp        0      0 0.0.0.0:8004            0.0.0.0:*               LISTEN      22091/nginx: master
           

接下來我們按照4個server的配置,建立各自的測試結果頁面:

cd /opt/app/code
mkdir server_8001 server_8002 server_8003 server_8004
           
cd server_8001
vi test_load_balance.html
           
<!DOCTYPE HTML>
<html >
<head>
    <title>負載均衡測試頁</title>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
</head>
<body>my port is 8001</body>
</html>
           

同樣的建立其他3個test_load_balance.html,隻是顯示port不同。

驗證結果

我們嘗試多次請求http://39.104.93.171/test_loa...

結果始終處于下面兩個頁面之間變換:

Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite
Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite

我們DROP掉8001和8002

iptables -I INPUT -p tcp --dport 8001 -j DROP
iptables -I INPUT -p tcp --dport 8002 -j DROP
           

再嘗試多次請求http://39.104.93.171/test_loa...

這回頁面始終顯示:

Nginx筆記(三)場景應用靜态資源web服務代理服務負載均衡服務緩存服務大檔案分割請求安全連結校驗geoipHTTPS服務動靜分離rewrite

upstream的server參數

參數 說明
down 不參與負載均衡
backup 預留的備份伺服器。當沒有其他節點提供服務時,它才提供服務
max_fails 允許請求失敗的次數
fail_timeout 經過max_fails失敗後,服務暫停的時間
max_conns 限制最大接收的連接配接數

上面示範時,8003是指定了down,實驗結果也驗證了它沒參與負載均衡。8004指定了backup,我們用iptables指令DROP了8001和8002後,已沒有其他節點對外提供服務了,是以backup開始接收請求。

其他參數可以自行嘗試。

負載均衡排程算法

方式 說明
輪詢 按順序逐一配置設定給不同的後端伺服器
權重輪詢 weight值越大,配置設定到的幾率越大
ip_hash 同一IP固定通路同一個後端伺服器
least_conn 哪個連接配接數少就發哪個機器
url_hash 按url參數的hash結果來配置設定
hash關鍵數值 hash自定義的key
# 負載均衡算法-權重輪詢
upstream backend {
    server localhost:8001 weight=5;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004 backup;
}
           
# 負載均衡算法-最少連接配接數
upstream backend {
    least_conn;
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004;
}
           
# 負載均衡算法-IP HASH
upstream backend {
    ip_hash;
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004;
}
           
# 負載均衡算法-URL HASH
upstream backend {
    url_hash;
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004;
}
           

當配置負載均衡算法為IP HASH或URL HASH時,便不再接受backup的server,不然無法通過配置校驗。不過由于backup違背了算法本身,是以這也在情理之中。

緩存服務

我們大緻可以把緩存分為 用戶端緩存、代理緩存和服務端緩存3類。

Nginx作為緩存服務,可以減少後端伺服器的壓力,當再次去通路之前通路過的資料時,在nginx前端就能拿到。是代理緩存。

參考配置

# 備份之前的配置
cd /etc/nginx/conf.d
mv load_balance.conf load_balance.conf.bak
# 從備份目錄初始一份配置并改名
cp /opt/backup/default.conf cache.conf
# 修改配置
vi cache.conf
           
...

#定義用于存放緩存檔案的空間
#/opt/app/cache 緩存檔案存放目錄
#keys_zone=my_cache:10m,緩存空間命名為my_cache,10m大概可以存8萬個左右的緩存key了
#inactive=60m,超60分鐘沒有通路的緩存自動清理
proxy_cache_path /opt/app/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
    ...

    if ($request_uri ~ ^/(login|register|password)) {
        set $cookie_nocache 1;
    }

    location / {
        # 緩存
        proxy_cache my_cache;
        # 基于代理
        proxy_pass http://backend;
        # 緩存過期周期配置,傳回200 304狀态的,緩存12小時過期
        proxy_cache_valid 200 304 12h;
        # 其他的緩存10分鐘過期
        proxy_cache_valid any 10m;
        # 緩存key
        #proxy_cache_key $scheme$proxy_host$request_uri;
        proxy_cache_key $host$uri$is_args$args;
        #配置不緩存的請求
        proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
        proxy_no_cache $http_pragma $http_authorization;
        # 增加一個頭資訊給用戶端,表示緩存是否命中
        add_header Nginx-Cache "$upstream_cache_status";
        # 後端伺服器某一台傳回不正常,則代理到下一台
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        include proxy_params;
    }
}
           

清理緩存

方式一:rm -rf 清空緩存目錄。會清空所有緩存

方式二:第三方擴充子產品ngx_cache_purge,可以清理指定緩存

緩存命中分析

在上面緩存的配置中,我們添加了Nginx-Cache這個響應頭部資訊

add_header Nginx-Cache "$upstream_cache_status";
           

關于$upstream_cache_status,有如下幾個值:

狀态 意義
MISS 緩存未命中,請求被傳送到背景處理
HIT 緩存命中
EXPIRED 緩存過期,請求被傳送到背景處理
UPDATING 正在更新緩存,将使用舊的應答
STALE 後端得到過期的應答

是以,我們可以分析nginx通路日志,hit次數/總請求次數就是緩存命中率

# 修改log_format,輸出$upstream_cache_status
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '"$upstream_cache_status"';
           
# 用awk指令統計
awk '{if($NF=="\"HIT\""){hit++}}END{printf "%.2f",hit/NR}' /var/log/nginx/access.log
           

大檔案分割請求

ngx_http_slice_module子產品是一個分割請求轉換成子請求,每個傳回一定範圍内響應的濾波器。該過濾器提供了更有效的大響應緩存。

該子產品不是預設生成的,它應該使用--with-http_slice_module配置參數啟用。

如果你按Nginx筆記(一)Nginx安裝的方式安裝Nginx,那麼該子產品預設已經編譯進來。可以用nginx -V指令驗證。

配置示例

#定義用于存放緩存檔案的空間
#/opt/app/cache 緩存檔案存放目錄
#keys_zone=my_cache:10m,緩存空間命名為my_cache,10m大概可以存8萬個左右的緩存key了
#inactive=60m,超60分鐘沒有通路的緩存自動清理
proxy_cache_path /opt/app/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

location ~ \.apk$ {
    slice             5m;
    proxy_cache       my_cache;
    proxy_cache_key   $uri$is_args$args$slice_range;
    proxy_set_header  Range $slice_range;
    proxy_cache_valid 200 206 1h;
    proxy_pass        http://localhost:8999;
}
           

在這個例子中,響應被分割成5兆位元組的可緩存切片。

安全連結校驗

ngx_http_secure_link_module用于檢查請求連結的真僞,保護資源免受未經授權的通路

該子產品不是預設生成的,它應該使用--with-http_secure_link_module配置參數啟用。

如果你按Nginx筆記(一)Nginx安裝的方式安裝Nginx,那麼該子產品預設已經編譯進來。可以用nginx -V指令驗證。

實際應用中,如需要對下載下傳連結進行合法性校驗,過期校驗。

我們用shell腳本模拟服務端生成一個下載下傳連結:

vim md5url.sh
           

輸入以下内容

#!/bin/sh
#
download_file="/download/file.img"
expires=$(date -d "2019-02-12 00:00:00" +%s)
secret="123456"
# 我們用過期時間+下載下傳url,加上密鑰,生成md5。後面nginx配置的md5校驗規則亦如此
md5=$(echo -n "${expires}${download_file} ${secret}"|openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)

servername="116.62.156.235"
echo "${servername}${download_file}?md5=${md5}&expires=${expires}"
           

執行sh md5url.sh,生成連結如下:

116.62.156.235/download/file.img?md5=kD4hdQLA-psd_QzPSzyrdA&expires=1549900800

我們在/opt/app/code下事先放一個下載下傳檔案/download/file.img

nginx配置示例

server {
    listen 80;
    server_name localhost;
    root /opt/app/code;
    
    location / {
        # 提取請求參數md5和expires
        secure_link $arg_md5,$arg_expires;
        # secure_link_md5定義的表達式MD5哈希值與請求參數中提取的md5值比較
        secure_link_md5 "$secure_link_expires$uri 123456";
        # 如果md5不相同,則該$secure_link變量設定為空字元串
        if ($secure_link = "") {
            return 403;
        }
        # 如果md5相同,則檢查是否過期。如果已過期,則該$secure_link變量設定為0
        if ($secure_link = "0") {
            return 410;
        }
    }
}
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 重載服務
systemctl reload nginx.service
           

通路生成的連結,便成功下載下傳檔案。當修改請求md5值,或者過期通路,便會顯示403頁面

geoip

基于IP位址比對MaxMind GeoIP二進制檔案,讀取IP所在地域資訊,包括國家以及城市資訊

當需要為國内與國外使用者提供不同的通路界面,如國内使用者代理到簡體中文的位址,國外使用者代理到英文版位址;

再比如國内使用者,需要基于使用者所在城市提供本地化的服務,如通路58同城,網頁預設就處于這個城市版面;

這些都可以通過ngx_http_geoip_module子產品來實作。

該子產品不是預設生成的,它應該使用--with-http_geoip_module配置參數啟用

# 安裝nginx的geoip子產品
yum install nginx-module-geoip
# 檢視已安裝的庫
cd /etc/nginx/modules
ls
ngx_http_geoip_module-debug.so  ngx_http_geoip_module.so  ngx_stream_geoip_module-debug.so  ngx_stream_geoip_module.so

cd ..
# 非預設編譯進來的,是以load進來
           
vim nginx.conf
           
load_module "modules/ngx_http_geoip_module.so";
load_module "modules/ngx_stream_geoip_module.so";
           
mkdir geoip
cd geoip
下載下傳地域資訊
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoIP.dat.gz
gunzip GeoLiteCity.dat.gz
cd ../conf.d
           

nginx配置示例

vim test_geo.conf
           
geoip_country /etc/nginx/geoip/GeoIP.dat;
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
server {
    listen 80;
    server_name localhost;
    location / {
        if ($geoip_country_code != CN) {
            return 403;
        }
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
    location /myip {
        default_type text/plain;
        return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city";
    }
}
           
# 校驗配置
nginx -tc /etc/nginx/nginx.conf
# 重載服務
systemctl reload nginx.service
           

當通路/myip時,我們簡單顯示了下本地出口ip以及國家名稱,國家編碼,以及城市編号。

HTTPS服務

動靜分離

分離資源,減少不必要的請求消耗,減少請求延時。

參考配置

# 備份之前的配置
cd /etc/nginx/conf.d
mv cache.conf cache.conf.bak
# 從備份目錄初始一份配置并改名
cp /opt/backup/default.conf dynamic_static.conf
# 修改配置
vi dynamic_static.conf
           
# 配置如下
upstream java_api {
    #事先在本機啟動了tomcat負責接收jsp請求
    server 127.0.0.1:8080;
}

server {
    ...

    # 根目錄也可以配置在location外面
    root /opt/app/code;
    
    # 動态的請求代理給backend
    location ~ \.jsp$ {
        proxy_pass http://java_api;
        index index.html index.htm;
    }

    # 靜态請求自己處理
    location ~ \.(jpg|png|gif)$ {
        expires 1h;
        gzip on;
    }

    location / {
        index index.html index.htm
    }
}
           

rewrite

以下場景都可以使用到Nginx的rewrite功能:

  • URL重寫以适配後端的接口設計;
  • 網站更新時候,對于部分老使用者繼續提供老版本的服務;
  • 簡化前端url,友善SEO優化;
  • 維護時挂維護頁面;
  • 僞靜态,僞裝真實url。

參考配置

vi /etc/nginx/conf.d/default.conf
           
server {
    ...

    root /opt/app/code;
    
    location ~ ^/break {
        # 比對/break,尋到root目錄下的/test目錄去,如果沒有找到則404
        rewrite ^/break /test/ break;
    }

    location ~ ^/last {
        # 比對/last,内轉/test/請求
        rewrite ^/last /test/ last;
        # 302臨時重定向,讓用戶端浏覽器重新通路/test
        #rewrite ^/last /test/ redirect;
    }
    
    location ~ ^/imooc {
        # 臨時性重定向 302,
        #rewrite ^/imooc http://www.imooc.com/ permanent;
        # 永久性重定向 301,下次将不再經過nginx而直接跳轉目标
        rewrite ^/imooc http://www.imooc.com/ redirect;
    }

    location /test/ {
        default_type application/json;
        return 200 '{"status":"success"}'
    }

    location / {
        rewrite ^/course-(\d+)-(\d+)-(\d+)\.html$ /course/$1/$2/course_$3.html break;
        # 以Chrome浏覽器通路/nginx路徑,跳轉到慕課網nginx位址
        #if ($http_user_agent ~* Chrome) {
        #    rewrite ^/nginx http://conding.imooc.com/class/121.html break;
        #}
        
        # 不存在該檔案,則重定向到百度
        #if (!-f $request_filename) {
        #    rewrite ^/(.*)$ http://www.baidu.com/$1 redirect;
        #}
        
        index index.html index.htm
    }
}
           

rewrite規則優先級

  • 執行server塊的rewrite指令
  • 執行location比對
  • 執行標明的location中的rewrite

優雅的rewrite規則規則

server {
    listen 80;
    server_name www.nginx.org nginx.org;
    if ($http_host = nginx.org) {
        rewrite (.*) http://www.nginx.org$1;
    }
}
           

可以改成:

server {
    listen 80;
    server_name nginx.org;
    rewrite ^ http://www.nginx.org$request_uri?;
}
server {
    listen 80;
    server_name www.nginx.org;
}