Nginx -- Web服務器

歷史:2004年俄羅斯人 伊戈爾·賽索耶夫 發布Nginx
官網:http://nginx.org/
第三方模塊:https://www.nginx.com/resources/wiki/modules/index.html

概念
正向代理:客戶端訪問服務器地址,本地的代理模塊會把請求改造成訪問代理的地址,通過代理訪問實際的服務器
反向代理:客戶端訪問代理的地址,通過代理訪問實際的服務器
Nagle算法:將要發送的數據存放在緩存里,當積累到一定量或一定時間,再將它們發送出去
Lua:一種輕量小巧的腳本語言
URI:Uniform Resource Identifier,統一資源標識符,標識一個資源,例如 cay@horstman.com
URL:Uniform Resource Locator,統一資源定位符,定位一個資源,例如http://www.test.com/index.html,是URI的子集

Nginx作為LB 與 HAProxy對比
1、Nginx除了LB 還有 Web 服務器功能
2、HAProxy是單進程,Nginx是多進程,可以利用多核
3、Nginx社區更活躍

Nginx作為Web服務器 與 Apache HTTP Server 對比
1、Nginx輕量級,占用資源少
2、Apache是同步多進程模型,一個連接對應一個進程;Nginx是異步多進程模式,多個連接對應一個進程,支持更多的并發連接
3、Nginx處理靜態文件效率高
4、Nginx 配置簡潔

CentOs安裝:yum install epel-release; yum install nginx
Ubuntu安裝:apt-get update; apt-get install nginx
tar.gz安裝

tar -zxvf nginx.tar.gz
./configure --without-http_rewrite_module --without-http_gzip_module  # 配置,不聯網時忽略rewrite 和 gzip 模塊
make
make install   # 會提示所安裝的目錄
./sbin/nginx  # 在nginx 安裝目錄里 執行啟動

啟停:
service nginx start|restart|stop
nginx -s reload|reopen|stop|quit
配置文件檢查:nginx -t

配置

/etc/conf/nginx.conf

user nginx;                       # worker進程所屬的用戶組
worker_processes auto;  # worker進程數量
error_log /var/log/nginx/error.log;  # 錯誤日志
pid /run/nginx.pid;            # 記錄主進程ID的文件

include /usr/share/nginx/modules/*.conf;  # 引入其他配置文件

events {
    worker_connections 1024;    # 一個worker的最大連接數
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    # $upstream_addr 上游地址
    access_log  /var/log/nginx/access.log  main;   # 訪問日志 路徑 和 格式
    # access_log off; # 關閉訪問日志

    sendfile            on;                    # 把文件數據從磁盤直接傳到套接字,不經過buffer
    tcp_nopush          on;               # 啟用套接字TCP_CORK選項,即sendfile時盡可能一次發完
    tcp_nodelay         on;               # 禁用Nagle算法
    keepalive_timeout   65;           # 在響應頭中設置keepalive
    types_hash_max_size 2048;
    client_max_body_size   20m;  # 最大上傳量,也可以放在server{} 或  location{} 里

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

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

    server {     # 一個虛擬服務器
        listen       80 default_server;   # default_server表示對80端口的請求,任何 server_name都不匹配時,選用這個server
        listen       [::]:80 default_server;  # 監聽IPv6的80端口
        server_name  www.test.com;     # 這個server綁定的域名
        root         /usr/share/nginx/html;  # 靜態文件根目錄,不設置root,則默認為 /usr/share/nginx/html

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

       if ($scheme = http) {
            return 301 https://$server_name$request_uri;  # 將http重定向到https,要寫在監聽80端口的server{}下
        }
        location ^~ /static/ {  
            ## 通過 expires 設置 Expires 和 Cache-Control 兩個字段,指導瀏覽器進行緩存驗證
            expires 24h;   # 緩存,緩存有效期內不進行服務器端驗證
            expires  max; # 使得 Expires 和 Cache-Control 為 10 年
            expires -1s; 或 epoch; # 使得 Cache-Control 為 no-cache,緩存,但緩存過期,進行服務端驗證
            ## 單獨設置 Cache-Control
            add_header Cache-Control "no-store";  # 禁用緩存
            ## 服務端驗證 設置
            if_modified_since exact;  # 提供Last-Modified,處理If-Modified-Since,精確度是秒,HTTP 1.0 就支持
            etag on;  # 提供Etag(跟最后修改時間、文件大小有關),處理If-None-Match,HTTP 1.1 才支持
            # if_modified_since 和 etag 都沒變化才會返回304,兩項一般會同時變化,先驗證etag變化就返回200

            root /webroot/static/;     # 訪問本地文件, 該目錄下如果沒有index文件,會出現403
        }  
    location /contract {
                // alias 和 root 二選一
               alias /usr/;  # 實際訪問的是 /usr/
               root /usr/;   # 實際訪問的是 /usr/contract 
               add_header Access-Control-Allow-Origin *;  # 允許跨域訪問
        }
        location / {
           proxy_pass http://tomcat:8080/   # 轉發給后端服務器,如果這里使用了變量,則需要配置 resolver 來指定DNS
           proxy_read_timeout  3600;   # 超時時間
        }

        error_page 403 404 /404.html;  # 碰到403、404 則 跳轉到 /404.html
        location = /404.html {
            root /usr/static;
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }

        error_page 403 404 =301 $scheme://$host:$server_port/;   # 重定向
    }
    server{
        # 第二個server
    }
}

location匹配規則
精確匹配:=,例 location = /login
匹配路徑:^~,例 location ^~ /static/ 匹配 /static/a.html
區分大小寫的正則匹配:~,location ~ .(gif|jpg|png|js|css)$
不區分大小寫的正則匹配:~*
區分大小寫的正則不匹配:!~
不區分大小寫的正則不匹配:!~*
通配:/

匹配優先級:=、^~、正則匹配(按書寫順序)、/

全局變量

$args: 請求行中問號后面的參數
$content_length: 請求頭中的Content-length字段。
$content_type: 請求頭中的Content-Type字段。
$host: 請求目標主機
$http_user_agent: 客戶端agent信息
$http_cookie: 客戶端cookie信息
$request_method: 客戶端請求的方法
$remote_addr: 客戶端的IP地址。
$remote_port: 客戶端的端口。
$request_filename: 當前所請求文件的路徑
$scheme: HTTP協議(如http,https)
$server_protocol: 請求使用的協議,通常是HTTP/1.0或HTTP/1.1。
$server_port: 請求到達服務器的端口號。
$request_uri: 請求參數的原始URI,不包含主機名,如:”/foo/bar.php?arg=baz”。
$uri: 不帶參數的當前URI,不包含主機名,如”/foo/bar.html”。
$document_uri: 與$uri相同

反向代理

location ^~ /uri {
    proxy_pass http://tomcat:8080/newuri;   # 轉發時可以改變端口 和 路徑,如果location是正則匹配,轉發時路徑不會變
    
   proxy_http_version 1.1  # 默認為1.0
    # 設置給上游服務器的 頭
    proxy_set_header Host $host;                            # 客戶端請求的目標host,即Nginx
    proxy_set_header Proxy-Host $proxy_port;       # Nginx請求的目標host,即上游服務器
    proxy_set_header X-Real-IP $remote_addr;      # 客戶端host
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 請求頭中的X-Forwarded-For + $remote_addr
    # client -> nginx -> nginx 結構中,第一臺nginx的$remote_addr是客戶端,$proxy_add_x_forwarded_for也為$remote_addr,第二臺nginx的$remote_addr為第一臺nginx,$proxy_add_x_forwarded_for為第一臺nginx的$proxy_add_x_forwarded_for + 第一臺nginx,即客戶端 + 第一臺nginx
    sub_filter 'a' 'b';  # 響應內容替換
    sub_filter_once off;  # 非單處替換
}

# websocket 代理
location ^~ /socket.io {
          proxy_pass http://127.0.0.1:5000;
          proxy_read_timeout 3600;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_set_header Host $host;
    }
upstream tomcats{   # 定義上游服務器
    server 10.0.100.10:11211;
    server 10.0.100.20:11211;
    keepalive 64;
}
location ^~ /uri {
    proxy_pass http://tomcat;   # 使用upstream,轉發時會有 /uri
    proxy_pass http://tomcat/;   # 轉發時沒有 /uri
}

負載均衡算法
1、輪詢(默認算法)
2、IP hash
3、最少連接數

upstream tomcats{   # 定義上游服務器
    server 10.0.100.10:11211;
    server 10.0.100.20:11211;
    least_conn;   # 開啟最少連接數 算法
}

HTTPS

server {
    listen 443 default ssl;
    server_name www.example.com example.com;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    ssl_certificate /usr/local/etc/nginx/www.example.com.crt;  # 證書
    ssl_ certificate_ key /usr/local/etc/nginx/www.example.com.key;  # 私鑰
或
        ssl_certificate "/etc/nginx/cert/5810237_example.com.pem";
        ssl_certificate_key "/etc/nginx/cert/5810237_example.com.key";

    location / {
        # https頁面 訪問的資源也必須是 https
        add_header Content-Security-Policy upgrade-insecure-requests;  # 如果html引用了http資源,強制改為https
        proxy_set_header X-FORWARDED-PROTO https;  # 讓上游服務器知道原始請求是https
        proxy_pass http://upstream;  # nginx和上游之間不用https
        # proxy_pass https://upstream;  # nginx和上游之間也用https
    }
}

gzip 壓縮

http {
    gzip on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_disable msie6;

    gzip_types text/plain text/css application/x-javascript text/xml
        application/xml application/xml+rss text/javascript
        application/javascript application/json;
}

rewrite

執行順序
1、執行server塊的rewrite
2、匹配location
3、執行location塊的rewrite,如果URL被重寫,則重新執行1-3,直到匹配location 并 不被 rewrite
4、如果循環超過10次,則返回500 Internal Server Error錯誤

格式

rewrite 正則 新串 [標志位];
例:rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;
含義:原url中的路徑部分 去匹配 正則,把匹配串替換為新串,新串中的$1即引用匹配串中的第1個分組(小括號)

標志位flag
last: 后續只匹配,不再rewrite
break: 用在location中,不再rewrite,采用當前location
redirect: 返回302臨時重定向,地址欄會顯示跳轉后的地址
permanent: 返回301永久重定向,地址欄會顯示跳轉后的地址

server {
    if ($request_method = POST) {    # if里的判斷運算符 與 location 判斷運算符 含義一致
        return 405;     # 直接返回狀態碼
    }
    location / {
        rewrite ^/listings/(.*)$ /$remote_port.html?listing=$1 last;  # 新串中可以引用全局變量$remote_port等
        
    set $flag 0;  # 由于 if 不能嵌套使用 也 不能多重條件,因此用 變量來實現復雜條件
        if ($http_user_agent ~* "(Android|iPhone|Windows Phone|UC|Kindle|Mobile)"){  # 移動端,正則表達式匹配
            set $flag "${flag}1";
        }
        if ($request_uri !~ /mobile){   # 正則表達式不匹配
            set $flag "${flag}1";
        }
       if ($request_uri !~ \.){   # 正則表達式 轉義
            set $flag "${flag}1";
        }
        if ($flag = "0111"){
            return 301 http://$server_name/mobile/index;  # 重定向
        }

        proxy_pass http://upstream;
    }


    location / {
        try_files $uri $uri/ /index.html;
    }
        
    location = / {
        set $flag 0;
            if ($http_user_agent ~* "(Android|iPhone|Windows Phone|UC|Kindle|Mobile)"){
                set $flag "${flag}1";
            }
            if ($flag = "01"){
                return 301 http://$server_name/mobile/index;    # if 會使 try_files 失效
            }
        if ($flag != "01"){
                return 301 http://$server_name/home;
            }
    }
}

try_file

location ^~ /test/ {
    index index.html;
    # try_files 表示找到一個可用的文件返回
    try_files /2.html /1.html /test/test2.html @bd;  # 引用location
}
        
location @bd {      # 定義location
    rewrite ^/(.*)$ http://www.google.com;
}

案例

1、小程序里需要打開第三方網頁,用我方域名代理第三方域名

location ~ "^\/.*\..*\/" {    # 識別出 "https://我方域名/某域名/path" 格式的請求;需要轉義的正則表達式得用引號包起來
       proxy_pass https:/$request_uri;  # 拼接出 "https://某域名/path"
       proxy_set_header Referer 'www.目標.com';
}

location / {
  proxy_pass https://www.目標.com;
  proxy_set_header Referer 'www.目標.com';
        
  proxy_set_header Accept-Encoding "";  # 避免gzip,使得sub_filter能正常工作
  sub_filter_once off;   # 替換所有
  sub_filter https:// https://www.我方.cn/;   # 從目標獲取的響應內容里,在所有寫明的域名前加一個我方域名,形成https://我方域名/某域名/path;避免頁面直接向別的域名發送請求,造成跨域限制(CORS、防盜鏈)
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,626評論 2 370