Stories

Detail Return Return

Nginx使用手冊 - Stories Detail

由於格式和圖片解析問題,為了更好的體驗可前往 閲讀原文

Nginx(發音為 "engine-x")是一個高性能、開源的HTTP和反向代理服務器,也可以作為電子郵件(IMAP/POP3)代理服務器、以及通用的TCP/UDP代理服務器。它由俄羅斯的程序員Igor Sysoev創建於2002年,其目的是解決C10K問題(即可以同時處理10000個併發連接)。它採用異步非阻塞的事件驅動模型,可以處理成千上萬個併發連接,同時使用少量的CPU和內存資源。

本篇帶着大家一起領略nginx的常見使用技巧

掃碼關注公眾號,查看更多最新優質文章

優勢

  1. 高性能:Nginx具有高併發、低內存消耗以及高穩定性的特點,可以很好地應對大流量的訪問
  2. 高可擴展性:Nginx支持模塊化擴展,可以靈活增加新功能。用户可以根據自己的需求選擇相應的模塊,從而實現定製化的功能
  3. 高可靠性:Nginx具有故障自動恢復、熱部署等功能,能夠保證服務器在遇到問題時仍能繼續提供服務
  4. 反向代理與負載均衡:Nginx可以作為反向代理服務器,提供負載均衡功能。通過負載均衡,Nginx可以將請求分發到多個後端服務器,從而實現高可用和高性能的服務
  5. 靜態文件處理:Nginx在處理靜態文件方面(如HTML、CSS、JS、圖片等)具有非常高的性能,可以作為Web服務器或者靜態資源服務器使用
  6. 靈活的配置:Nginx的配置文件結構清晰,易於理解和修改。用户可以根據自己的需求對Nginx進行靈活的配置

功能

  • HTTP服務器:作為Web服務器,可以處理HTTP請求,提供網頁瀏覽服務
  • 反向代理:將客户端的請求轉發到其他服務器,並將服務器的響應返回給客户端。這樣可以隱藏服務器的真實IP地址,提高安全性
  • 負載均衡:在多個服務器之間分配客户端的請求,實現請求的負載均衡
  • 緩存和壓縮:Nginx支持內容緩存和壓縮,可以加快頁面加載速度,降低服務器負載
  • 虛擬主機:通過配置虛擬主機,可以使用一個Nginx服務器處理多個域名的請求
  • 安全性:支持SSL/TLS加密,可以對傳輸的數據進行加密,保證數據的安全性
  • 電子郵件代理:作為電子郵件服務器,可以處理IMAP/POP3協議,提供郵件收發服務

安裝nginx

yum install nginx -y

本人使用的是ARM架構的centos進行安裝的,當執行以下命令時提示沒有可用的安裝包,如果你和我一樣,可以訪問官方下載頁面進行nginx的repo配置:

下載準備:

yum install yum-utils

設置YUM存儲庫,創建名為/etc/yum.repos.d/nginx.repo的文件,並複製以下內容:

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

以上配置好了後再次進行nginx的下載應該就可以了

下載好後查看nginx版本:

➜ nginx -v
nginx version: nginx/1.22.1

配置開機啓動:

➜ systemctl enable nginx --now
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.

常用命令

  1. 查看nginx版本

    ➜ nginx -v
    nginx version: nginx/1.22.1
    
    # 詳細內容(版本號、編譯器版本、安裝路徑、日誌路徑、PID文件路徑、HTTP模塊、SSL模塊、GZIP模塊等等)
    ➜ nginx -V
    nginx version: nginx/1.22.1
    built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
    built with OpenSSL 1.0.2k-fips  26 Jan 2017
    TLS SNI support enabled
    configure arguments: --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 --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --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-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
  2. 測試 Nginx 配置文件的語法和邏輯是否正確

    ➜ nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    
    # 檢測並輸出配置文件,快速診斷配置文件問題
    ➜ nginx -T
  3. 啓動nginx與重啓

    ➜ nginx
    ➜ nginx -s reload
  4. 關閉nginx

    # 立即停止
    ➜ nginx -s stop
    # 處理完請求後停止
    ➜ nginx -s quit

有時候會在機器上查找nginx的一些重要文件路徑,如:配置文件、日誌文件等等,可以使用nginx -V命令,在終端搜索lognginx.conf等關鍵字即可

配置文件

可以使用nginx -t知道nginx的配置文件路徑具體位置,打開配置文件如下:

# /etc/nginx/nginx.conf
user  nginx;

# 數量大,併發高,會受到硬件的配置影響
worker_processes  auto; # number/auto

error_log  /var/log/nginx/error.log notice; # notice、info
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    # 定義文件類型映射表,返回瀏覽器會在頭部加上對應的文件類型
    include       /etc/nginx/mime.types;
    # mime中無對應類型,默認流類型
    default_type  application/octet-stream;

    # 日誌格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    # 訪問日誌
    access_log  /var/log/nginx/access.log  main;

    # sendfile 是一種高效的文件傳輸方式,它可以將文件數據直接從磁盤讀取到內核緩衝區,再通過網絡傳輸到客户端,避免了將文件數據從內核緩衝區複製到用户空間的開銷,提高了文件傳輸的效率。
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    # gzip壓縮
    gzip  on;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        # redirect server error pages to the static page /50x.html
        error_page  404              /404.html;
        location = /404.html {
            root   /usr/share/nginx/html;
        }
    }

    include /etc/nginx/conf.d/*.conf;
}

由以上的默認配置可以看出nginx配置是由以下幾部分組成的:

  1. main塊:主要包含全局配置參數,服務器的用户(組)、worker 進程數、進程 ID 文件路徑、日誌存放路徑等
  2. events塊:用於配置事件模塊的參數,例如 worker 進程的連接數、事件模型等
  3. http塊:用於配置 HTTP 協議相關的參數,例如服務器監聽的端口、虛擬主機、代理、緩存等
  4. server塊:屬於http塊中的模塊,用於配置一個虛擬主機的參數,例如監聽的端口、域名、SSL 證書、代理、緩存等,http塊中可以包含多個server塊(常用server來配置虛擬主機)
  5. location塊:屬於server塊中的模塊,用於配置一個 URI 的參數,例如 URI 匹配規則、代理、緩存等(匹配主機路徑)

Nginx 配置文件採用了一種層次結構的格式,每個塊都以花括號 {} 包含,其中的參數和指令以分號 ; 結尾。通過修改 Nginx 配置文件,可以自定義 Nginx 服務器的行為和參數,以適應不同的需求和場景

在默認配置文件結尾會將conf.d路徑下的所有*.conf結尾的配置文(server級別)件引入到主配置文件,這樣可以根據不同的server模塊進行劃分配置,便於管理和維護:

include /etc/nginx/conf.d/*.conf;

server

server 塊用於配置一個虛擬主機的參數,例如監聽的端口、域名、SSL 證書、代理、緩存等。每個 server 塊都必須包含一個 listen 指令,用於指定虛擬主機監聽的端口和 IP 地址

示例:

server {
    listen 80;
    server_name example.com;
    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

以上的server監聽80端口並匹配域名exemple.com,當訪問/時會訪問/usr/share/nginx/html/index.html文件。

listen表示當前虛擬主機監聽的端口,可以寫多個,如監聽https端口可以寫listen 443 ssl;

server_name表示匹配的域名,可以寫正則來匹配,如*.example.com表示exempe.com的所有二級域名都可以匹配到

除了基本參數外,server 塊還可以配置其他的參數,如:sl_certificate 和 ssl_certificate_key用於配置 SSL 證書和私鑰的路徑等等

location

location用來匹配server中的訪問路徑(path),如訪問https://blog.usworn.cn/me可以匹配path/me。location支持全匹配和正則表達式:

  • 全匹配:= /xxx
  • 正則匹配:

    • ~:區分大小寫
    • ~*:不區分大小寫
    • ^~:用於不含正則表達式uri前,nginx找到和請求uri匹配度最高的 location 後,立即用此location,不再用location 中的正則匹配

例子:

server {
    # ...

    # 全匹配 /me
    location = /me {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }

    # 匹配 以/admin 開頭的path
    location ~ ^/admin {}

    # 同上,這裏不區分大小寫相當於 /admin
    location ~* ^/ADMIN {}
}

靜態服務

作為靜態服務使用時,可以提供高效的靜態文件傳輸和緩存服務,從而加速網站的加載速度,提升用户體驗

server {
    # 指定靜態文件的根目錄,nginx 會根據 uri 在 根目錄下匹配路徑
    location ~ {
        root /usr/share/nginx/html;
        index index.html;
    }

    # 路徑映射,可以對外隱藏真實的路徑
    location /images/ {
        alias /documents/icons/;
    }
}

假如訪問index.html,內容如下:

<!DOCTYPE html>
<html>
<head>
    <title>Welcome to nginx!</title>
</head>
<body>
    <img src="/images/icon-docker.png" >
</body>
</html>

訪問頁面時會請求請求圖片,在nginx中替換掉圖片地址為/documents/icons/icon-docker.png,這對外部來説隱藏了內部的真實地址

也可以作為資源目錄列表:

server {
    # 資源列表
    location / {
        autoindex on;  # 開啓資源列表目錄
        autoindex_exact_size on;  # 顯示文件的確切大小,單位是byte;off顯示文件大概大小,單位KB、MB、GB
        autoindex_localtime on;  # off(默認)時顯示的文件時間為GMT時間;on顯示的文件時間為服務器時間
    }
}

訪問控制

  1. 使用 deny 指令來進行訪問控制,該指令可以限制某些 IP 地址或 IP 地址段的訪問

    server {
        # 禁止指定IP
        location /foo {
            deny 192.168.10.10;
        }
        # 禁止IP 地址段
        location /bar {
            deny 192.168.1.0/24;
        }
        # 允許指定IP
        location / {
            deny all;
            allow 192.168.1.10;
        }
    }

  2. 設置用户名和密碼鑑權

    安裝httpd-tools,用來生成賬户名和密碼

    yum install httpd-tools -y

    設置用户名和密碼:這裏將會生成新的文件/etc/nginx/.htpasswd,用户名為ihengshuai,密碼提示你輸入

    ➜ htpasswd -c /etc/nginx/.htpasswd ihengshuai
    New password:
    Re-type new password:
    Adding password for user ihengshuai

    查看用户名和密碼:默認生成的密碼會被加密,密碼加密算法有好幾種,你也可以使用明文密碼,請參考htpasswd -h瞭解更多

    ➜ cat /etc/nginx/.htpasswd
    ihengshuai:$apr1$FvO5arNB$nsrzQ8e.4DX.c8JUSJJTE1

    接下來進行nginx配置:

    # vim /etc/nginx/default.conf
    server {
        #...
        auth_basic "請輸入用户名和密碼";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }

重定向

nginx中支持rewritereturn關鍵字進行重定向

rewrite

rewrite <regexp> <replacement> [flag];
  • regexp:路徑匹配,如匹配:^/admin
  • replacement:替代的內容,比如換成 https://blog.usword.cn
  • flag:標識符

    • last:匹配完後繼續向下匹配 location
    • break:匹配完後,不再匹配後面的規則
    • redirect:302臨時重定向,瀏覽器會顯示新的URL
    • permanent:301永久重定向,瀏覽器會顯示新的URL

例子:

server {
    location / {
        rewrite ^(/frontend(.*))$ https://blog.usword.cn$1 permanent;
        # 不管是啥都重定向到另一個域名
        # rewrite ^(.*)$ https://blog.usword.cn$1 redirect;

        # 設置狀態碼 418 的錯誤 路徑
        error_page 418 = @redirect_stop;
        # 重定向 次數超過 10次時 ,返回狀態碼 418
        if ($redirect_count > 10) {
            return 418;
        }
    }
    location @redirect_stop {
        # do something
    }
}

當訪問路徑中以/frontend開頭時永久重定向到http://blog.usword.cn,並將路徑拼接到後面(這裏需要了解正則表達式使用)

如果重寫規則不正確,可能會導致死循環或者無限重定向。為了避免這種情況,可以使用 error_page指令或者 return 指令設置重定向的最大次數或者超時時間

return

return <code> [text];
  • code:一個 HTTP 響應碼,用於指示服務器應該返回哪種類型的響應
  • text:可選的文本字符串,用於指定響應正文

例子:

server {
    location /api {
        add_header 'Content-Type' 'application/json';
        return 200 '{"code": 200, "msg": "ok"}';
    }
    location ~* ^(/frontend(.*))$ {
        return 302 https://blog.usword.cn$1;
    }
}

以上當訪問/api時設置狀態碼200並以json的形式返回數據,當匹配到/frontend開頭的路徑時重定向到https://blog.usword.cn 並將path拼接到後面

GZIP壓縮

使用 gzip 模塊對 HTTP 響應進行壓縮。這可以顯著減少傳輸數據的大小,從而提高網站的性能和響應速度。gzip壓縮功能由ngx_http_gzip_module和ngx_http_gzip_static_module模塊提供

開啓gzip:可以用在http、server、location中

gzip on;

其他用法:

server {
    gzip on;
    gzip_types text/html text/css application/javascript;
    gzip_static on;
    gzip_proxied expired no-cache auth;
    gzip_buffers 16 8k;
    gzip_min_length 2k;
    gzip_comp_level 4;
    gzip_http_version 1.0;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\\.";
}
  1. gzip_types:要採用 gzip 壓縮的 MIME 文件類型,其中 text/html 被系統強制啓用;
  2. gzip_static:默認 off,該模塊啓用後,Nginx 首先檢查是否存在請求靜態文件的 gz 結尾的文件,如果有則直接返回該 .gz 文件內容;
  3. gzip_proxied:默認 off,nginx 做為反向代理時啓用,用於設置啓用或禁用從代理服務器上收到相應內容 gzip 壓縮;
  4. gzip_buffers:獲取多少內存用於緩存壓縮結果,16 8k 表示以 8k*16 為單位獲得
  5. gzip_min_length:允許壓縮的頁面最小字節數,頁面字節數從 header 頭中的 Content-Length 中進行獲取。默認值是 0,不管頁面多大都壓縮。建議設置成大於 1k 的字節數,小於 1k 可能會越壓越大
  6. gzip_comp_level:gzip 壓縮比,壓縮級別是 1-9,默認6,1 壓縮級別最低,9 最高,級別越高壓縮率越大,壓縮時間越長,建議 4-6;
  7. gzip_http_version:默認 1.1,啓用 gzip 所需的 HTTP 最低版本;
  8. gzip_vary:用於在響應消息頭中添加 Vary:Accept-Encoding,使代理服務器根據請求頭中的 Accept-Encoding 識別是否啓用 gzip 壓縮;
  9. gzip_disable 指定哪些不需要 gzip 壓縮的瀏覽器,正則匹配 請求頭的User-Agent

例子:對圖片進行壓縮

location ~* (png|jpeg|gif)$ {
    gzip on;
    gzip_comp_level 6;
    gzip_types image/png image/jpeg image/jpg image/gif;
}

圖像轉換

nginx中可以使用http_image_filter_module模塊的功能進行圖片的轉換如:縮放、裁剪、質量等等,使用此功能需要安裝這個模塊,這裏演示在Centos中的安裝過程,若已安裝可以跳過此步驟。

首先檢查是否安裝了此模塊,運行命令:如果發現有此模塊將會高亮顯示,如果沒有什麼都不會輸出

➜ nginx -V 2>&1 | grep 'http_image_filter_module'

configure arguments: --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 --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --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-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' `--with-http_image_filter_module`

安裝模塊依賴環境:

➜ yum install gd-devel pcre pcre-devel -y

如果原來是使用yum安裝的nginx,則需要在官方網站上找到對應版本的nginx包下載到本地:這裏我以1.22.1版本為例

# 下載
➜ wget https://nginx.org/download/nginx-1.22.1.tar.gz
# 解壓
➜ tar xf nginx-1.22.1.tar.gz

為了不影響原來的nginx的數據和配置,使用和原版本的nginx同樣的編譯參數,然後在後面添加上--with-http_image_filter_module參數即可:

# 查看原來版本的編譯參數,並複製configure arguments 的值
➜ nginx -V
# 編譯nginx
➜ cd nginx-1.22.1
➜ ./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 --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --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-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' `--with-http_image_filter_module`

# 編譯安裝文件
➜ make && make install

# 重啓nginx
➜ nginx -s reload
# 可以再次使用一下命令進行驗證是否安裝成功
➜ nginx -V 2>&1 | grep 'http_image_filter_module'

到這裏就可以使用http_image_filter_module模塊的功能了,官方文檔配置戳這裏

以上安裝此模塊後編譯如果出現其他的錯誤,請按照提示安裝上相關的依賴即可解決

image_filter使用參數:

  • image_filter off;:關閉模塊
  • image_filter test;:確保圖片格式為PNG、JPEG、GIF、WEBP,否則返回415狀態碼
  • image_filter size;:以json的形式輸出圖片的信息,如:'{"img":{"width":1135,"height":500,"type":"jpeg"}}',resize、crop等同時使用時無效果
  • image_filter rotate 90|180|270;:旋轉圖像,可以和resize、crop一起使用
  • image_filter resize width height;:按比例縮放圖像,要減少一個維度可以將另一個值設置為-
  • image_filter crop width height;:按比例將圖像縮小到較大的一側,並在另一側產生無關邊緣
  • image_filter_buffer size;:讀取圖片緩衝區大小,若圖片太大緩衝區太小則會拋415錯誤
  • image_filter_interlace on;:如果啓用,最終圖像將交錯。對於JPEG,最終圖像將採用"逐行JPEG"格式。
  • image_filter_jpeg_quality 1-100;:設置轉換的JPEG圖像的質量。可接受的值是從1到100的範圍內。較小的值通常意味着圖像質量越低,以達到減少數據傳輸。推薦的最大值為95,參數值可以包含變量
  • image_filter_webp_quality 1-100:設置webp圖片質量,同上
  • image_filter_transparency on|off;:定義在使用調色板指定的顏色轉換GIF圖像或PNG圖像時是否應保留透明度。透明度的降低會導致質量更好的圖像,PNG中的alpha通道透明度始終保留。
  • image_filter_sharpen 1-100;:增加最終圖像的清晰度,鋭度百分比可以超過100。零值將禁用鋭化。參數值可以包含變量

:::tip
注意以上大部分操作都會耗時,尤其是對於很大的圖片,如果裁剪、縮放的比例很大,將會增加耗時,應合理設置處理流程

此模塊處理圖像出現異常的情況下基本都是拋出415錯誤,因此在不能正常處理圖像情況下,重定向到指定的位置更為友好
:::

例子

server {
    location /images/ {
        # 初始化 width 為-,也就是原始大小
      set $width -;

      # 匹配圖片url上的 w參數 如:/images/cat.png?w=1 | w=xx
      # 正則判斷是純數字且大於0時將值 賦值給 width
      if ($arg_w ~* ^[1-9]\d+$) {
        set $width $arg_w;
      }
      # 設置緩衝區 5M
      image_filter_buffer 5m;
      image_filter test;
      # 縮放圖片 width,另一側按比例縮放
      image_filter resize $width -;

      alias /documents/;
      allow all;

      # 當拋出 415 錯誤時,走 @image_filter_error 路由
      error_page 415 @image_filter_error;
    }

    # 重定向到 錯誤圖片
    location @image_filter_error {
        return 301 /images/error.png;
    }
}

在瀏覽器上測試使用w參數:大於0都可以正常處理,其他的都會以原始大小返回;當圖像大小大於5M時,由於太大將會重定向到錯誤圖片,以上根據實際情況自行處理

除了以上對圖片進行轉換外,還可以使用ngx_http_set_misc_module模塊或Lua腳本將圖片轉換成webp格式,提高圖像加載,這裏就不介紹了

緩存

nginx默認支持靜態資源的緩存和代理緩存

靜態資源緩存

可以使用expiresCache-Control請求頭設置緩存

  1. 使用expires進行緩存,Expires 是 HTTP/1.0 中定義的字段,它指定了在過期之前客户端可以緩存響應的時間。服務器會在響應頭中設置一個到期日期,客户端在該日期之前可以緩存響應。Expires 頭部的時間格式是 GMT 格式的絕對時間,如 "Expires: Wed, 21 Oct 2015 07:28:00 GMT"。

    server {
        location ~ \.(png|jpg|jpeg|gif|webp)$ {
            expires 1d;
        }
    }
  2. 使用Cache-Control進行緩存,它是 HTTP/1.1 中定義的字段,它提供了更為靈活的緩存控制方式。它可以指定緩存的時間、緩存的位置、緩存的類型等。常用的指令包括max-ageno-cacheno-storemust-revalidate 等。其中,max-age 指定了緩存的最長時間,它的值是一個相對時間,如 "Cache-Control: max-age=86400" 表示緩存 1 天。

    server {
        location ~ \.(png|jpg|jpeg|gif|webp)$ {
            add_header Cache-Control "public, max-age=86400";
        }
    }

    Cache Control可以使用的參數如下:

    • public:指示響應可以被任何中間緩存緩存,包括客户端和代理服務器。
    • private:指示響應只能被客户端緩存,不應該被代理服務器緩存。
    • max-age:指示緩存存儲的最長時間,單位為秒。例如,Cache-Control: max-age=3600 表示緩存有效期為 1 小時。
    • s-maxage:與 max-age 類似,但只適用於共享緩存(比如代理服務器)。如果同時設置了max-age 和 s-maxage,則 s-maxage 優先級更高。
    • no-cache:指示客户端必須在使用緩存之前重新驗證資源的有效性。如果資源未被修改,則可以從緩存中讀取資源。否則,需要重新下載資源。
    • no-store:指示不應將響應存儲在任何緩存中,包括客户端和代理服務器。
    • must-revalidate:指示在過期之後,緩存必須從原始服務器重新獲取資源,以確保緩存仍然有效。如果不能從原始服務器重新獲取資源,則緩存必須標記為過期。

二者的區別和對比:

Expires 和 Cache-Control 的區別主要在於過期時間的計算方式不同。Expires 是基於服務器時間的絕對時間,因此它的缺點是服務器時間和客户端時間可能不同步,可能導致緩存不一致。而 Cache-Control 則是相對時間,可以避免這個問題。此外,Cache-Control還支持更為靈活的控制方式,可以更好地控制緩存策略。建議使用Cache-Control 來設置 HTTP 緩存控制,而Expires則可以用作向後兼容,或在某些場景下作為備用方案。

代理緩存

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m inactive=60m;
server {
    location /proxy {
        proxy_pass http://localhost:10000;

        # 定義緩存的鍵名
        proxy_cache_key "$scheme$proxy_host$request_uri";
        # 緩存的有效期為 5 分鐘
        proxy_cache_valid 200 5m;
        # 根據 Pragma 字段決定是否跳過緩存
        proxy_cache_bypass $http_pragma;
        # 制重新驗證緩存
        proxy_cache_revalidate on;
        # 啓用代理緩存,並指定緩存區名稱
        proxy_cache my_cache;
        # 啓用緩存背景更新
        proxy_cache_background_update on;
        # 設置緩存背景更新的時間間隔為 1 小時
        proxy_cache_background_update_interval 1h;
        # 設置緩存背景更新的失敗重試次數為 2 次
        proxy_cache_background_update_retries 2;
        # 設置緩存背景更新時使用的臨時文件路徑
        proxy_cache_background_update_temp_path /tmp/nginx_cache;
        # 啓用緩存鎖定,控制併發緩存請求
        proxy_cache_lock on;
        # 設置緩存鎖定的超時時間為 5 秒
        proxy_cache_lock_timeout 5s;
        # 緩存鎖定失敗時,是否返回錯誤碼 503
        proxy_cache_lock_age on;
        # 啓用緩存失效時使用舊的緩存數據
        proxy_cache_use_stale error timeout updating;
        # 設置緩存失效時使用舊的緩存數據的有效期為 1 分鐘
        proxy_cache_valid 404 1m;
    }
}

防盜鏈

防盜鏈(Referer 防盜鏈)是指在網站或服務器端設置一些規則,只允許指定的域名或網站引用自己的資源,防止非法盜鏈,減少帶寬浪費。

在 Nginx 中,可以使用 valid_referers 指令來實現防盜鏈的功能。該指令用於設置有效的引用來源(Referer)列表,只有在該列表中的來源才能訪問指定的資源。

valid_referers [none|blocked|server_names|string ...];
  • none:允許空的引用來源(Referer)。
  • blocked:阻止所有的引用來源(Referer)。
  • server_names:允許與服務器名匹配的引用來源(Referer)。
  • string:允許指定字符串的引用來源(Referer),可以使用通配符和正則表達式進行匹配。

例子:

server {
    server_name *.general-mac.com;

    location ~ \.(png|jpg|jpeg|gif|webp)$ {
        valid_referers blocked server_names "~.*general-mac\.com$";

        if ($invalid_referer) {
            return 403;
        }
    }
}

上面的例子設置了不允許refer為none(不允許單獨打開圖片),使用正則匹配只允許refer為 general-mac.com 或其任何子域名,其餘的都會返回403,

反向代理

server {
    location /proxy {
        proxy_pass http://localhost:10001;

        # 添加響應頭部返回給客户端
        add_header X-Real-IP $remote_addr;

        # 傳給目標服務器設置的頭部信息
        # 源host
        proxy_set_header Host $http_host;
        #上層請求真實IP (一般設置在第一層代理服務器)
        proxy_set_header X-Real-IP $remote_addr;
        # 訪問的協議
        proxy_set_header X-Forwarded-Scheme $scheme;
        # 將經過多個代理服務器的ip以 逗號 拼接,最左邊是用户真實ip
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Websocket
        proxy_set_header Connection "upgrade";
        proxy_set_header Upgrade $http_upgrade;

        # 目標服務器數據回傳超時時間
        proxy_send_timeout 10;
        # 目標服務器響應超時時間
        proxy_read_timeout 30;
        # 和目標服務器連接超時時間
        proxy_connect_timeout 90;
    }
}

使用nodejs簡單的寫一個後端服務:

const express = require("express");
const app = express();

const port = 10001;
app.use((req, res) => {
    res.json({
        port,
        code: 200,
        msg: "ok",
        url: req.url
    })
})

app.listen(port, () => console.log('server is running on port' + port));

測試:

➜ curl general-mac.com/proxy -I
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Thu, 06 Apr 2023 13:17:41 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 290
Connection: keep-alive
X-Powered-By: Express
ETag: W/"122-vJBMYWLUDf/IIuHJiL8M6GUx+Wo"
X-Real-IP: 192.168.10.1

配置跨域

跨域是怎麼產生的這裏不再贅述(你可以查看「HTTP協議及安全防範一文」),在nginx中進行反向代理的跨域配置

# 後端服務器,使用上面的nodejs
server {
    listen 10010;
    location /proxy {
        # 設置允許的源(IP+PORT)
        add_header Access-Control-Allow-Origin $http_origin;
        # 設置允許的 請求方法
        add_header Access-Control-Allow-Methods 'OPTIONS, GET, POST, PUT, DELETE';
        # 設置允許的請求頭
        add_header Access-Control-Allow-Headers 'x-locale';
        # 其他自定義...
        # 預檢請求 204 快速返回
        if ($request_method = 'OPTIONS') {
           return 204;
        }
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Host $host;
        proxy_set_header X-Http-Host $http_host;
        proxy_set_header X-Forwarded-Scheme $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://backend;
    }
}

新建一個HTML頁面:

<html>
<head><meta charset='utf8'/></head>
<body>
  <input id='input'>
  <button>請求</button>
  <script>
    const btn = document.querySelector('button');
    btn.addEventListener('click', async e => {
        const res = await fetch('http://192.168.10.9:10010/proxy', {
            mode: 'cors',
            headers: {
                'x-locale': 'zh'
            }
        })
        .then(res => res.json())
        console.log(res)
    })
  </script>
</body>
</html>

負載均衡

nginx中可以使用nginx_http_upstream_module模塊實現負載均衡,請確保已安裝

upstream backend {
    # 使用三個後端服務地址
    server backend1.example.com weight=1;
    server backend2.example.com;
    server backend3.example.com;

    # 輪詢
    # round_robin;

    # 連接最小數
    # least_conn;

    # IP哈希
    # ip_hash;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

nginx可以根據不同的負載均衡策略進行流量分發

配置HTTPS

在使用HTTPS之前,需要獲得SSL證書。可以從證書頒發機構(CA)購買證書,或者使用免費的證書頒發機構(如Let's Encrypt)獲得證書,這裏採用OpenSSL自簽證書,便於使用封裝成以下腳本auto-cetificate.sh

#!/bin/bash
# https://docs.azure.cn/zh-cn/articles/azure-operations-guide/application-gateway/aog-application-gateway-howto-create-self-signed-cert-via-openssl

echo "請使用sudo運行以獲取系統權限!"
echo "請輸入域名:"

read userdomain

# 啥都不輸退出
if [ ! "$userdomain" ]; then
    exit
fi

# 使用OpenSSL簽發證書
# 1. 生成服務器私鑰 (domain.com.key)  domain.com 隨便起的名字
openssl genrsa -out $userdomain.key 4096

# 2.生成證書籤名請求(CSR) domain.com.csr
# 生成 CSR 的過程中,會提示輸入一些信息,其中一個提示是 Common Name (e.g. YOUR name),
# 這個非常重要,這一項應填入 FQDN(Fully Qualified Domain Name)完全合格域名/全稱域名,
# 如果您使用 SSL 加密保護網絡服務器和客户端之間的數據流,
# 舉例被保護的網站是 https://test.chinacloudsites.cn,
# 那麼此處 Common Name 應輸入 test.chinacloudsites.cn
openssl req -new -key $userdomain.key -out $userdomain.csr

# 3.使用上一步的證書籤名請求籤發證書
openssl x509 -req -days 365 -in $userdomain.csr -signkey $userdomain.key -out $userdomain.crt -extensions SAN

# pem
# openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
# openssl s_client -showcerts -connect gitlab.ihengshuai.com:443 -servername gitlab.ihengshuai.com < /dev/null 2>/dev/null | openssl x509 -outform PEM > /certs/gitlab.ihengshuai.com.crt


echo
echo "Generate success!"
echo

# 將本地域名寫入host
echo 需要將域名寫入host嗎[yes/no]?
read confirm_read_host
if [ "$confirm_read_host" != "yes" ]; then
    exit
fi

echo 需要保持和證書域名相同不[yes/no]?
read confirm_write_host
if [ "$confirm_write_host" == "no" ]; then
    echo 請填寫待寫入host的域名
    read custom_host_domain
    cp /etc/hosts /etc/hosts.old
    echo "127.0.0.1 $custom_host_domain" >>/etc/hosts
    exit
fi

cp /etc/hosts /etc/hosts.old
echo "127.0.0.1 $userdomain" >>/etc/hosts
echo "Write success!"
sleep 1

執行腳本根據提示輸入生成證書:

➜ ./auto-cetificate.sh

最終會產生如下文件:

➜ ls && pwd
auto-cetificate.sh  general-mac.com.crt  general-mac.com.csr  general-mac.com.key
/root/certificates

生成DH加密參數:

# 此過程會耗時
openssl dhparam -out dhparam.pem 2048
對於SSL相關配置、握手不太清楚的可以閲讀我的「HTTP協議及安全防範」一文

在nginx中配置https:

server {
    listen       80;
    listen       443 ssl;
    server_name  general-mac.com;

    # 證書
    ssl_certificate /root/certificates/general-mac.com.crt;
    ssl_certificate_key /root/certificates/general-mac.com.key;

    # TLS版本、加密套件
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; # 加密套件根據自己需求調整
    # 服務器推薦加密套件
    ssl_prefer_server_ciphers on;
    # DH參數
    ssl_dhparam /root/certificates/dhparam.pem;

    # TLS會話恢復
    ssl_session_timeout 10m;
    ssl_session_cache   shared:SSL:10m;
    ssl_session_tickets off;

    # 重定向https
    if ($ssl_protocol = '') {
        rewrite ^(.*) https://$server_name$request_uri permanent;
    }
    # 判斷有多種方式
    #if ($scheme = 'http') {
    #  rewrite ^(.*) https://$server_name$request_uri permanent;
    #}
}

配置好後記得重啓nginx,打開遊覽器訪問general-mac.com:由於自簽證書沒有被CA認證會被瀏覽器鑑定不安全的鏈接,點擊高級進一步訪問即可,或者將證書放入系統根證書中讓操作系統信任

優化https

啓用了https後由於會進行SSL握手會消耗更多的CPU資源,通過啓用SSL會話重用來優化:

ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1h;
ssl_session_tickets off;
  • ssl_session_cache:這個指令用於配置SSL會話緩存,它指定了緩存的名稱("shared:SSL")和大小("50m")。SSL會話緩存是用來存儲SSL握手過程中生成的會話密鑰的,這些會話密鑰可以被重用來加速後續的SSL握手過程。通過啓用SSL會話緩存,可以減少SSL握手的時間和CPU負載,從而提高服務器的性能
  • ssl_session_timeout:這個指令用於配置SSL會話緩存的超時時間,它指定了會話緩存的有效期為1個小時。一旦會話緩存過期,會話密鑰將被刪除,下一次SSL握手將會重新生成一個新的會話密鑰。通過使用合適的會話超時時間,可以平衡服務器的安全性和性能

配置HTTP2/3

要在nginx中啓用HTTP/2需要在nginx版本1.9.5或更高版本中啓用,只支持在加密通道上運行,因此只能在HTTPS上使用,在以上的基礎上添加http2

server {
    listen 443 ssl http2;

    location / {
        # HTTP2 server push功能
        http2_push /style.css;
    }
}

打開瀏覽器訪問:如果你沒有看到h2,需要勾選顯示protocol一欄

HTTP/2使用多路複用技術,可以在單個TCP連接上同時發送多個請求和響應。這樣可以減少延遲和提高併發性,從而加快頁面加載速度;HTTP/2使用二進制協議,可以減少網絡流量和解析時間,從而提高了網絡性能和效率

雖然HTTP2使用多路複用技術減少連接時間,由於其存在隊頭阻塞的問題,當一個請求或響應被阻塞時,後續請求或響應也會被阻塞,從而導致整個連接的性能下降,因此它仍不是完美的協議也是存在一些缺點

:::tip 什麼是隊頭阻塞
<u>在HTTP/2中,多個請求和響應可以通過單個TCP連接並行傳輸。但是,由於HTTP/2使用了幀的概念來分割請求和響應,而幀必須按順序發送和接收,因此如果前面的請求或響應被阻塞,後續的請求或響應也必須等待前面的請求或響應完成後才能發送或接收。這就是隊頭阻塞的問題。</u>
:::

那如何解決隊頭阻塞問題呢?可以使用多域名請求提高併發度、優化請求隊列(性能好的放前面之類)、採用HTTP3

這裏來講QUIC協議(HTTP3),一種基於UDP協議的傳輸層協議,其優勢如下:

  • 更快的連接建立和恢復
  • 更好的多路複用:使用流來分隔請求和響應,可以更好地實現多路複用,並且不需要使用幀頭部,從而提高了頭部壓縮效率。此外,QUIC還支持優先級,可以更好地控制請求和響應的優先級
  • 更好的擁塞控制:QUIC採用基於TCP的擁塞控制算法,但可以更快地適應網絡環境的變化,從而提高了網絡傳輸的效率。同時,QUIC還支持基於連接的流量控制,可以更好地適應不同的應用需求
  • QUIC使用TLS 1.3來保護數據的安全性和隱私性,並且支持0-RTT、1—RTT握手,可以更快地建立安全連接。此外,QUIC還支持源地址驗證和連接遷移等功能,可以更好地防止網絡攻擊和提高網絡的可靠性

如何使用?可以安裝nginx-quic使用其功能,這裏就不介紹如何安裝了,可以參考nginx-quic官方配置或quiche配置nginx

server {
    listen 443 ssl http2; #TCP
    listen 443 http3 quic reuseport; # QUIC

    ssl_protocols   TLSv1.3;
    # 開啓 TLS 1.3 0-RTT
    ssl_early_data on;
    add_header Alt-Svc 'h3-29=":8443"; ma=2592000,h3-T051=":8443"; ma=2592000,h3-Q050=":8443"; ma=2592000,h3-Q046=":8443"; ma=2592000,h3-Q043=":8443"; ma=2592000,quic=":8443"; ma=2592000; v="46,43"';
}

參考文檔:

  • nginx-quic官方配置
  • nginx-quic-repository
  • Binary Packages to Preview Nginx HTTP3/QUIC Implementation
  • quiche配置nginx

keepalived實現高可用

由於流量都是通過nginx入口分發給應用服務,nginx很難保持永久正常服務狀態,當nginx掛了時就會導致所有應用都無法訪問,因此使用多個機器進行備份待用實現高可用是必然的

keepalived是一款常用於搭建高可用性服務的軟件,可以與nginx等應用程序一起使用,以確保在一個節點故障時,服務能夠在另一個節點上繼續運行,從而提高應用程序的可用性和穩定性。keepalived需要綁定和主機同一網段的一個或多個虛擬ip,根據檢測機制將虛擬ip綁定到指定的機器上,當機器宕機時,又會綁定到另一個健康的機器上。使用keepalived實現高可用至少需要2台主機,這裏準備兩台虛擬機。

  1. 每個節點都安裝keepalived和nginx

    yum install keepalived nginx -y
  2. 查看節點網卡,這裏顯示我有兩張網卡ens160和ens256,這裏使用ens256網卡地址,兩個節點的ip分別為192.168.10.9192.168.10.8

    # 節點1
    ➜ keepalived ip a
    2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether xx:xx:xx:xx:76:b0 brd ff:ff:ff:ff:ff:ff
        inet 192.168.3.92/24 brd 192.168.3.255 scope global noprefixroute dynamic ens160
           valid_lft 79657sec preferred_lft 79657sec
    3: ens256: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether xx:xx:xx:xx:72:86 brd ff:ff:ff:ff:ff:ff
        inet 192.168.10.9/24 brd 192.168.10.255 scope global noprefixroute ens256
           valid_lft forever preferred_lft forever
    
    # 節點2
    ➜ keepalived ip a
    # ...
    192.168.10.8/24
  3. 配置keepalived,vim /etc/keepalived/keepalived.conf:默認的配置文件應該有很多,只需要以下配置即可,其他可以直接刪除掉

    注意每個節點都需要配置以下內容,不同的節點請注意配置文件中的提示進行修改
    # /etc/keepalived/keepalived.conf
    ! Configuration File for keepalived
    
    global_defs {
       router_id LVS_DEVEL
       #vrrp_strict
       vrrp_skip_check_adv_addr
       vrrp_garp_interval 0
       vrrp_gna_interval 0
    }
    
    vrrp_script chk_http_ port {
        # 檢測nginx健康狀態腳本,根據下一步驟創建
        script "/etc/keepalived/nginx_check.sh"
        interval 2
        weight 2
    }
    
    vrrp_instance VI_1 {
        # 指定keepalived的角色,MASTER為主,BACKUP為備,當前節點設置為MASTER,其餘節點設置為BACKUP
        state MASTER
        # 指定網卡,根據自己節點網卡的名稱 替換ens256
        interface ens256
        # vrrp實例id,所有節點的值必須一致
        virtual_router_id 51
        # 數值越大,優先級越大,獲取處理請求的優先級越高,根據節點的性能自行調整
        priority 100
        # 檢測節點狀態的心跳間隔
        advert_int 1
        # 節點間通信類型和密碼
        authentication {
            auth_type PASS # 密碼類型
            auth_pass 1111 # 密碼
        }
        # 虛擬ip,根據當前節點的ip網段設置
        virtual_ipaddress {
            # 設置其中一個虛擬ip為 192.168.10.5  網卡 ens256  打標籤 ens256:vip51
            192.168.10.5/24 dev ens256 label ens256:vip51
        }
    }
  4. 配置檢測nginx狀態腳本,同樣每個節點都需要,vim /etc/keepalived/nginx_check.sh

    #! /bin/bash
    
    # 查看nginx的進程數
    A=`ps -C nginx --no-heading | wc -l`
    # 進程數位0時,啓動nginx
    if [ $A -eq 0 ];then
        /usr/sbin/nginx
        sleep 2
        # 兩秒後nginx進程還是0則殺死keepalived,進行VIP的轉移,將會飄到另一節點上
        if [ `ps -C nginx --no-heading | wc -l` -eq 0 ];then
            killall keepalived
        fi
    fi
  5. 所有節點添加keepalived_script用户並賦予執行腳本權限:

    ➜ useradd keepalived_script
    ➜ visudo # 添加以下內容
    keepalived_script ALL=(ALL) NOPASSWD: ALL
  6. 所有節點啓動nginx和keepalived,請確保nginx可以正常訪問:為了方便演示,可以將不同節點的nginx首頁設置成不同的

    # 啓動nginx,或 systemctl start nginx,安裝包的在bin文件下執行
    ➜ nginx
    # 啓動keepalived
    ➜ systemctl start keepalived
    
    # 查看keepalive狀態
    ➜ systemctl status keepalived -l
    keepalived.service - LVS and VRRP High Availability Monitor
    Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; vendor preset: disabled)
    Active: active (running) since 六 2020-04-08 18:08:52 CST; 18min ago
    Process: 5171 ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS (code=exited, status=0/SUCCESS)
    Main PID: 5172 (keepalived)
        CGroup: /system.slice/keepalived.service
           ├─5172 /usr/sbin/keepalived -D
           ├─5173 /usr/sbin/keepalived -D
           └─5174 /usr/sbin/keepalived -D
    
    4月 08 18:08:54 general-mac Keepalived_vrrp[5174]: Sending gratuitous ARP on ens256 for 192.168.10.5
    4月 08 18:08:54 general-mac Keepalived_vrrp[5174]: Sending gratuitous ARP on ens256 for 192.168.10.5
  7. 在主節點上查看ip:可以看到當前主節點的ens256網卡上會綁定一個VIP(192.168.10.5),就是keepalived設置的虛擬ip192.168.10.5,查看其他機器是沒有當前VIP的

    ➜ ip a
    #省略其他...
    3: ens256: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether xx:xx:xx:xx:72:86 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.9/24 brd 192.168.10.255 scope global noprefixroute ens256
       valid_lft forever preferred_lft forever
    inet 192.168.10.5/24 scope global secondary ens256:vip51
       valid_lft forever preferred_lft forever
  8. 瀏覽器訪問VIP地址192.168.10.5

    當所有節點都沒有問題時keepalived會將訪問導向priority優先級最高的節點上,上面主節點優先級最高,所以會返回主節點上的nginx首頁(包含k8s圖片)

    這裏停用主節點上的keepalived來演示宕機的情況,宕機後VIP會從當前節點剔除並根據優先級綁定到另一節點,這樣再次訪問時就會訪問到另一節點的nginx上,而當宕機恢復後keepalived又會根據優先級回到原來的節點上,感興趣可以試試

    # 主節點上停止
    ➜ systemctl stop keepalived
    # 主節點上查看ip,網卡上沒了VIP
    ➜ ip a
    
    # 另一節點上查看,會發現綁定了VIP,再次刷新瀏覽器發現網頁變了
    ➜ ip a

內置變量

以下是一些常用的內置變量,對於配置是有很大幫助的

$arg_PARAMETER #GET 請求中變量名 PARAMETER 參數的值
$args #這個變量等於 GET 請求中的參數,例如,foo=123&bar=blahblah;這個變量可以被修改
$binary_remote_addr #二進制碼形式的客户端地址
$body_bytes_sent #傳送頁面的字節數
$content_length #請求頭中的 Content-length 字段
$content_type #請求頭中的 Content-Type 字段
$cookie_COOKIE #cookie COOKIE 的值
$document_root #當前請求在 root 指令中指定的值
$document_uri #與 $uri 相同
$host #請求中的主機頭(Host)字段,如果請求中的主機頭不可用或者空,則為處理請求的 server 名稱(處理請求的 server 的 server_name 指令的值)。值為小寫,不包含端口
$hostname #機器名使用 gethostname 系統調用的值
$http_HEADER #HTTP 請求頭中的內容,HEADER 為 HTTP 請求中的內容轉為小寫,-變為_(破折號變為下劃線),例如:$http_user_agent(Uaer-Agent 的值)
$sent_http_HEADER #HTTP 響應頭中的內容,HEADER 為 HTTP 響應中的內容轉為小寫,-變為_(破折號變為下劃線),例如:sent_http_content_type…
$is_args #如果 $args 設置,值為"?",否則為""
$limit_rate #這個變量可以限制連接速率
$nginx_version #當前運行的 nginx 版本號
$query_string #與 $args 相同
$remote_addr #客户端的IP地址
$remote_port #客户端的端口
$remote_port #已經經過 Auth Basic Module 驗證的用户名
$request_filename #當前連接請求的文件路徑,由 root 或 alias 指令與 URI 請求生成
$request_body #這個變量(0.7.58+)包含請求的主要信息。在使用 proxy_pass 或 fastcgi_pass 指令的 location 中比較有意義
$request_body_file #客户端請求主體信息的臨時文件名
$request_completion #如果請求成功,設為"OK";如果請求未完成或者不是一系列請求中最後一部分則設為空
$request_method #這個變量是客户端請求的動作,通常為 GET 或 POST。包括 0.8.20 及之前的版本中,這個變量總為 main request 中的動作,如果當前請求是一個子請求,並不使用這個當前請求的動作
$request_uri #這個變量等於包含一些客户端請求參數的原始 URI,它無法修改,請查看 $uri 更改或重寫 URI
$scheme #所用的協議,例如 http 或者是 https,例如 rewrite ^(.+)$$scheme://example.com$1 redirect
$server_addr #服務器地址,在完成一次系統調用後可以確定這個值,如果要繞開系統調用,則必須在listen中指定地址並且使用bind參數
$server_name #服務器名稱
$server_port #請求到達服務器的端口號
$server_protocol #請求使用的協議,通常是 HTTP/1.0、HTTP/1.1或HTTP/2
$uri #請求中的當前 URI(不帶請求參數,參數位於 args ) , 不 同 於 瀏 覽 器 傳 遞 的 args),不同於瀏覽器傳遞的 args),不同於瀏覽器傳遞的 request_uri 的值,它可以通過內部重定向,或者使用 index 指令進行修改。不包括協議和主機名,例如 /foo/bar.html

如何打印一些變量?

  1. 通過log 指令,通過 $variable 語法打印變量

    # http上下文
    
    log_format main3 '$uri'; # 定義日誌格式
    access_log /opt/var/log/nginx/access.log main3; # 定義日誌的路徑
  2. 可以不用log,通過將變量返回給客户端,就可以查看了

    location / {
      return 200 $uri; # 直接返回出去
      # 或
      add_header X-uri $uri; # 通過header返回
      # 以及其他方法均可...
    }

參考文檔

  • Nginx官方文檔
  • Nginx手冊
user avatar Leesz Avatar qingzhan Avatar inslog Avatar guixiangyyds Avatar zhulongxu Avatar Z-HarOld Avatar wmbuke Avatar bugDiDiDi Avatar tanggoahead Avatar best-doraemon Avatar johanazhu Avatar lizhiqianduan Avatar
Favorites 46 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.