整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          基于 Nginx 的 HTTPS 性能優化實踐

          要: 隨著相關瀏覽器對HTTP協議的“不安全”、紅色頁面警告等嚴格措施的出臺,以及向 iOS 應用的 ATS 要求和微信、支付寶小程序強制 HTTPS 需求,以及在合規方面如等級保護對傳輸安全性的要求都在推動 HTTPS 的發展。

          前言

          分享一個卓見云的較多客戶遇到HTTPS優化案例。

          隨著相關瀏覽器對HTTP協議的“不安全”、紅色頁面警告等嚴格措施的出臺,以及向 iOS 應用的 ATS 要求和微信、支付寶小程序強制 HTTPS 需求,以及在合規方面如等級保護對傳輸安全性的要求都在推動 HTTPS 的發展。

          雖然 HTTPS 優化了網站訪問體驗(防劫持)以及讓傳輸更加安全,但是很多網站主趕鴨子上架式的使用了 HTTPS 后往往都會遇到諸如:頁面加載速度變慢、服務器負載過高以及證書過期不及時更新等問題。

          所以本文就來探討一下 HTTPS 的優化實踐。

          選型

          其實像 Apache Httpd、LigHttpd、Canddy 等 Web 服務軟件都可以設置 HTTPS,但是在相應的擴展生態和更新率上都不如 Nginx。 Nginx 作為大型互聯網網站的 Web 入口軟件有著廣泛的支持率,例如阿里系的 Tengine、CloudFlare 的 cloudflare-nginx、又拍云用的 OpenResty 都是基于 Nginx 而來的,Nginx 是接受過大規模訪問驗證的。同時大家也將自己開發的組件回饋給 Nginx 社區,讓 Nginx 有著非常良好的擴展生態。

          ? 圖1-1 Nginx 在全網的使用情況

          所以說 Nginx 是一款很好的 Web 服務軟件,選擇 Nginx 在提升性能的同時能極大的降低我們的擴展成本。

          新功能

          圍繞 Web 服務已經有非常多的新功能需要我們關注并應用了,這里先羅列相關新功能。

          HTTP/2

          相比廉頗老矣的 HTTP/1.x,HTTP/2 在底層傳輸做了很大的改動和優化包括有:

          1. 每個服務器只用一個連接,節省多次建立連接的時間,在TLS上效果尤為明顯
          2. 加速 TLS 交付,HTTP/2 只耗時一次 TLS 握手,通過一個連接上的多路利用實現最佳性能
          3. 更安全,通過減少 TLS 的性能損失,讓更多應用使用 TLS,從而讓用戶信息更安全

          在 Akamai 的 HTTP/2 DEMO中,加載300張圖片,HTTP/2 的優越性極大的顯現了出來,在 HTTP/1.X 需要 14.8s 的操作中,HTTP/2 僅需不到1s。

          HTTP/2 現在已經獲得了絕大多數的現代瀏覽器的支持。只要我們保證 Nginx 版本大于 1.9.5 即可。當然建議保持最新的 Nginx 穩定版本以便更新相關補丁。同時 HTTP/2 在現代瀏覽器的支持上還需要 OpenSSL 版本大于 1.0.2。

          TLS 1.3

          和 HTTP/1.x 一樣,目前受到主流支持的 TLS 協議版本是 1.1 和 1.2,分別發布于 2006年和2008年,也都已經落后于時代的需求了。在2018年8月份,IETF終于宣布TLS 1.3規范正式發布了,標準規范(Standards Track)定義在 rfc8446。

          TLS 1.3 相較之前版本的優化內容有:

          1. 握手時間:同等情況下,TLSv1.3 比 TLSv1.2 少一個 RTT
          2. 應用數據:在會話復用場景下,支持 0-RTT 發送應用數據
          3. 握手消息:從 ServerHello 之后都是密文。
          4. 會話復用機制:棄用了 Session ID 方式的會話復用,采用 PSK 機制的會話復用。
          5. 密鑰算法:TLSv1.3 只支持 PFS (即完全前向安全)的密鑰交換算法,禁用 RSA 這種密鑰交換算法。對稱密鑰算法只采用 AEAD 類型的加密算法,禁用CBC 模式的 AES、RC4 算法。
          6. 密鑰導出算法:TLSv1.3 使用新設計的叫做 HKDF 的算法,而 TLSv1.2 是使用PRF算法,稍后我們再來看看這兩種算法的差別。

          總結一下就是在更安全的基礎上還做到了更快,目前 TLS 1.3 的重要實現是 OpenSSL 1.1.1 開始支持了,并且 1.1.1 還是一個 LTS 版本,未來的 RHEL8、Debian10 都將其作為主要支持版本。在 Nginx 上的實現需要 Nginx 1.13+。

          Brotli

          Brotli 是由 Google 于 2015 年 9 月推出的無損壓縮算法,它通過用變種的 LZ77 算法,Huffman 編碼和二階文本建模進行數據壓縮,是一種壓縮比很高的壓縮方法。

          根據Google 發布的研究報告,Brotli 具有如下特點:

          1. 針對常見的 Web 資源內容,Brotli 的性能要比 Gzip 好 17-25%;
          2. Brotli 壓縮級別為 1 時,壓縮速度是最快的,而且此時壓縮率比 gzip 壓縮等級為 9(最高)時還要高;
          3. 在處理不同 HTML 文檔時,brotli 依然提供了非常高的壓縮率;

          在兼容 GZIP 的同時,相較 GZIP:

          1. JavaScript 上縮小 14%
          2. HTML上縮小 21%
          3. CSS上縮小 17%

          Brotli 的支持必須依賴 HTTPS,不過換句話說就是只有在 HTTPS 下才能實現 Brotli。

          ECC 證書

          橢圓曲線密碼學(Elliptic curve cryptography,縮寫為ECC),一種建立公開金鑰加密的算法,基于橢圓曲線數學。橢圓曲線在密碼學中的使用是在1985年由Neal Koblitz和Victor Miller分別獨立提出的。

          內置 ECDSA 公鑰的證書一般被稱之為 ECC 證書,內置 RSA 公鑰的證書就是 RSA 證書。由于 256 位 ECC Key 在安全性上等同于 3072 位 RSA Key,加上 ECC 運算速度更快,ECDHE 密鑰交換 + ECDSA 數字簽名無疑是最好的選擇。由于同等安全條件下,ECC 算法所需的 Key 更短,所以 ECC 證書文件體積比 RSA 證書要小一些。

          ECC 證書不僅僅可以用于 HTTPS 場景當中,理論上可以代替所有 RSA 證書的應用場景,如 SSH 密鑰登陸、SMTP 的 TLS 發件等。

          不過使用 ECC 證書有兩個點需要注意:

          一、 并不是每一個證書類型都支持的,一般商業證書中帶增強型字眼的才支持ECC證書的簽發。

          二、 ECC證書在一些場景中可能還不被支持,因為一些產品或者軟件可能還不支持 ECC。 這時候就要虛線解決問題了,例如針對部分舊操作系統和瀏覽器不支持ECC,可以通過ECC+RSA雙證書模式來解決問題。

          安裝

          下載源碼

          綜合上述我們要用到的新特性,我們整合一下需求:

          HTTP/2 要求 Nginx 1.9.5+,,OpenSSL 1.0.2+

          TLS 1.3 要求 Nginx 1.13+,OpenSSL 1.1.1+

          Brotli 要求 HTTPS,并在 Nginx 中添加擴展支持

          ECC 雙證書 要求 Nginx 1.11+

          這里 Nginx,我個人推薦 1.15+,因為 1.14 雖然已經能支持TLS1.3了,但是一些 TLS1.3 的進階特性還只在 1.15+ 中提供。

          然后我們定義一下版本號:

          # Version
          OpenSSLVersion='openssl-1.1.1a';
          nginxVersion='nginx-1.14.1';
          

          建議去官網隨時關注最新版:

          http://nginx.org/en/download.html

          https://www.openssl.org/source/

          https://github.com/eustas/ngx_brotli/releases

          Nginx

          cd /opt
          wget http://nginx.org/download/$nginxVersion.tar.gz
          tar xzf $nginxVersion.tar.gz
          

          OpenSSL

          cd /opt
          wget https://www.openssl.org/source/$OpenSSLVersion.tar.gz
          tar xzf $OpenSSLVersion.tar.gz
          

          Brotli

          cd /opt
          git clone https://github.com/eustas/ngx_brotli.git
          cd ngx_brotli
          git submodule update --init --recursive
          

          編譯

          cd /opt/$nginxVersion/
          ./configure \
          --prefix=/usr/local/nginx \ ## 編譯后安裝的目錄位置
          --with-openssl=/opt/$OpenSSLVersion \ ## 指定單獨編譯入 OpenSSL 的源碼位置
          --with-openssl-opt=enable-tls1_3 \ ## 開啟 TLS 1.3 支持
          --with-http_v2_module \ ## 開啟 HTTP/2 
          --with-http_ssl_module \ ## 開啟 HTTPS 支持
          --with-http_gzip_static_module \ ## 開啟 GZip 壓縮
          --add-module=/opt/ngx_brotli ## 編譯入 ngx_BroTli 擴展
          make && make install ## 編譯并安裝
          

          后續還有相關變量設置和設置服務、開啟啟動等步驟,篇幅限制就省略了,這篇文章有介紹在 Ubuntu 下的 Nginx 編譯:https://www.mf8.biz/ubuntu-nginx/ 。

          配置

          接下來我們需要修改配置文件。

          HTTP2

          listen 443 ssl http2;
          

          只要在 server{} 下的lisen 443 ssl 后添加 http2 即可。而且從 1.15 開始,只要寫了這一句話就不需要再寫 ssl on 了,很多小伙伴可能用了 1.15+ 以后衍用原配置文件會報錯,就是因為這一點。

          TLS 1.3

          ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
          

          如果不打算繼續支持 IE8,或者一些合規的要求,可以去掉TLSv1。

          然后我們再修改對應的加密算法,加入TLS1.3引入的新算法:

          ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
          

          如果不打算繼續支持 IE8,可以去掉包含 3DES 的 Cipher Suite。

          默認情況下 Nginx 因為安全原因,沒有開啟 TLS 1.3 0-RTT,可以通過添加 ssl_early_data on; 指令開啟 0-RTT的支持。

          ————

          實驗性嘗試

          眾所周知,TLS1.3 由于更新了很久,很多瀏覽器的舊版本依舊只支持 Draft 版本,如 23 26 28 分別在 Chrome、FirFox 上有支持,反而正式版由于草案出來很久,導致TLS1.3在瀏覽器上兼容性不少太好。

          可以使用 https://github.com/hakasenyang/openssl-patch/ 提供的 OpenSSL Patch 讓 OpenSSL 1.1.1 同時支持草案23,26,28和正式版輸出。 不過由于不是官方腳本,穩定性和安全性有待考量。

          ECC雙證書

          雙證書配置的很簡單了,保證域名的證書有RSA和ECC各一份即可。

           ##證書部分
           ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC證書
           ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密鑰
           ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA證書
           ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密鑰
          

          Brotli

          需要在對應配置文件中,添加下面代碼即可:

           brotli on;
           brotli_comp_level 6;
           brotli_min_length 1k;
           brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
          

          為了防止大家看糊涂了,放一個完整的 server{}供大家參考:

           server {
           listen 443 ssl http2; # 開啟 http/2
           server_name mf8.biz www.mf8.biz;
           
           #證書部分
           ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC證書
           ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密鑰
           ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA證書
           sl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密鑰
           
           #TLS 握手優化
           ssl_session_cache shared:SSL:1m;
           ssl_session_timeout 5m;
           keepalive_timeout 75s;
           keepalive_requests 100;
           
           #TLS 版本控制
           ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
           ssl_ciphers 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5';
           # 開啟 1.3 o-RTT
           ssl_early_data on;
           
           # GZip 和 Brotli
           gzip on;
           gzip_comp_level 6;
           gzip_min_length 1k;
           gzip_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
           brotli on;
           brotli_comp_level 6;
           brotli_min_length 1k;
           brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
           location / {
           root html;
           index index.html index.htm;
           }
           }
          

          先驗證一下配置文件是否有誤:

          nginx -t
          

          如果反饋的是:

          nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
          nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
          

          就可以重啟 Nginx ,然后到對應網站中去查看效果了。

          驗證

          HTTP/2

          通過瀏覽器的開發者工具,我們可以在 Network 欄目中看到 Protocol 中顯示 h2 有無來判斷。

          TLS 1.3

          老地方,我們可以通過瀏覽器的開發者工具 中的 Security 欄目看到 Connection 欄目下是否有顯示 TLS 1.3

          ECC 雙證書

          ECC 雙證書配置了以后無非就是在舊瀏覽器設別上的驗證了。這里用足夠老的上古XP虛擬機來給大家證明一波。

          XP系統上:

          現代操作系統上的:

          Brotli

          通過瀏覽器的開發者工具,我們可以在 Network 欄目中,打開具體頁面的頭信息,看到 accept-encoding 中有 br 字眼就行。

          總結

          通過上述手段應該可以讓 HTTPS 訪問的體驗優化不少,而且會比沒做 HTTPS 的網站訪問可能更快。

          這樣的模式比較適合云服務器單機或者簡單集群上搭建,如果有應用 SLB 七層代理、WAF、CDN 這樣的產品可能會讓我們的這些操作都白費。 我們的這幾項操作都是自建的 Web 七層服務,如果有設置 SLB 七層代理、WAF、CDN 這樣設置在云服務器之前就會被覆蓋掉。

          由于 SLB 七層和CDN這樣的產品會更加追求廣泛的兼容性和穩定性并不會第一時間就用上上述的這些新特性(HTTP/2 是普遍有的),但是他們都配備了阿里云的 Tengine 的外部專用算法加速硬件如 Intel? QuickAssist Technology(QAT) 加速器可以顯著提高SSL/TLS握手階段性能。 所有 HTTPS 的加密解密都在 SLB 或 CDN 上完成,而不會落到ECS上,可以顯著降低 ECS 的負載壓力,并且提升訪問體驗。

          目前云上的網絡產品中能支持四層的都是可以繼續兼容我們這套設計的,例如:SLB 的四層轉發(TCP UDP)、DDOS高防的四層轉發。

          作者:妙正灰

          ginx

          一 為什么要用Nginx?

          我們之前有分析過,單臺服務器可能會遇到的問題,比如服務器宕機,或者并發用戶太多,單臺服務器不夠等問題,所以需要集群架構,就是將項目部署到多臺服務器。

          但這樣會出現新的問題:

          1. 用戶發送的請求會被發送到哪臺服務器?
          2. 如果是有軟件幫助分發,怎么做到盡量均衡?

          對于這些問題的出現,我們可以用Nginx來解決,除此以外,Nginx還可以幫助我們區分動態服務器和靜態服務器。

          二 Nginx是什么?

          Nginx (engine x) 是一個高性能的Http服務器和反向代理web服務器,同時也提供了IMAP/POP3/SMTP服務。它可以用做反向代理服務器,郵件服務器,實現負載均衡和動靜分離。

          穩定性強、豐富的功能集、簡單的配置文件和低系統資源的消耗,占用內存少,并發能力強。

          中國大陸使用nginx網站用戶有:百度、京東、新浪、網易、騰訊、淘寶等。

          三 Nginx安裝和配置

          1.使用docker安裝Nginx

           docker pull daocloud.io/library/nginx:latest
          

           docker images
          

          docker run -d -p 80:80 --name nginx 29
          


          2.Nginx核心配置文件

          2.1 找到Nginx內部的配置文件

          先進入Nginx容器內部

          docker exec -it 容器id bash   #進入容器的終端,可以執行一些如ls pwd等一些簡單的shell命令
          

          再進入容器的etc/nginx目錄下:

          將nginx.conf文件的內容復制出來

          2.2 nginx.conf文件結構

          
          # 全局塊
          user  nginx;
          worker_processes  1;
          
          error_log  /var/log/nginx/error.log warn;
          pid        /var/run/nginx.pid;
          
          
          #events塊
          events {
              worker_connections  1024;
          }
          
          
          
          http {
              include       /etc/nginx/mime.types;
              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        on;
              #tcp_nopush     on;
          
              keepalive_timeout  65;
          
              #gzip  on;
          
              include /etc/nginx/conf.d/*.conf;
          }
          
          

          全局塊:

          從配置文件開始到 events 塊之間的內容,主要會設置一些影響nginx 服務器整體運行的配置指令,主要包括配置運行 Nginx 服務器的用戶(組)、允許生成的 worker process 數,進程 PID 存放路徑、日志存放路徑和類型以及配置文件的引入等。
          
          worker_processes  1   #這是 Nginx 服務器并發處理服務的關鍵配置,worker_processes 值越大,可以支持的并發處理量也越多,但是會受到硬件、軟件等設備的制約。
          

          events 塊:

          events 塊涉及的指令主要影響 Nginx 服務器與用戶的網絡連接,常用的設置包括是否開啟對多 work process 下的網絡連接進行序列化,是否允許同時接收多個網絡連接,選取哪種事件驅動模型來處理連接請求,每個 word process 可以同時支持的最大連接數等。 上述例子就表示每個 work process 支持的最大連接數為 1024. 這部分的配置對 Nginx 的性能影響較大,在實際中應該靈活配置。
          

          http塊:

          http模塊顧名思義,就是關于http服務請求的配置。這些配置包括http請求的文件類型(MIME-TYPE)的定義,http請求日志的輸出,http連接的超時時長,單連接請求上限的配置。
          

          http塊的最后一句#include /etc/nginx/conf.d/*.conf ,是指引入了conf.d目錄下的以.conf為結尾的配置文件。我們找到他們。

          default.conf內容如下:

          server {
              listen       80;
              listen  [::]:80;
              server_name  localhost;
          
              #charset koi8-r;
              #access_log  /var/log/nginx/host.access.log  main;
          
              location / {
                  root   /usr/share/nginx/html;
                  index  index.html index.htm;
              }
          
              #error_page  404              /404.html;
          
              # redirect server error pages to the static page /50x.html
              #
              error_page   500 502 503 504  /50x.html;
              location = /50x.html {
                  root   /usr/share/nginx/html;
              }
          
              # proxy the PHP scripts to Apache listening on 127.0.0.1:80
              #
              #location ~ \.php$ {
              #    proxy_pass   http://127.0.0.1;
              #}
          
              # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
              #
              #location ~ \.php$ {
              #    root           html;
              #    fastcgi_pass   127.0.0.1:9000;
              #    fastcgi_index  index.php;
              #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
              #    include        fastcgi_params;
              #}
          
              # deny access to .htaccess files, if Apache's document root
              # concurs with nginx's one
              #
              #location ~ /\.ht {
              #    deny  all;
              #}
          }
          
          

          去掉注釋部分

          server {
              listen       80;
              listen  [::]:80;
              server_name  localhost;
          
              location / {
                  root   /usr/share/nginx/html;
                  index  index.html index.htm;
              }
          
              error_page   500 502 503 504  /50x.html;
              location = /50x.html {
                  root   /usr/share/nginx/html;
              }
          
           
          }
          

          將其替換到nginx.conf文件中的include /etc/nginx/conf.d/*.conf,然后可以看到http塊的內容為:

          http {
              include       /etc/nginx/mime.types;
              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        on;
              #tcp_nopush     on;
          
              keepalive_timeout  65;
          
              #gzip  on;
          
              server {
                  listen       80;
                  listen  [::]:80;
                  server_name  localhost;
          
                  location / {
                      root   /usr/share/nginx/html;
                      index  index.html index.htm;
                  }
          
                  error_page   500 502 503 504  /50x.html;
                  location = /50x.html {
                      root   /usr/share/nginx/html;
                  }
          
           
             }
          }
          

          http塊結構包含:

          server塊: 每一個Server模塊就是一個獨立的虛擬主機,每個虛擬的主機可配置不同的域名或IP地址

          ?

          今天主要介紹nginx的模塊——ngx_http_proxy_module和ngx_http_upstream_module,嚴格來說,nginx自帶是沒有針對負載均衡后端節點的健康檢查的,但是可以通過默認自帶的ngx_http_proxy_module 模塊和ngx_http_upstream_module模塊中的相關指令來完成當后端節點出現故障時,自動切換到健康節點來提供訪問。


          01

          ngx_http_proxy_module

          反向代理( reverse proxy) 方式是指用代理服務器來接受 Internet 上的連接請求, 然后將請求轉發給內部網絡中的上游服務器, 并將從上游服務器上得到的結果返回給 Internet 上請求連接的客戶端, 此時代理服務器對外的表現就是一個 Web 服務器。 充當反向代理服務器也是 Nginx 的一種常見用法( 反向代理服務器必須能夠處理大量并發請求)。


          由于Nginx具有“強悍”的高并發高負載能力, 因此一般會作為前端的服務器直接向客戶端提供靜態文件服務。 但也有一些復雜、 多變的業務不適合放到 Nginx 服務器上, 這時會用Apache、 Tomcat 等服務器來處理。 于是, Nginx 通常會被配置為既是靜態Web服務器也是反向代理服務器( 如下圖所示), 不適合Nginx處理的請求就會直接轉發到上游服務器中處理。

          ngx_http_proxy_module模塊允許傳送請求到其它服務器,也就是做反向代理。下面提供一個基本的配置示例:

          location / {
            root /usr/share/nginx/html;
            proxy_redirect default;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout 2;
            proxy_send_timeout 5;
            proxy_read_timeout 5;
            proxy_buffer_size 256k;
            proxy_buffers 4 256k;
            proxy_busy_buffers_size 256k;
            proxy_pass http://127.0.0.1:80;
          }
          

          ngx_http_proxy_module模塊常用指令解釋:

          1)proxy_bind

          Syntax: proxy_bind address [transparent] | off;
          Default: —
          Context: http, server, location
          This directive appeared in version 0.8.22.
          


          在調用connect()前將上游socket綁定到一個本地地址,如果主機有多個網絡接口或別名,但是你希望代理的連接通過指定的接口或地址,可以使用這個指令。

          透明傳輸模式允許傳出連接到代理服務器起源于一個非本地IP地址,例如,從一個真實的IP地址的客戶端 ︰

          proxy_bind $remote_addr transparent;
          

          為了使此參數工作,就必須以超級用戶的特權運行nginx的工作進程和配置內核路由表攔截來自代理服務器的網絡流量。

          2)proxy_buffer_size

          Syntax: proxy_buffer_size size;
          Default:proxy_buffer_size 4k|8k;
          Context:http, server, location
          

          設置緩沖區的大小為size,nginx從被代理的服務器讀取響應時,使用該緩沖區保存響應的開始部分。這部分通常包含著一個小小的響應頭。該緩沖區大小默認等于proxy_buffers指令設置的一塊緩沖區的大小,但它也可以被設置得更小。

          3)proxy_buffers

          Syntax: proxy_buffers number size;
          Default:proxy_buffers 8 4k|8k;
          Context:http, server, location
          

          設置用于讀取應答(來自被代理服務器)的緩沖區數目和大小,為每個連接設置緩沖區的數量是number參數,每塊緩沖區的大小是size參數。這些緩沖區用于保存從被代理的服務器讀取的響應。每塊緩沖區默認等于一個內存頁的大小。這個值默認是4K還是8K,取決于平臺。

          4)proxy_buffering

          Syntax: proxy_buffering on | off;
          Default:proxy_buffering on;
          Context:http, server, location
          

          代理的時候,開啟或關閉緩沖后端服務器的響應。

          當開啟緩沖時,nginx盡可能快地從被代理的服務器接收響應,再將它存入proxy_buffer_size和proxy_buffers指令設置的緩沖區中。

          如果響應無法整個納入內存,那么其中一部分將存入磁盤上的臨時文件。proxy_max_temp_file_size和proxy_temp_file_write_size指令可以控制臨時文件的寫入。

          當關閉緩沖時,收到響應后,nginx立即將其同步傳給客戶端。nginx不會嘗試從被代理的服務器讀取整個請求,而是將proxy_buffer_size指令設定的大小作為一次讀取的最大長度。

          響應頭“X-Accel-Buffering”傳遞“yes”或“no”可以動態地開啟或關閉代理的緩沖功能。 這個能力可以通過proxy_ignore_headers指令關閉。

          5)proxy_busy_buffers_size

          Syntax: proxy_busy_buffers_size size;
          Default:proxy_busy_buffers_size 8k|16k;
          Context:http, server, location
          

          當開啟緩沖響應的功能以后,在沒有讀到全部響應的情況下,寫緩沖到達一定大小時,nginx一定會向客戶端發送響應,直到緩沖小于此值。

          這條指令用來設置此值。 同時,剩余的緩沖區可以用于接收響應,如果需要,一部分內容將緩沖到臨時文件。該大小默認是proxy_buffer_size和proxy_buffers指令設置單塊緩沖大小的兩倍。

          6)proxy_max_temp_file

          Syntax: proxy_max_temp_file_size size;
          Default:proxy_max_temp_file_size 1024m;
          Context:http, server, location
          

          打開響應緩沖以后,如果整個響應不能存放在proxy_buffer_size和proxy_buffers指令設置的緩沖區內,部分響應可以存放在臨時文件中。 這條指令可以設置臨時文件的最大容量。

          而每次寫入臨時文件的數據量則由proxy_temp_file_write_size指令定義。

          將此值設置為0將禁止響應寫入臨時文件。

          7)proxy_temp_file_write_size

          Syntax: proxy_temp_file_write_size size;
          Default:proxy_temp_file_write_size 8k|16k;
          Context:http, server, location
          

          在開啟緩沖后端服務器響應到臨時文件的功能后,設置nginx每次寫數據到臨時文件的size(大小)限制。 size的默認值是proxy_buffer_size指令和proxy_buffers指令定義的每塊緩沖區大小的兩倍, 而臨時文件最大容量由 proxy_max_temp_file_size指令設置。

          8)proxy_temp_path

          Syntax: proxy_temp_path path [level1 [level2 [level3]]];
          Default:proxy_temp_path proxy_temp;
          Context:http, server, location
          

          定義從后端服務器接收的臨時文件的存放路徑,可以為臨時文件路徑定義至多三層子目錄的目錄樹。 比如,下面配置

          proxy_temp_path /spool/nginx/proxy_temp 1 2;  
          

          那么臨時文件的路徑看起來會是這樣:

          /spool/nginx/proxy_temp/7/45/00000123457
          

          9)proxy_connect_timeout

          Syntax: proxy_connect_timeout time;
          Default:proxy_connect_timeout 60s;
          Context:http, server, location
          

          設置與后端服務器建立連接的超時時間,應該注意這個超時一般不可能大于75秒。默認為60s,建議生產環境連接時間設置為1到2s。

          10)proxy_http_version

          Syntax: proxy_http_version 1.0 | 1.1;
          Default:proxy_http_version 1.0;
          Context:http, server, location
          This directive appeared in version 1.1.4.
          

          設置代理使用的HTTP協議版本,默認使用的版本是1.0,而1.1版本則推薦在使用keepalive連接時一起使用。我接觸的生產環境中都是設置http 1.1版本了。

          11)proxy_ignore_client_abort

          Syntax: proxy_ignore_client_abort on | off;
          Default:proxy_ignore_client_abort off;
          Context:http, server, location
          

          決定當客戶端在響應傳輸完成前就關閉連接時,nginx是否應關閉后端連接。

          12)proxy_pass

          Syntax: proxy_pass URL;
          Default:—
          Context:location, if in location, limit_except
          

          設置后端服務器的協議和地址,還可以設置可選的URI以定義本地路徑和后端服務器的映射關系。 這條指令可以設置的協議是“http”或者“https”,而地址既可以使用域名或者IP地址加端口(可選)的形式來定義:

          proxy_pass http://localhost:8000/uri/;
          

          對于URI可選,一般情況下使用是不需要指定的,除非你需要的訪問方式就是這樣的。

          也可以使用UNIX域套接字路徑來定義,該路徑接在“unix”字符串后面,兩端由冒號所包圍,比如:

          proxy_pass http://unix:/tmp/backend.socket:/uri/;
          

          如果proxy_pass沒有使用URI,傳送到后端服務器的請求URI一般客戶端發起的原始URI,如果nginx改變了請求URI,則傳送的URI是nginx改變以后的完整規范化URI:

          location /path/ {
            proxy_pass http://127.0.0.1;
          }
          

          虛擬路徑代理就是,比如說訪問”http://127.0.0.1/path/uri”地址,當匹配到這個location之后,通過”proxy_pass http://127.0.0.1/”代理到后端時,一個新的URL就成了”http://127.0.0.1/uri”這樣。

          其中的/path就稱為虛擬路徑,虛擬給用戶的,后端沒有真正的/path路徑,這里要特別注意”proxy_pass http://127.0.0.1/”最后的”/”,如果沒有這個”/”那么訪問就會出現404,因為你沒有給proxy_pass定義URI,所以不存在將規范化以后的請求路徑(原始請求URI)與location配置中的路徑的匹配部分將被替換為proxy_pass指令中定義的URI這一說法,切記。Nginx實現虛擬路徑代理

          注意

          當使用一個正則表達式(~或~*)指定localtion時,在這種情況下,proxy_pass應該是一個沒有URI的指令,如果指定了URI,那么代理到后端時,URI會被去掉,從而變成了http://127.0.0.1/some/path,也就是說原始訪問URI不會做任何改變傳送到后端。

          還有一種情況,當URI使用rwrite重寫指令后,在這種情況下,proxy_pass應該是一個沒有URI的指令,如果指定了URI,那么代理到后端時,URI會被去掉,從而變成了http://127.0.0.1/some/path。

          rewrite /name/([^/]+) /users?name=$1 break;
          

          最后,這種以代理的工作方式,一般都會使用到Nginx upstream,以此來做負載均衡。這種情況下直接給定一個upstream的名稱即可(需要先定義一個upstream),如下:

          location / {
          upstream test{
          127.0.0.1:80;
          }
          proxy_pass http://test;
          }
          


          13)proxy_next_upstream

          Syntax: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | 
          http_403 | http_404 | non_idempotent | off ...;
          Default:proxy_next_upstream error timeout;
          Context:http, server, location
          

          當你使用Nginx proxy代理時,如果是代理到后端是使用upstream,那么這個指令就是指定在何種情況下,一個失敗的請求應該被發送到下一臺后端服務器,有如下指令:

          error – 和后端服務器建立連接時,或者向后端服務器發送請求時,或者從后端服務器讀取響應時,出現錯誤;

          timeout – 和后端服務器建立連接時,或者向后端服務器發送請求時,或者從后端服務器讀取響應時,出現超時;

          invalid_header – 后端服務器返回空響應或者非法響應頭;

          http_500 – 后端服務器返回的響應狀態碼為500;

          http_502 – 后端服務器返回的響應狀態碼為502;

          http_503 – 后端服務器返回的響應狀態碼為503;

          http_504 – 后端服務器返回的響應狀態碼為504;

          http_404 – 后端服務器返回的響應狀態碼為404;

          off – 關閉proxy_next_upstream功能—出錯就選擇另一臺上游服務器再次轉發。

          需要理解一點的是,只有在沒有向客戶端發送任何數據以前,將請求轉給下一臺后端服務器才是可行的。也就是說,如果在傳輸響應到客戶端時出現錯誤或者超時,這類錯誤是不可能恢復的。

          另外Nginx1.7開始提供了將請求傳遞給下一臺服務器可以通過重試的次數和時間進行限制。

          14)proxy_next_upstream_timeout

          Syntax: proxy_next_upstream_timeout time;
          Default:proxy_next_upstream_timeout 0;
          Context:http, server, location
          This directive appeared in version 1.7.5.
          

          限制了重試請求可以被傳遞給下一臺服務器的時間,默認值為0將關閉這一限制。

          15)proxy_next_upstream_tries

          Syntax: proxy_next_upstream_tries number;
          Default:proxy_next_upstream_tries 0;
          Context:http, server, location
          This directive appeared in version 1.7.5.
          

          限制了重試請求可以被傳遞給下一臺服務器的次數,默認值為0將關閉這一限制。

          16)proxy_read_timeout

          Syntax: proxy_read_timeout time;
          Default:proxy_read_timeout 60s;
          Context:http, server, location
          

          定義從后端服務器讀取(接收)數據的超時時間(Nginx從客戶端接收到請求,然后把數據包轉發到后端服務器,后端服務器處理完請求后返回給Nginx服務器,Nginx接收后端數據包稱為一次read),此超時是指相鄰兩次讀操作之間的最長時間間隔,而不是整個響應傳輸完成的最長時間。如果后端服務器在超時時間段內沒有傳輸任何數據,連接將被關閉。默認時間為60s,建議值為2-4s。

          17)proxy_send_timeout

          Syntax: proxy_send_timeout time;
          Default:proxy_send_timeout 60s;
          Context:http, server, location
          

          定義向后端服務器發送一次數據包的超時時間(Nginx從客戶端接收到請求,然后把數據包轉發到后端服務器稱為一次send),此超時是指相鄰兩次寫操作之間的最長時間間隔,而不是整個請求傳輸完成的最長時間。

          如果再向后端服務器發送數據包時,超過了超時時間的設置,那么連接將被關閉。默認時間為60s,建議值為2-4s。

          18)proxy_set_header

          Syntax: proxy_set_header field value;
          Default:proxy_set_header Host $proxy_host;
          proxy_set_header Connection close;
          Context:http, server, location
          

          允許重新定義或者添加發往后端服務器的請求頭。value可以包含文本、變量或者它們的組合。 當且僅當當前配置級別中沒有定義proxy_set_header指令時,會從上面的級別繼承配置。 默認情況下,只有兩個請求頭會被重新定義:

          proxy_set_header Host $proxy_host;
          proxy_set_header Connection close;
          

          如果不想改變請求頭“Host”的值,可以這樣來設置:

          proxy_set_header Host $http_host;
          

          但是,如果客戶端請求頭中沒有攜帶這個頭部,那么傳遞到后端服務器的請求也不含這個頭部。 這種情況下,更好的方式是使用$host變量——它的值在請求包含“Host”請求頭時為“Host”字段的值,在請求未攜帶“Host”請求頭時為虛擬主機的主域名:

          proxy_set_header Host $host;
          


          此外,服務器名可以和后端服務器的端口一起傳送:

          proxy_set_header Host $host:$proxy_port;
          


          如果某個請求頭的值為空,那么這個請求頭將不會傳送給后端服務器:

          proxy_set_header Accept-Encoding "";
          


          proxy_add_x_forwarded_for內置變量,將proxy_add_x_forwarded_for內置變量,將remote_addr變量值添加在客戶端“X-Forwarded-For”請求頭的后面,并以逗號分隔。

          如果客戶端請求未攜帶“X-Forwarded-For”請求頭,proxy_add_x_forwarded_for變量值將與proxy_add_x_forwarded_for變量值將與remote_addr變量相同。

          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          


          19)proxy_pass_header

          Syntax: proxy_pass_header field;
          Default:—
          Context:http, server, location
          


          允許指定跳過某些字段從代理服務器到客戶端,一般用在CDN中傳回來的字段信息,但不需要傳回到后端服務器,就可以使用proxy_pass_header指令跳過。

          20)proxy_redirect

          Syntax: proxy_redirect default;
          proxy_redirect off;
          proxy_redirect redirect replacement;
          Default:proxy_redirect default;
          Context:http, server, location
          

          設置后端服務器“Location”響應頭和“Refresh”響應頭的替換文本。 假設后端服務器返回的響應頭是 “Location: http://localhost:8000/two/some/uri/”,那么指令

          proxy_redirect http://localhost:8000/two/ http://frontend/one/;
          

          將把字符串改寫為 “Location: http://frontend/one/some/uri/”。


          02

          ngx_http_upstream_module

          實例

          upstream appservers { 
           zone appservers 64k; 
           #默認權重為1
           server appserv1.example.com weight=5; 
           server appserv2.example.com:8080 fail_timeout=5s slow_start=30s; 
           server 192.0.2.1 max_fails=3; 
           
           server reserve1.example.com:8080 backup; 
           server reserve2.example.com:8080 backup; 
          } 
           
          server { 
           location / { 
           proxy_pass http://appservers; 
           health_check; 
           } 
           
           location /upstream_conf { 
           upstream_conf; 
           allow 127.0.0.1; 
           deny all; 
           } 
          } 
          

          參數解釋:

          1.weight=number

          設定服務器的權重,默認是1。

          2.max_fails=number

          設定Nginx與服務器通信的嘗試失敗的次數。

          3.fail_timeout=time

          設定

          • 統計失敗嘗試次數的時間段。在這段時間中,服務器失敗次數達到指定的嘗試次數,服務器就被認為不可用。
          • 服務器被認為不可用的時間段。

          默認情況下,該超時時間是10秒。backup標記為備用服務器。當主服務器不可用以后,請求會被傳給這些服務器。

          4.down

          標記服務器永久不可用,可以跟ip_hash指令一起使用。

          5.route=string

          設置服務器路由名稱。


          后面會分享更多devops和DBA方面的內容,感興趣的朋友可以關注一下~


          主站蜘蛛池模板: 国产精品视频分类一区| 福利国产微拍广场一区视频在线| 亚洲一区二区三区在线播放| 日韩毛片基地一区二区三区| 免费无码一区二区| 一区二区视频在线| 无码乱人伦一区二区亚洲| 视频一区精品自拍| 丝袜无码一区二区三区| 波多野结衣一区在线观看| 麻豆aⅴ精品无码一区二区| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 国模无码一区二区三区不卡| 亚洲熟妇av一区| 国产免费一区二区三区| 最新中文字幕一区| 伊人久久大香线蕉av一区| 国产人妖视频一区二区破除| 亚洲国产综合无码一区二区二三区 | 成人在线视频一区| 亚洲V无码一区二区三区四区观看 亚洲爆乳精品无码一区二区三区 亚洲爆乳无码一区二区三区 | 国产福利电影一区二区三区久久久久成人精品综合 | 亚洲国产成人久久综合一区 | 日本福利一区二区| 精品一区二区三区免费 | 无遮挡免费一区二区三区| 亚欧免费视频一区二区三区| 一区二区三区高清在线 | 视频一区二区三区免费观看| 亚洲国产精品自在线一区二区| 亚洲日韩中文字幕一区| 曰韩精品无码一区二区三区| 无码日韩AV一区二区三区| 末成年女AV片一区二区| 精品国产AⅤ一区二区三区4区| 午夜AV内射一区二区三区红桃视| 国产成人精品无码一区二区三区| 精品国产一区在线观看| 亚洲夜夜欢A∨一区二区三区| 中文人妻av高清一区二区| 伊人久久精品一区二区三区 |