Nginx從入門到實踐(一)


結合實踐、收集各種場景、常見問題,講解Nginx中最實用的Webserver場景,提供一套整體的搭建配置方式

Nginx中間件,不局限於業務邏輯,有效獨立於后台開發框架(不論后端是Java開發、PHP開發、或者其他語言框架)都能做到平台通用

不僅重實踐、也會結合原理(如:Http協議、操作系統),讓你理解背后的原理更有利於你解決實際問題(如:bug解決、二次開發等)

基礎篇

環境調試確認

yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
yum -y install wget httpd-tools vim
cd /opt;mkdir app download logs work backup

關閉iptables

# 查看
iptables -L

# 關閉
iptables -F

# 查看
iptables -t nat -L

# 關閉
iptables -t nat -F

中間件架構

Nginx優勢

  • 多路IO復用
  • 使用Epoll模型
  • 輕量級
  • CPU親和
  • sendfile

安裝

http://nginx.org/en/linux_packages.html#stable

vim /etc/yum.repos.d/nginx.repo 

內容如下S

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
yum install nginx
# 查看版本
nginx -v

# 查看安裝編譯參數
nginx -V

基本參數使用

安裝目錄

rpm -ql nginx

路徑 類型 作用
/etc/logrotate.d/nginx 配置文件 nginx日志輪轉,用於logrotate服務的日志切割
/etc/nginx
/etc/nginx/nginx.confd
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
目錄,配置文件 nginx主配置文件
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params
/etc/nginx/fastcgi_params
配置文件 cgi配置相關,fastcgi配置
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/win-utf
配置文件 編碼轉換映射轉化文件
/etc/nginx/mime.types 配置文件 設置http協議的Content-Type與擴展名對應關系
/usr/lib/systemd/system/nginx-debug.service
/usr/lib/systemd/system/nginx.service
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug
配置文件 用於配置出系統守護進程管理器管理方式
/usr/lib64/nginx/modules
/etc/nginx/modules
目錄 nginx模塊目錄
/usr/sbin/nginx
/usr/sbin/nginx-debug
命令 nginx服務的啟動管理的終端命令
/usr/share/doc/nginx-1.14.2
/usr/share/doc/nginx-1.14.2/COPYRIGHT
/usr/share/man/man8/nginx.8.gz
文件, 目錄 nginx的手冊和幫助文件
/var/cache/nginx 目錄 nginx的緩存目錄
/var/log/nginx 目錄 nginx的日志目錄
安裝編譯參數

nginx -V

編譯選項 作用
--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
執行對應模塊時,nginx所保留的臨時性文件
--user=nginx
--group=nginx
設定nginx進程啟動的用戶和組用戶
--with-cc-opt=parameters 設置額外的參數將被添加到CFLAGS變量
--with-ld-opt=parameters 設置附加的參數,鏈接系統庫

默認配置語法

- - -
user 設置nginx服務的系統使用用戶
worker_processes 工作進程數
error_log nginx的錯誤日志
pid nginx服務啟動時候pid
events worker_connections
use
每個進程允許最大連接數
工作進程數

log

http://nginx.org/en/docs/http/ngx_http_log_module.html
錯誤日志,格式如下

2018/12/11 15:51:32 [error] 5809#5809: *37 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 120.194.101.83, server: _, request: "GET /favicon.ico HTTP/1.1", host: "120.79.65.88", referrer: "http://120.79.65.88/"

error_log /var/log/nginx/error.log warn;
日志存放位置/var/log/nginx/error.log
級別warn

access_log 記錄了哪些用戶,哪些頁面以及用戶瀏覽器、ip和其他的訪問信息,形式如下

222.88.236.165 - - [11/Dec/2018:16:38:42 +0800] "GET /static/js/login.js HTTP/1.1" 200 14459 "http://mxonline.iceflower.xyz:8081/login/?next=/course/info/6/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36" "-"

格式設置

    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;

具體的設置可以在官網中找到,可進行自定制

模塊

http://nginx.org/ru/docs/http/ngx_http_stub_status_module.html

sub_status

--with-http_stub_status_module nginx的客戶端狀態

配置nginx文件,寫在server中

location = /mystatus {
    stub_status;
}

重啟nginx,瀏覽器訪問IP+/mystatus,格式如下

Active connections: 1 
server accepts handled requests
 43 43 79 
Reading: 0 Writing: 1 Waiting: 0 

Active connections
當前活動客戶端連接數,包括Waiting連接數。
accepts
已接受的客戶端連接總數。
handled
處理的連接總數。通常,參數值與accepts 除非已達到某些資源限制(例如, worker_connections限制)相同。
requests
客戶端請求的總數。
Reading
nginx正在讀取請求標頭的當前連接數。
Writing
nginx將響應寫回客戶端的當前連接數。
Waiting
當前等待請求的空閑客戶端連接數。

random_index

http://nginx.org/en/docs/http/ngx_http_random_index_module.html
--with-http_random_index_module 目錄中選擇一個隨機主頁

location / {
    root /opt/app/code/html;
    random_index on;
}

root 后面是主頁面存放位置
不會選擇隱藏文件作為主頁面

sub_module

http://nginx.org/en/docs/http/ngx_http_sub_module.html
--with-http_sub_module HTTP內容替換

location / {
    sub_filter '<a href="http://127.0.0.1:8080/'  '<a href="https://$host/';
    sub_filter '<img src="http://127.0.0.1:8080/' '<img src="https://$host/';
    sub_filter_once on;
}

敏感詞,流媒體替換

請求限制

limit_conn_module

limit_conn_module 連接頻率限制
http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

連接限制

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;
 
    ...
 
    server {
 
        ...
 
        location /api/ {
            limit_conn addr 10;
            limit_conn_status 503; 
        }
    }
}

示例中定義key(zone=addr)為addr,分配內存大小為10m(zone=addr:10m)(如果限制域的存儲空間耗盡了,對於后續所有請求,服務器都會返回503),同一個ip($binary_remote_addr)和服務器連接超過10個(limit_conn addr 10)將會被攔截並返回503(limit_conn_status 503)錯誤碼

limit_conn_zone
語法: limit_conn_zone key zone=name:size;(設置限制規則、區域名稱及分配的內存大小)
可配置區域: http
key: 必選項;設置限制規則;取值可以是text文本、nginx變量或兩者的組合;實例中使用的nginx變量$binary_remote_addr表示根據每個ip限制並發
name: 必選項; 自定義一個區域名稱; 任意字符串
size: 分配內存的大小


limit_conn
語法: limit_conn zone number; (使用由limit_conn_zone定義的攔截規則, 並設置具體的限制連接數量)
可配置區域: http, server, location
zone: 必選項; 由limit_conn_zone(zone=name)定義的名稱; 表示使用定義的哪個限制規則
number: 必選項; 正整數; 表示具體的限制連接數量
 

limit_conn_status 
語法: limit_conn_status code;
默認值: 503
可配置區域: http, server, location
表示超出limit_req配置的請求數量后返回給客戶端的錯誤碼使用該指令
  

limit_conn_log_level
語法: limit_conn_log_level info | notice | warn | error;
默認值: limit_conn_log_level error;
可配置區域: http, server, location
當服務器拒絕處理由於速率超過或延遲請求處理而拒絕處理請求時,設置所需的日志記錄級別。
limit_req_module

limit_req_module 請求頻率限制
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

http {
    limit_req_zone $binary_remote_addr zone=req_perip:50m rate=10r/s;

    ...

    server {

        ...

        location /api/ {
                limit_req zone=req_perip burst=50 nodelay;
                limit_req_status 503;
        }
    }
}

示例中定義的區域名稱為req_perip(zone=req_perip),分配內存大小為50m(如果限制域的存儲空間耗盡了,對於后續所有請求,服務器都會返回503),同一個ip($binary_remote_addr)平均處理的請求頻率不能超過每秒10次(rate=10r/s); 如果超過每秒10次但超過的請求數量小於等於50(burst=50)時,會延遲請求。如果超過每秒的請求數超過50,則立即返回503(limit_req_status 503)給客戶端

limit_req_zone
語法: limit_req_zone key zone=name:size rate=rate;(可理解為該指令用來定義限制請求頻率)
可配置區域: http 
key: 必選項;取值范圍: 1,text(文本); 2,nginx變量;3,text和nginx變量的組合; name: 必選項;自定義字符串 
size: 必選項;分配內存大小,用來保存鍵值的狀態參數 
rate: 必選項;每秒可請求的頻率(r/s), 或每分鍾可請求的頻率(r/m)
  

limit_req
語法: limit_req zone=name [burst=number] [nodelay]; (可理解為使用定義的限制請求頻率,一定是先定義后使用!也就是一定要有limit_req_zone指令的配置后才能使用該配置)
可配置區域: http, server, location 
name: 必選項;自定義字符串, 名字必須與limit_req_zone中zone=name這個名字一致 
number: 必選項;正整數數字, 平均每秒允許不超過limit_req_zone指令中rate規定的請求數,並且不會超過該值所指定數量的請求,可延遲請求的數量 
nodelay: 可選配置,表示請求頻率超過rate規定值后又超過burst規定值后立即返回客戶端503(可設置返回code)
  

limit_req_status
語法: limit_req_status code;
默認值: 503
可配置區域: http, server, location
表示超出limit_req配置的請求數量后返回給客戶端的錯誤碼使用該指令
  

limit_req_log_level
語法: limit_req_log_level info | notice | warn | error;
默認值: limit_req_log_level error;
可配置區域: http, server, location
當服務器拒絕處理由於速率超過或延遲請求處理而拒絕處理請求時,設置所需的日志記錄級別。

\(binary_remote_addr是\)remote_addr(客戶端IP)的二進制格式,固定占用4個字節。而\(remote_addr按照字符串存儲,占用7-15個字節。用\)binary_remote_addr可以節省空間。

訪問控制

http_access_module

http_access_module 基於IP的訪問控制
http://nginx.org/en/docs/http/ngx_http_access_module.html

location / {
    deny  192.168.1.1;  # 拒絕訪問
    allow 192.168.1.0/24;   # 允許訪問
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;   # IPV6
    deny  all;
}

局限性

IP1 客戶端
IP2 代理服務器
IP3 服務器
基於客戶端的IP,但是對於Nginx來說,它不會管你哪個是真正的客戶端,如果我們的訪問不是客戶端與服務端直接連接,而是通過了一層代理,比如它的代理可以負載均衡、CDN的這種代理實現,也就是我們的訪問不是客戶端直接訪問的服務端,而是通過其他的中間件訪問服務端,這時候會出現一個問題,因為Nginx的access_module它是基於remote_addr這個變量來識別客戶端的IP的,那么如果一個ip通過中間件訪問服務端,那么Nginx認為訪問的ip就是中間件的IP,那么我們在基於IP做限制的時候,那么其實是沒有作用的。所以這樣的話,准確性是不高的,所以就是利用nginx的access_module有局限性。

解決辦法

  • 使用http_x_forwarded_for來解決這個問題

    但是http_x_forwarded_for進行訪問控制會存在問題,因為是一個協議要求的,並不是所有的cdn和代理廠商它會按照要求來做,甚至x_forwarded_for存在被修改的可能,因為只是一個頭信息,所以最終還是不真實。

    http_x_forwardded_for也是Nginx的http頭變量的一個常用的變量,它和remote_addr是有區別的。不同的是,x_forwarded_for是http協議中規定頭中要攜帶的,所以在客戶端訪問中間件,再訪問服務端的時候,那么服務端通過Nginx會記錄真實IP和中間件的IP。
    格式:http_x_forwarded_for = 客戶端ip,第一台代理ip,第二台代理ip,第N台代理ip....,所以http_x_forwarded_for是由一連串以逗號分隔的ip組成的。

  • 結合geo模塊
    http://nginx.org/ru/docs/http/ngx_http_geo_module.html

  • 通過HTTP自定義變量傳遞

http_auth_basic_module

http_auth_basic_module 基於用戶的信任登錄
http://nginx.org/en/docs/http/ngx_http_auth_basic_module.html

location / {
    auth_basic           "輸入密碼";
    auth_basic_user_file user_passwd;
}

htpasswd安裝
yum install httpd-tools -y

首次創建並加入
htpasswd -c ./user_passwd admin

[root@GYJ nginx]# cd /etc/nginx/
[root@GYJ nginx]# ls
conf.d     fastcgi_params  koi-win     modules     nginx.conf.rpmnew  uwsgi_params
default.d  koi-utf         mime.types  nginx.conf  scgi_params        win-utf
[root@GYJ nginx]# htpasswd -c ./user_passwd admin
New password: 
Re-type new password: 
Adding password for user admin
[root@GYJ nginx]# ls
conf.d     fastcgi_params  koi-win     modules     nginx.conf.rpmnew  user_passwd   win-utf
default.d  koi-utf         mime.types  nginx.conf  scgi_params        uwsgi_params
[root@GYJ nginx]# vim user_passwd 
[root@GYJ nginx]# cat user_passwd 
admin:$apr1$I04BhX5R$9JexKOl2aYCe.Tww67XMu0
[root@GYJ nginx]# 

http_auth_basic_module局限性
用戶信息依賴文件方式,管理操作機械,效率不高

解決方法:
Nginx結合LUA實現高效驗證
Nginx結合LDAP,利用nginx_auth_ldap模塊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM