Nginx-反向代理
四层HTTP代理:https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html
七层TCP代理:https://nginx.org/en/docs/http/ngx_http_proxy_module.html
概述
ngx_http_proxy_module: 将客户端的请求以http协议转发至指定服务器进行处理。
ngx_stream_proxy_module:将客户端的请求以tcp协议转发至指定服务器处理。
ngx_http_fastcgi_module:将客户端对php的请求以fastcgi协议转发至指定服务器助理。
ngx_http_uwsgi_module:将客户端对Python的请求以uwsgi协议转发至指定服务器处理。
架构
1. 实现http反向代理
要求:将用户对域 www.nagedu.net 的请求转发值后端服务器处理
环境准备:
192.168.7.102 #Nginx 代理服务器 192.168.7.103 #后端web A,Apache部署 192.168.7.104 #后端web B,Apache部署
1.1 反向代理配置参数
proxy_pass;#用来设置将客户端请求转发给的后端服务器的主机,可以是主机名、IP地址:端口的方式,也可以代理到预先设置的主机群组,需要模块gx_http_upstream_module支持。
location /web { index index.html;
#生产环境多数不加/ proxy_pass http://192.168.7.103:80; #不带斜线将访问的/web,等于访问后端服务器 http://192.168.7.103:80/web/index.html,即后端服务器配置的站点根目录要有web目录才可以被访问,这是一个追加/web到后端服务器http://servername:port/WEB/INDEX.HTML的操作 proxy_pass http://192.168.7.103:80/; #带斜线,等于访问后端服务器的http://192.168.7.103:80/index.html 内容返回给客户端 }
proxy_hide_header field; #用于nginx作为反向代理的时候,在返回给客户端http响应的时候,隐藏后端服务版本相应头部的信息,可以设置在http/server或location块
location /web { index index.html; proxy_pass http://192.168.7.103:80/; proxy_hide_header ETag; }
proxy_pass_header field; #默认nginx在响应报文中不传递后端服务器的首部字段Date, Server, X-Pad, X-Accel等参数,如果要传递的话则要使用 proxy_pass_header field声明将后端服务器返回的值传递给客户端
proxy_pass_request_body on | off; #是否向后端服务器发送HTTP包体部分,可以设置在http/server或location块,默认即为开启
proxy_pass_request_headers on | off; #是否将客户端的请求头部转发给后端服务器,可以设置在http/server或location块,默认即为开启
proxy_set_header;用于代理透传客户端真实IP
proxy_set_header; #可以更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实IP的时候,就要更改每一个报文的头部,如下: #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $remote_addr; #添加HOST到报文头部,如果客户端为NAT上网那么其值为客户端的共用的公网IP地址,常用于在日之中记录客户端的真实IP地址。 $proxy_add_x_forwarded_for “X-Forwarded-For”客户端请求标头字段,$remote_addr附加变量,用逗号分隔。如果客户端请求标头中不存在“X-Forwarded-For”字段,则该$proxy_add_x_forwarded_for变量等于该$remote_addr变量。
proxy_connect_timeout time;#配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒,用法如下:
proxy_connect_timeout 60s; #60s为自定义nginx与后端服务器建立连接的超时时间
proxy_read_time time; #配置nginx服务器向后端服务器或服务器组发起read读请求后,等待的超时时间,默认60s
proxy_send_time time; #配置nginx项后端服务器或服务器组发起write请求后,等待的超时时间,默认60s
proxy_http_version 1.0; #用于设置nginx提供代理服务的HTTP协议的版本,默认http 1.0
proxy_ignore_client_abort off; #当客户端网络中断请求时,nginx服务器中断其对后端服务器的请求。即如果此项设置为on开启,则服务器会忽略客户端中断并一直等着代理服务执行返回,如果设置为off,则客户端中断后Nginx也会中断客户端请求并立即记录499日志,默认为off。
proxy_headers_hash_bucket_size 128;#当配置了 proxy_hide_header和proxy_set_header的时候,用于设置nginx保存HTTP报文头的hash表的上限。
proxy_headers_hash_max_size 512;#设置proxy_headers_hash_bucket_size的最大可用空间
server_namse_hash_bucket_size 512;#server_name hash表申请空间大小
server_names_hash_max_szie 512;#设置服务器名称hash表的上限大小
1.2 示例
反向代理示例--单台web服务器
server { listen 80; server_name www.magedu.net;
location / { proxy_pass http://192.168.7.103:80/; } }
反向代理示例--指定location
server { listen 80; server_name www.magedu.net;
location / { index index.html index.php; root /data/nginx/html/pc; }
location /web { #proxy_pass http://192.168.7.103:80/; #注意有后面的/, proxy_pass http://192.168.7.104:80; } }
后端web服务器必须要有相对于的访问URL
[root@s3 ~]# mkdir /var/www/html/web [root@s3 ~]# echo "web1 page for apache" > /var/www/html/web/index.html [root@s4 ~]# mkdir /var/www/html/web [root@s4 ~]# echo "web2 page for apache" > /var/www/html/web/index.html
2. 反向代理示例--缓存功能
缓存功能默认关闭状态
2.1 参数说明
proxy_cache zone | off; #默认off #指明调用的缓存,或关闭缓存机制;Context:http, server, location
proxy_cache_key string; #缓存中用于“键”的内容,默认值:proxy_cache_key $scheme $proxy_host $request_uri;
proxy_cache_valid [code ...] time; #定义对特定响应码的响应内容的缓存时长,定义在http
, server
,location
中
示例:
proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m;
proxy_cache_path; #定义可用于proxy功能的缓存;Context:http 注意:这个只能在主配置文件的http块配置,作用为全局。
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];
示例
proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创建 levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=1048576个目录 keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数) inactive=120s; #缓存有效时间 max_size=1g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache; proxy_cache_key $request_uri; proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间 proxy_cache_valid any 1m;
proxy_cache_use_stale error http_502 http_503; #在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端,
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默认是off
proxy_cache_methods GET | HEAD | POST ...; #对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存
2.2 配置与测试
2.2.1 非缓存场景压测
]# ab -n 2000 -c200 http://www.magedu.net/web/log.html Total transferred: 3059318000 bytes HTML transferred: 3058760000 bytes Requests per second: 155.14 [#/sec] (mean) Time per request: 1289.166 [ms] (mean) Time per request: 6.446 [ms] (mean, across all concurrent requests) Transfer rate: 231747.94 [Kbytes/sec] received
2.2.2 准备缓存配置
主配置文件
]# vim /apps/nginx/conf/nginx.conf proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g; #配置在nginx.conf http配置段
调用缓存
]# vim /apps/nginx/conf/conf.d/pc.conf
location /web { #要缓存的URL 或者放在server配置项对所有URL都进行缓存 proxy_pass http://192.168.7.104:80/; proxy_set_header clientip $remote_addr; #clientip字段需要在后端日志中定义 proxy_cache proxycache; proxy_cache_key $request_uri; proxy_cache_valid 200 302 301 1h; proxy_cache_valid any 1m; }
验证缓存
]# ab -n 2000 -c200 http://www.magedu.net/web/log.html Total transferred: 3059318000 bytes HTML transferred: 3058760000 bytes Requests per second: 1922.78 [#/sec] (mean) Time per request: 104.016 [ms] (mean) Time per request: 0.520 [ms] (mean, across all concurrent requests) Transfer rate: 2872259.55 [Kbytes/sec] received
3. 添加头部报文信息
https://nginx.org/en/docs/http/ngx_http_headers_module.html
nginx基于模块ngx_http_headers_module可以实现对头部报文添加指定的key与值,这个值是定义后端给浏览器返回的值
proxy_set_header
是Nginx
设置请求头信息给上游服务器,add_header
是Nginx
设置响应头信息给浏览器
如果响应代码等于 200、201 (1.3.10)、204、206、301、302、303、304、307 (1.1.16、1.0.13) 或 308 (1.13),则将指定字段添加到响应标头.0)。参数值可以包含变量。
如果指定了always
参数,则无论响应代码如何,都将添加指定的字段。
Syntax: add_header name value [always];
Default: —
Context: http, server, location, if in location
add_header name value [always]; add_header X-Via $server_addr; add_header X-Cache $upstream_cache_status; add_header X-Accel $server_name;
示例
location /web { proxy_pass http://192.168.7.103:80/; proxy_set_header clientip $remote_addr; proxy_cache proxycache; proxy_cache_key $request_uri; proxy_cache_valid 200 302 301 1h; proxy_cache_valid any 1m; add_header X-Via $server_addr; add_header X-Cache $upstream_cache_status; add_header X-Accel $server_name; }
验证头部信息
4. 反向代理多台服务器
Nginx可以基于ngx_http_upstream_module模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能
官方文档: https://nginx.org/en/docs/http/ngx_http_upstream_module.html
Syntax: upstream name { ... }
Default: —
Context: http
resolver 10.0.0.1; upstream dynamic { zone upstream_dynamic 64k; server backend1.example.com weight=5 slow_start=5s; server backend2.example.com:8080 fail_timeout=5s slow_start=30s; server 192.0.2.1 max_fails=3; server backend3.example.com resolve; server backend4.example.com service=http resolve; server backup1.example.com:8080 backup; server backup2.example.com:8080 backup; } server { location / { proxy_pass http://dynamic; health_check; } }
默认情况下,请求使用加权循环平衡方法在服务器之间分配。 在上面的示例中,每 7 个请求将分布如下:5 个请求发往 backend1.example.com,1 个请求发往第二台和第三台服务器。 如果在与服务器通信期间发生错误,请求将被传递到下一个服务器,依此类推,直到尝试所有正常运行的服务器。 如果无法从任何服务器获得成功响应,则客户端将收到与最后一个服务器通信的结果。
参数简介
weight=number #设置权重,默认为1。
slow_start=number #设置服务器将其权重从零恢复到标称值的时间,当不健康的服务器变得健康时,或者当服务器在一段时间后变得可用时,它被认为不可用。默认值为零,即禁用慢启动。该参数不能与 hash、ip_hash 和随机负载均衡方法一起使用。
max_conns=number #给当前server设置最大活动链接数,默认为0表示没有限制。 max_fails=number #对后端服务器连续监测失败多少次就标记为不可用。 fail_timeout=time #对后端服务器的单次监测超时时间,默认为10秒。 backup #设置为备份服务器,当所有服务器不可用时将重新启用次服务器。 down #标记为down状态,不会调度。 resolve #当server定义的是主机名的时候,当A记录发生变化会自动应用新IP而不用重启Nginx,必须在 http 块或相应的上游块中指定解析器指令。
Syntax: zone name [size];
Default: —
Context: upstream
This directive appeared in version 1.9.0.
定义共享内存区域的名称和大小,以保持工作进程之间共享的组的配置和运行时状态。 几个组可以共享同一个区域。 在这种情况下,只指定一次大小就足够了.
调度算法
hash KEY consistent;
#基于指定key做hash计算,使用consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致性hash基于取模运算。
hash $request_uri consistent; #基于用户请求的uri做hash
ip_hash;
#源地址hash调度方法,基于的客户端的remote_addr(源地址)做hash计算,以实现会话保持,如果原后端服务器不可用会调度到新的服务器。
least_conn
#最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器
least_time header
| last_byte
[inflight
];
指定组应使用负载平衡方法,其中将请求传递到具有最短平均响应时间和最少活动连接数的服务器,同时考虑服务器的权重。 如果有多个这样的服务器,则使用加权循环平衡方法依次尝试它们。
如果指定了 header 参数,则使用接收响应头的时间。 如果指定了 last_byte 参数,则使用接收完整响应的时间。 如果指定了 inflight 参数(1.11.6),不完整的请求也会被考虑在内。
示例
upstream webserver { #hash $request_uri consistent; #ip_hash; #least_conn; server 192.168.7.103:80 weight=1 fail_timeout=5s max_fails=3; #后端服务器状态监测 server 192.168.7.104:80 weight=1 fail_timeout=5s max_fails=3; server 192.168.7.101:80 weight=1 fail_timeout=5s max_fails=3 backup; }
server { listen 80; server_name www.magedu.net;
location / { index index.html index.php; root /data/nginx/html/pc; }
location /web { index index.html; proxy_pass http://webserver/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #添加客户端IP到报文头部,透传到后端服务器 }
透传IP后端服务器设置
apache
]# vim /etc/httpd/conf/httpd.conf LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
nginx
]# cat /apps/nginx/conf/nginx.conf "$http_x_forwarded_for"' #默认日志格式就有此配置
5. 实现Nginx tcp负载均衡
Nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于DNS的域名解析,其配置方式和指令和http 代理类似,其基于ngx_stream_proxy_module模块实现tcp负载,另外基于模块ngx_stream_upstream_module实现后端服务器分组转发、权重分配、状态监测、调度算法等高级功能。
官方文档:https://nginx.org/en/docs/stream/ngx_stream_core_module.html
负载均衡实例
stream { #定义stream upstream backend { #定义后端服务器 hash $remote_addr consistent; #定义调度算法 server backend1.example.com:12345 weight=5; #定义具体server server 127.0.0.1:12345 max_fails=3 fail_timeout=30s; server unix:/tmp/backend3; } upstream dns { #upstream 后面名称不能用下划线_ server 192.168.0.1:53535; #定义具体server server dns.example.com:53; } server { #定义server listen 12345; #监听IP:PORT proxy_connect_timeout 1s; #连接超时时间 proxy_timeout 3s; #转发超时时间 proxy_pass backend; #转发到具体服务器组 } server { listen 127.0.0.1:53 udp reuseport; proxy_timeout 20s; proxy_pass dns; } server { listen [::1]:12345; proxy_pass unix:/tmp/stream.socket; } }
修改redis监听地址
]# vim /etc/redis.conf bind 0.0.0.0
nginx配置
stream {
upstream redis_server {
server 192.168.7.104:6379 max_fails=3 fail_timeout=30s;
}
upstream mysql_server {
least_conn;
server 192.168.7.104:3306 max_fails=3 fail_timeout=30s;
}
server {
listen 192.168.7.102:3306;
proxy_connect_timeout 6s;
proxy_timeout 15s;
proxy_pass mysql_server;
}
server {
listen 192.168.7.102:6379;
proxy_connect_timeout 3s;
proxy_timeout 3s;
proxy_pass redis_server;
}
重启nginx并访问测试
]# ss -tnl | grep 6379 LISTEN 0 128 192.168.7.102:6379 *:*
测试通过nginx 负载连接redis
]# redis-cli -h 192.168.7.102 192.168.7.102:6379> set name jack OK 192.168.7.102:6379> get name "jack" 192.168.7.102:6379>
通过nginx 负载连接mysql
]# mysql -uroot -p123456 -h 192.168.7.102 Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 32 Server version: 5.5.60-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> create database linux34; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | linux34 | | mysql | | performance_schema | +--------------------+ 4 rows in set (0.01 sec) MariaDB [(none)]>
nginx实现ssl+http跳转https
server { listen 443 ssl; server_name xxx.com; client_max_body_size 100M; ssl_certificate xxx.pem; ssl_certificate_key xxx.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root /data/nginx/web/; index index.html index.htm; } } server { listen 80; server_name xxx.com www.xxx.com; //监听两个域名 rewrite ^(/.*)$ https://xxx.com$1 permanent; //将www请求重写为xxx.com }
注意:如果还有其他接口监听代理,必须将重写和重定向写到最下面,不然会匹配即停止