0%

干货分享 Nginx 反向代理的参数详解

关于 Nginx 系列其他文章的传送门

  1. 《 老司机都在用的 Nginx 实用配置 》

  2. 《 干货分享 Nginx 反向代理的参数详解 》     您当前所在位置

  3. 《 8 分钟轻松学会 Nginx 负载均衡和参数调优 》

  4. 《 实战详解 - 使用 Nginx 负载均衡 Docker 中的 WordPress 和 PhpMyAdmin 》



proxy

一、Nginx 反向代理

在代理中有两种模式,分为 正向代理反向代理

  • 正向代理
    • 代表请求方,去访问服务方。举个简单易懂的例子 --> SSR
    • SNAT
  • 反向代理
    • 代表服务方,对外提供服务,别人来访问你。
    • DNAT

vs

Nginx 里最核心的功能就是反向代理,和 LVS 不一样的是,Nginx 是工作在七层的软件,能理解报文中更多的信息,进行更高级的代理方式,支持的代理内容有:

  • http
  • mail
  • stream

二、HTTP 代理

ngx_http_proxy_module 反代模块

Nginx 是高度模块化的,使用这个模块来开启反代功能。

proxy_pass

  • 反代的核心配置,设置将请求代理到哪一台服务器
  • 语法:proxy_pass URL;
  • 可用位置:location, if, limit_except

需要特别注意
proxy_pass 后面的路径不带 uri 时,其会将 locationuri 传递给后端主机。

1
2
3
4
5
6
7
8
9
10
server {
...
server_name HOSTNAME;
location /uri/ {
proxy http://hos[:port];
}
...
}

http://HOSTNAME/uri --> http://host/uri

proxy_pass 后面的路径是一个 uri 时,proxy_passuri 会把 locationuri 顶替掉。

1
2
3
4
5
6
7
8
9
10
server {
...
server_name HOSTNAME;
location /uri/ {
proxy http://host/new_uri/;
}
...
}

http://HOSTNAME/uri/ --> http://host/new_uri/

如果 location 定义其 uri 时使用了正则表达式的模式,或在 if 语句或 limt_execept 中使用 proxy_pass 指令,则 proxy_pass 之后必须不能使用 uri。用户请求时传递的 uri 将直接附加在代理到的服务的之后。

1
2
3
4
5
6
7
8
9
10
server {
...
server_name HOSTNAME;
location ~|~* /uri/ {
proxy http://host;
}
...
}

http://HOSTNAME/uri/ --> http://host/uri/;

proxy_set_header

  • 设定发往后端主机的请求报文的请求首部的值。
  • proxy_set_header FIELD VALUE;
  • 可用位置:http, server, location

示例
先定义首部的内容,Nginx 向后代理时,就会加上定义的首部。

1
2
proxy_set_header X-Real-IP  $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

后端 http 配置文件中添加一个日志字段,被代理的服务器就能看到发请求报文的客户端 IP 了。

1
%{X-Real-IP}i

proxy_hide_header

  • 语法:proxy_hide_header field;
  • Nginx 默认情况下会隐藏主机信息,包括 “Date”, “Server”, “X-Pad”, and “X-Accel-...” 等,这里可以设置额外的响应头,不发给客户端。
  • 相反的,如果希望允许传递某些响应头给客户端,可以使用 proxy_pass_header 指令。

proxy_connect_timeout

  • 代理服务器与后端服务器建立连接的超时时间
  • proxy_connect_timeout 60;
  • 默认为 60s,不应该超过 75s

proxy_read_timeout

  • 从后端接收响应报文的超时时长。
    proxy_read_timeout 60;
  • 默认为 60s

proxy_send_timeout

  • 向后端发送请求报文的超时时长
    proxy_send_timeout 60;
  • 默认为 60s

ngx_http_headers_module 自定义头模块

proxy_set_headerproxy_hide_header 只能在代理模式下操纵请求和响应报文的首部,而这个模块不仅可以在代理模式时使用,也能在非代理时使用,将响应给客户端的响应报文中添加自定义首部,或修改指定首部的值。

  • 可用位置:http, server, location, if in location

add_header

  • 添加自定义首部。
  • add_header name value [always];

示例:

  • add_header X-Via $server_addr;
  • add_header X-Accel $server_name;

expires

  • expires [modified] time;
  • 用于定义 Expire 或 Cache-Control 首部的值多久过期。

示例:

  • expires epoch | max | off;

三、HTTP 缓存

Nginx 作为反向代理服务器时,通过将经常读取的文件保存一份在本地服务器上的方式,提高代理速度。
因为所有的数据都有 局部性,会产生热区效应,使用缓存机制提高性能。

局部性

  • 时间局部性:如果一个数据最近被访问过,那么很快就会被再一次访问。
  • 空间局部性:如果一个数据被访问过,那么他周边的数据也会被访问。

所以一个网站中,20% 的数据要承载 80% 的访问量,遵循著名的 “2:8法则”。

proxy_http

使用 Nginx 的缓存时需要注意:

  1. 先定义后再使用。
  2. 不能交叉使用,http 要用 http 专有的缓存插件;fastcgi 要用 fastcgi 专有的缓存插件,不同的协议不能混用。
  3. 缓存有淘汰机制 LRU,即选择最久未使用的数据予以淘汰。
  4. 缓存数据通过"键值"格式存储,为了查找时加速,其中“键”是将请求的 url 做 HASH 计算后,按照 HASH 值中字母或数字的顺序分级存放,Nginx 中最多 3 级。

下面列举一些常用的 HTTP 缓存模块的参数

ngx_http_proxy_module 代理模块的缓存功能

ngx_http_proxy_module 模块除了能配置 proxy 参数,还能配置 缓存参数

proxy_cache_path

定义可用于 proxy 功能的缓存,最多 3 级,定义后,需要引用才能使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
proxy_cache_path path [levels=levels]
[use_temp_path=on|off]
[keys_zone=name:size]
[inactive=time]
[max_size=size]
[manager_files=number]
[manager_sleep=time]
[manager_threshold=time]
[loader_files=number]
[loader_sleep=time]
[loader_threshold=time]
[purger=on|off]
[purger_files=number]
[purger_sleep=time]
[purger_threshold=time];

可用位置:

  • 定义时必须在 http
  • 引用时位置 server, location

示例:

  • 定义:
    • proxy_cache_path /var/cache/nginx levels=1:1:2 keys_zone=webcache:10m;
  • 引用:
    • proxy_cache webcache;

proxy_cache

指明要调用的缓存,或关闭缓存机制。

  • proxy_cache zone | off;
  • 可用位置:http, server, location

proxy_cache_key

  • 定义缓存中用什么数据当做“键”。
  • proxy_cache_key string;
  • 默认值:proxy_cache_key $scheme$proxy_host$request_uri;
  • 生产环境中可能不同的 url 或 uri 对应的是相同的资源,为了提高缓存的命中率,需妥善定义“键”。

proxy_cache_valid

  • 定义对特定响应码的响应内容的缓存时长。
  • proxy_cache_valid [code ...] time;
  • 可以多次定义不同响应吗的缓存时长。

示例
先在 http{...} 中定义;

1
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:1:1 keys_zone=pxycache:20m max_size=1g;

在需要调用缓存功能的配置段引用缓存,例如 server{...}

1
2
3
4
proxy_cache pxycache;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 1h;
proxy_cache_valid any 1m;

proxy_cache_use_stale

  • 当无法从原始服务器获取最新的内容时,Nginx 可发送在其缓存中的陈旧的文件,而不是向客户端传达错误信息。
  • proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ...;

示例

1
2
3
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
// 当 Nginx 收到后端服务器返回的 error,timeout 或者其他指定的 5xx 错误时
// 并且在其缓存中有请求文件的陈旧版本,则会将这些陈旧版本的文件而不是错误信息发送给客户端。

proxy_cache_methods

  • 客户端使用此指令中指定的请求方法时,使用缓存响应。 GETHEAD 方法虽然是默认的,但还是建议明确指定它们。
  • proxy_cache_methods GET | HEAD | POST ...;
  • 可用位置:http, server, location

四、FastCGI 代理模块

php-fpm

在中小型站点中,使用 php 是最合适的选择,那么在搭建 LAMP 时,php 有两种部署方式:

1、作为 httpd 的模块运行,缺点是 httpd 要处理静态和动态的请求,流量大时 web 服务器的压力较大。

  • 当 httpd 是 prefork 时,是 php_module
  • 当 httpd 是 worker 时,是 zts_module

2、通过 FastCGI 的方式运行,优点是动静分离。

  • fpm:fastcgi process manager

第 2 中方式中的 fpm,其实就是个 FastCGI 进程管理器,它在 php 解释器的基础上,加了一个壳,使 php 可以监听在一个套接字上,通过 FastCGI 接收并处理并发请求。

而 FastCGI 为了处理并发请求,使用的 MPM(多路工作模块)和 httpd 中的 frefork 一致,采用 M/W 的方式,Master 进程管理 Worker 线程,Worker 线程处理 php 请求。

在 Nginx 中,暂时并不支持像第 1 种那样以模块的方式运行 php,只能通过调用 Nginx 自己的 FastCGI 模块,来和后端的 fpm 通信。

ngx_http_fastcgi_module 模块

使用这个模块将请求通过 FastCGI 传递给后端服务器,下面列出几个常用配置参数。

fastcgi_pass

  • fastcgi_pass ADDRESS;
  • ADDRESS 为 fastcgi server 的地址。
  • 可用位置: location, if in location
  • 注意:不需要加任何协议开头,如:http://, fastcgi:// 等。

fastcgi_index

  • fastcgi_index index.php ;
  • 设置 fastcgi 默认的主页资源。

fastcgi_param (传递参数)

  • fastcgi_param parameter value [if_not_empty];
  • 向后端 FastCGI 服务器传递参数,和静态资源不同,动态资源需要很多客户端请求时的参数。

假设 nginx 把请求代理至后端 fpm 时,fpm 是没办法直接使用 nginx 中客户端连接信息的参数的,因为 nginx 中变量的表达方式,和 fpm 中变量的表达方式不一样,例如 nginx 中的变量都是小写,fpm 却是大写等等,所以 nginx 代理 fpm 时,要把自己的变量名转成 fpm 的变量名才行。

fpm 中需要传递的参数很多,nginx 安装好后,在 /etc/nginx/ 目录下会自动生成一个 fastcgi.conf 文件,该文件中包含了使用 fpm 时 必备的参数

配置示例

1
2
3
4
5
6
7
8
// 前提:已经配置好 fpm server 和 mariadb-server 服务
location ~* \.php$ {
fastcgi_pass 127.0.0.1:9000; // 后端 fpm 的地址
fastcgi_index index.php; // 主页文件 // ↓ 这个变量代表请求的 uri
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
// ↑ fpm 中的变量 // ↑ 前边路径代表 uri 的起始目录,对应 fpm 服务器中资源存放目录
include fastcgi_params; // 变量参数映射列表
}

五、FastCGI 缓存

FastCGI 的缓存其实也是通过 ngx_http_fastcgi_module 实现,也需要先定义再使用,之前说过,不同协议的缓存不能混在一起使用,所以需要和 http 缓存分开,单独定义。

这几个参数的使用方法和 http 缓存一样,就不重复叙述了。

  • fastcgi_cache_path 定义缓存同样需要写在配置文件的 http 配置段中。
  • fastcgi_cache
  • fastcgi_cache_key
  • fastcgi_cache_methods
  • fastcgi_cache_valid

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
http {
...
fastcgi_cache_path /var/cache/nginx/fastcgi_cache levels=1:2:1 keys_zone=fcgi:20m inactive=120s;
...
server {
...
location ~* \.php$ {
...
fastcgi_cache fcgi;
fastcgi_cache_key $request_uri;
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
...
}
...
}
...
}

六、php-fpm 状态页

php-fpm 自己提供了一个状态页面,可以配合监控程序来使用,下面说一下怎么开启。

环境

192.168.50.11 – Nginx
192.168.50.12 – php-fpm

php-fpm 端配置

1、安装 php-fpm

1
yum install php-fpm -y

2、更改配置
打开 /etc/php-fpm.d/www.conf 配置文件,更改以下配置。

1
2
3
4
5
listen = 127.0.0.1:9000` --> listen = 9000    # 改为监听所有 IP
listen.allowed_clients = 127.0.0.1 --> listen.allowed_clients = 192.168.50.11 # 设置允许的 IP
# 下面两行默认有注释,去掉即可,去掉后如下
pm.status_path = /status
ping.path = /ping

3、额外创建一个 phpinfo 页,此步不是必须。这里注意文件目录为 /data/index.php,后边会用到。

Nginx 端配置

1、安装 Nginx

1
yum install nginx -y

2、在默认配置文件 /etc/nginx/nginx.conf 里添加两个新的 location

1
2
3
4
5
6
7
8
9
10
11
12
location ~* \.php$ {
fastcgi_pass 192.168.50.12:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data$fastcgi_script_name; # 这里注意要和之前创建的 phpinfo 的目录一致
include fastcgi_params;
}

location ~* ^/(status|ping)$ {
include fastcgi_params;
fastcgi_pass 192.168.50.12:9000;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
}

验证
从浏览器访问 http://192.168.50.11/status,就打开 fpm 的状态信息了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pool:                 www      # fpm 池子名称,大多数为 www
process manager: dynamic # 进程管理方式,值:static, dynamic or ondemand, dynamic
start time: 05/Aug/2019:21:07:48 +0800 # 启动日期,如果 reload了,时间会更新
start since: 1089 # 运行时长
accepted conn: 15 # 当前池子接受的请求数
listen queue: 0 # 请求等待队列,如果这个值不为 0,那么要增加 FPM 的进程数量
max listen queue: 0 # 请求等待队列最高的数量
listen queue len: 128 # socket 等待队列长度
idle processes: 4 # 空闲进程数量
active processes: 1 # 活跃进程数量
total processes: 5 # 总进程数量
max active processes: 2 # 最大的活跃进程数量(FPM启动开始算)
max children reached: 0 # 进程最大数量限制的次数,如果这个数量不为 0,那说明你的最大进程数量太小了,请改大一点
slow requests: 0 # 启用了 php-fpm slow-log,缓慢请求的数量

访问 http://192.168.50.11/ping,返回 pong,表示连接正常。

访问 http://192.168.50.11/index.php,也能看到 phpinfo 页面,就不放截图了。

muyou