如何入門掌握Nginx?

前言:因爲抱着對Nginx的好奇心,決心把近期的我的學習主題定爲了Nginx的入門學習。學習的內容大概就是學習極客時間,陶輝老師出品的《Nginx核心知識100講》。再配合本身業務場景中的幾個實戰,得出的些許經驗在此分享給你們。在文章中有很多截圖是直接截課程中老師的ppt部分進行整理的(侵權即刪,我再另做圖)。—— 注意,這是教徹底沒概念的小白如何入門。若是已經瞭解過的能夠直接關閉退出,不要浪費時間html

簡單入門Nginx

自定義編譯構建Nginx

通常來講,若是沒有特殊需求。Nginx的構建能夠直接依賴yum install nginx或者brew install nginx就安裝啓動起來,很是舒服。可是當你須要添加一些模塊、加一些默認不編譯進Nginx的功能、熱更新以及等等等等操做時,就會又須要從新學會自定義編譯構建。再加上自定義構建其實並無想象中困難,且易於後續的繼續深刻學習,因此個人建議是要學會這個簡單的自定義構建方式。linux

獲取編譯源文件

打開Nginx的官網,直接找到Download標籤下下載相應的二進制文件。而後直接下載,或者使用wget 文件路徑進行下載。通常穩妥起見都是直接選擇Mainline版本便可nginx

開始編譯安裝

將下載下來的壓縮包進行解壓tar -xzvf nginx-1.15.12.tar.gz.解壓完成後就能看到相似這樣的文件目錄.web

通常來講咱們不須要關心這個目錄的內容,可是有興趣的能夠稍做了解,進階的時候會用獲得。正則表達式

nginx-1.15.12/
├── auto 
|   ├── cc 用於編譯
|   ├── lib
|   ├── os 操做系統的判斷
|   ├── ... 其餘內容都是爲了支持config文件斷定nginx是否支持特性、模塊等
├── CHANGES 版本的特性以及bug修復狀況重構等的概覽
├── conf 示例文件
├── configure 腳本,生成中間文件,執行變編譯前的必備操做.可使用`./configure --help`查看支持參數
├── contrib 提供兩個.pl腳本和vim的工具
|   ├── vim 能夠執行`cp -r contrib/vim/* ~/.vim/` 來支持vim的nginx語法
├── html 提供兩個標準的HTML
|   ├── 50x.html 發生500錯誤時的展現文件
|   ├── index.html 歡迎界面
├── man linux對於nginx的幫助文件
├── src nginx的源代碼
├── objs configure編譯時生成的中間文件
|   ├── ngx_modules.c 決定了編譯時(make),會被編譯進nginx的模塊.能夠用於查看該nginx共編譯了什麼模塊進去
|   ├── nginx
|         ├── src `C語音`編譯時生成的全部文件
|         ├── so 若是使用動態模塊的文件
複製代碼

編譯的過程,咱們通常都是依賴configure文件提供的指令進行,很是簡單。執行./configure --help能夠查看執行的參數,自定義構建方式。好比,因爲權限緣由,我無法將nginx安裝到系統的默認目錄/etc/nginx/...,這時候我須要自定義編譯安裝的目錄能夠這樣操做vim

執行會校驗模塊等的內容,並生成objs編譯中間文件,經過裏面的ngx_modules.c文件能夠快捷地查看到該nginx所支持的功能特性。若是沒有更多的報錯,就能夠執行make以及make install進行安裝了。期間若是發生報錯,通常都能很簡便地從各大搜索引擎中找到相應的解決方案。api

編譯完成後,咱們的操做更多就是在編譯安裝的那個nginx下了。你也能夠看到相應的文件目錄結構大抵如此,若是是直接經過yum install的目錄結構應該是會有些許不一樣的。bash

大部分文件夾我也是沒有接觸的,這裏介紹幾個關鍵的文件:websocket

  • sbin:存放着Nginx的命令行指令。能夠將裏面的執行文件軟鏈或者直接經過./sbin/nginx + 指令執行
  • logs: 顧名思義存放着日誌文件
  • conf: Nginx的配置文件夾,經過裏面的配置來告訴Nginx該如何工做(咱們的主要工做目錄)

通常到這裏後執行,./sbin/nginx -s便可啓動nginx開始愉快地玩耍了。cookie

Nginx的配置語法

不知道個人理解會不會有所誤差,Nginx的實現其實就是在使用各個模塊提供的方法指令來指導Nginx的工做,因此學會它的基本配置語法天然是相當重要的。這裏直接貼出語法實例圖,你們能夠經過實際的語法文件以及每一個小箭頭的註釋來了解一個配置文件大抵由什麼部分組成,就不細說了。

1998176F-2824-48C7-8913-F644B924D6DF.png

Nginx的指令

指令部分也是很是簡單,通常用於中止、重啓等等。

  1. 格式: nginx -s reolad
  2. 幫助: -? 或 -h
  3. 使用指定的配置文件: -c
  4. 指定配置指令: -g 覆寫配置文件中的配置項
  5. 指定運行目錄: -p 一樣是覆寫配置文件中的運行目錄
  6. 發送信號: -s
    1. 馬上中止服務:stop;
    2. 優雅的中止服務: quit;
    3. 重載配置文件: reload;——修改配置文件中的值後要另其生效(不中止服務)
    4. 從新開始記錄日誌文件: reopen;
  7. 測試配置文件是否有語法錯誤: -t 或 -T
  8. 打印nginx的版本信息、編譯信息等: -v 或 -V

Nginx的文檔基本閱讀和搜索方法

全文的思路一致貫穿下來的思想就是,前期學習Nginx的過程就是學習其配置。那麼第一件事,就是要了解Nginx給咱們提供了什麼樣的功能以及咱們應該要怎樣合理合法正確地去使用它。

我通常的思路大概是如此,首先,打開你的最心儀的搜索引擎。

image-20190508202107944-7318067.png

通常來講,若是你的需求是比較廣泛的,在排名前幾的教程文章中你就能搜到你想要的內容。

固然與此同時,我還會根據本身的需求,找到Nginx官方文檔中的模塊介紹去閱讀更加科學的指令指導。每個模塊的介紹中都會包含如下三個方面:

  • Example Configuration 示例
  • Directives 全部指令的相關介紹
  • Embedded Variables 模塊提供的變量

其中,咱們着重瞭解一下指令的文檔該如何閱讀

image-20190508202738735.png

每部份內容都會標明指令名稱和支持的參數以及默認值。剩餘的內容都是描述這個指令的做用功能。每每當咱們懷疑這個指令的使用方式或者功效時,便可在此查閱到完美的解讀(畢竟其餘教程在通過消化後的知識可能會省略掉不少細節)

ps: 官網有時候還能找到一些比較常見的配置教程(好比websocket如何配置等等,很是值得閱讀)

Nginx掌握debug日誌調試方法

在我初學Nginx的時候,經常由於苦於沒有辦法像js那樣打斷點、加console.log而苦惱不已,直到我發現了開啓debug日誌的方法,麻麻不再用擔憂我不知道本身哪裏配置錯了。

開啓debug的方法其實也很簡單,在官網中也能找到相應的示例:A Debugging log

開啓的方法要回歸到咱們上面提到的自定義編譯構建,在編譯時添加一行參數,開啓debug模式

./configure --with-debug
複製代碼

以後一樣是執行編譯安裝後,在相應想要打印錯誤日誌的地方進行相應的配置.

error_log /path/to/log debug
複製代碼

以後重啓nginx後即可以生效了。固然官網中其實有提供更加詳細的說明,建議閱讀相應的文章進一步瞭解。

須要掌握的重要知識點

掌握了上面的基礎知識,基本上就已經具有了配置Nginx的基本能力,基於下面的路徑基本能把百分之50%的需求簡單解決(我我的的感受)

可是其實在配置中Nginx仍是有很多坑,也或者說有幾個特別重要的知識點,若是沒有掌握可能會在配置的過程當中讓你痛不欲生。下面,一個一個知識點過,固然若是直接買課程聽陶輝老師講,那確定是要深刻不少.這裏,我只是從自身的角度出發來衡量知識點的重要性。Let’s go!!

指令合併與繼承

指令的合併

Nginx的指令能夠分爲:值指令和動做類指令

  • 值指令:存儲配置項的值,能夠合併。例如:rootgizp
  • 動做類指令:指定行爲,不能夠合併。例如:rewriteproxy_pass

指令的繼承

  • 子配置不存在時,直接使用父配置塊
  • 子配置存在時,直接覆蓋父配置塊

Server的匹配順序

當配置多個server配置塊且匹配邏輯複雜,極有可能一個請求進來同時命中多個server塊時,須要參考一下的優先級順序來判斷進入哪一個Server塊進行執行。

  1. 精確匹配
  2. *在前的泛域名
  3. *在後的泛域名
  4. 按文件中的順序匹配正則表達式域名
  5. default server
    1. 第一個
    2. Listen 指定 default

Location指令 [ location [= | ~ | ~* | ^~] uri { … } 或 location @name { ... } ]

Location指令要掌握的內容其實大致和Server一致,也是匹配順序的問題。不過有一個小細節值得注意的是Location僅匹配URI,忽略參數

image-20190509105518688-7370518.png

邪惡的If指令

當if指令塊連續出現時,最後一個爲真的if指令塊將一直影響後續的處理。一般不使用連續的if,特別是連續爲true的狀況下會形成誤解。

形成錯誤的緣由

  1. if指令在rewrite階段執行
  2. if {} 塊中的配置,會在if條件爲真時,替換當前請求的配置。
    1. if {} 一樣向上繼承父配置
    2. 當rewrite接口順序執行時,每次if爲真都會替換當前請求的配置
  3. if {} 中的配置,會影響rewrite接口以後的階段執行。
location /only-one-if {
	set $true 1;
	// 不生效
	if ($true) {
	  add_headder X-First 1;
	}
	// 生效的模塊
	if ($true) {
		 add_header X-Second 2;
	}
	return 204;
}
複製代碼

因此,if 指令塊中要確保能夠正確處理請求,不依賴if {}塊外的指令。固然還可使用break阻斷後續rewrite階段的指令執行。

Rewrite模塊:Return和Rewrite的區別

return指令

命令Nginx中止處理,直接返回重定向到客戶端。return指令簡潔有效,相比之下,return的使用優先級高於rewrite。

rewrite指令

rewrite 規則會改變部分或整個用戶請求中的 URL,主要有兩個用途:

  • 類似於return的指令,經過直接返回http://
  • 控制Nginx的處理流程

在rewrite指令中,有一項falg的標誌位,比較重要的有兩個:

  • last: 中止處理當前的 ngx_http_rewrite_module 指令集,並開始對匹配更改後的 URI 的新 location 進行搜索(再從 server 走一遍匹配流程)。此時對於當前 serverlocation 上下文,再也不處理 ngx_http_rewrite_module 重寫模塊的指令。

  • break: 中止處理當前的 ngx_http_rewrite_module 指令集

lastbreak的異同:

  • last 重寫 url 後,會再從 server 走一遍匹配流程,而 break 終止重寫後的匹配
  • break 和 last 都能阻止後面的 rewrite 指令再次執行

變量

Nginx的變量有很是多的用處,可是在使用過程當中咱們也務必掌握下面兩個知識點,很是簡單。

  • 變量的惰性求值。相信這個概念你們都不陌生了,也就是變量只有在被使用的那一刻纔會執行「解析出變量的方法」。這至關於提升性能的一個方法。
  • 變量值能夠爲時刻變化,其值爲使用那一刻的值——變量的惰性求值而帶來的一個做用。也就是變量名在Nginx啓動之初即已經定義好,可是倘若在可以獲取到相應值以前的階段使用該變量,那麼顯而易見地只能獲取到一個空值。亦或是在後續階段假若變量被改變,也不能響應回前面的執行步驟。

有關變量變化須要更深刻地去掌握Nginx的運行機制和執行步驟方可更加深刻理解。

實踐

單域名反向代理支持多套應用服務

需求場景: 只提供單域名,而後須要根據路徑前綴反向到具體的應用服務上。

難點:

  • 路由配置反向代理都是很簡單的。難點在於應用服務並不知道本身被反向代理了,在獲取資源內容或者是發起API請求的時候會用相似這樣的URI路徑:www.myapp.com/public/xxxxx或者www.myapp.com/api/xxxx/.對於這種通用的請求,可能每套服務上都會被用到,而咱們是不便於去找回它的源請求位置的(不但願改動應用層的代碼)

實現思路:

  1. 對於剛進入的服務會進行location的匹配。而在相應的location指令塊中,咱們會設置相應的服務cookie值——標識該請求的目標源應用。location中能夠設置重定義cookie的值,若是沒有被重定義那麼則是採用cookie中的反向代理服務。
  2. 因爲單頁面應用若是使用history模式,單頁面的路徑跳轉可能改寫路徑(並不通過nginx)。因此nginx沒有時機去重寫它的請求URL,在刷新頁面時爲了方便除了開發人員去查看當前所處系統,須要時刻注意去使用rewrite指令重寫URL的內容。

nginx.png

直接看代碼吧~

http {
  # 避免超時的相關操做
  fastcgi_connect_timeout 3600;
  fastcgi_send_timeout 3600;
  fastcgi_read_timeout 3600;
  proxy_connect_timeout 3600;
  proxy_send_timeout 3600;
  proxy_read_timeout 3600;
  
  upstream see_test {
     server 127.0.0.1:9501;
  }

  upstream see_poc_fjnx {
     server 127.0.0.1:9502;
  }
  
  server {
    listen 8890 default_server;
    server_name  www.myapp.com;
    
    if ($http_cookie ~* "prefix_url=see_poc_fjnx") {
        set $group see_poc_fjnx;
    }
    if ($http_cookie ~* "prefix_url=see_test") {
        set $group see_test;
    }
    
    location /public {
        proxy_pass http://$group;
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
    }

    location /api {
        proxy_pass http://$group;
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
    }
    

    location /poc/fjnx/ {
        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_pass http://see_poc_fjnx/;
        proxy_redirect / http://http://www.myapp.com/poc/fjnx/;
        userid on;
        userid_name prefix_url=see_poc_fjnx;
        userid_mark =;
        userid_service 1;
    }
    
    location / {
      if ($group = see_poc_fjnx) {
          rewrite ^/(.+) http://www.myapp.com/poc/fjnx/$1 last;
      }

       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_pass http://see_test/;
       proxy_redirect / http://www.myapp.com/;
       userid on;
       userid_name prefix_url=see_test;
       userid_mark =;
       userid_service 1;
    }
  }
}
複製代碼

後續:其實整篇文章邏輯比較細碎和零散,對於對Nginx已經有必定了解的同窗並不適用。同時若是有了必定實踐經驗,想要更加深刻了解Nginx的話的確推薦極客時間的這門課程。


參考文檔

相關文章
相關標籤/搜索