1. 七层反向代理
主要的指令:
Syntax: upstream name {...}
Default: --
Context: http
Syntax: server address [parameters];
Default: --
Context: upstream
-
server指令的通用参数: backup: 指定当前server为备份服务,仅当非备份server不可用时,请求才会转发到该server down: 标识某台服务已经下线,不再服务
-
upstream模块提供的变量(不含cache)
upstream_addr: 上游服务器的IP地址,格式为可读的字符串,例如127.0.0.1:8012
upstream_connect_time: 与上游服务建立连接消耗的时间,单位为秒,精确到毫秒
upstream_header_time: 接受上游服务发回响应中http头部所消耗的时间,单位为妙,精确到毫秒
upstream_response_time: 接受完整的上游服务响应所消耗的时间,单位为妙,精确到毫秒
upstream_http_名称:从上游服务返回的响应头部的值
upstream_bytes_received: 从上游服务接受到的响应长度,单位为字节
upstream_response_length: 从上游服务返回的响应包体长度,单位为字节
upstream_status: 上游服务返回的HTTP响应中的状态码。如果未连接上,该变量值为502
upstream_cookie_名称:从上游服务发回的响应头Set-Cookie中取出的cookie的值
upstream_trailer_名称:从上游服务的响应尾部取到的值
1.1 对上游服务建立keepalive连接的ngx_http_upstream_keepalive_module
-
模块:
ngx_http_upstream_keepalive_module
,默认编译进nginx,通过--without-http_upstream_keepalive_module
移除 -
指令:
Syntax: keepalive connections;
Default: --
Context: upstream
功能: 向upstream配置的这组上游服务中最多保持多少个空闲的tcp连接,用于keepalive请求
1.15.3非稳定版本新增指令:
Syntax: keepalive_requests number;
Default: keepalive_requests 100;
Context: upstream
功能: 在一条TCP连接上最多可以跑多少个请求
Syntax: keepalive_timeout timeout;
Default: keepalive_timeout 60s;
Context: upstream
功能: 一个TCP连接在处理完一个keepalive请求之后,最多等待60s,如果没有第二个http请求,就关闭该TCP连接。
- 指定上游服务域名解析的resolver指令:
Syntax: resolver address ... [valid=time] [ipv6=on|off]
Default: --
Context: http,server,location
Syntax: resolver_timeout time;
Default: resolver_timeout 30s;
Context: http,server,location
- 测试: 上游应用服务的配置(使用nginx来模拟上游服务):
server {
listen 8011;
default_type text/plain;
return 200 '8011 server response.\n';
}
server {
listen 8012
default_type text/plain;
return 200 '8012 server response.\n';
}
nginx作为7层反向代理的配置:
upstream rrups {
server 127.0.0.1:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;
server 127.0.0.1:8012;
keepalive 32;
}
server {
server_name rrups.taohui.tech;
error_log myerror.log info;
location / {
proxy_pass http://rrups;
#http1.0是不支持keepalive的,为了防止浏览器发来的请求是使用http 1.0的,
#我们需要重置http版本,以启用keepalive功能。
proxy_http_version 1.1;
#浏览器发来的请求中的Connection头部的值可能为close,
#所以需要使用下面的指令重置下
proxy_set_header Connection "";
}
}
因为使用keepalive,所以上游服务处理完请求之后,并不会关闭该连接,可以使用tcpdump来验证:
查看tcpdump抓取的报文,可以发现,这两次连接,并没有出现FIN包,所以连接没有关闭。
1.2 负载均衡算法
1.2.1 Round-Robin算法
Round-Robin负载均衡算法是默认集成在upstream框架中,使用server指令的参数来配置。 它提供了如下4个参数:
- weight: 服务访问的权重,默认是1
max_conns
: server的最大并发连接数,仅作用于单worker进程。默认是0,表示没有限制。max_fails
: 在fail_timeout
时间段内,最大的失败次数。当达到最大失败时, 会在fail_timeout
秒内这台server不允许再次被选择fail_timeout
:单位为秒,默认值为10秒。具有2个功能: 指定一段时间内,最大的失败次数
max_fails
。 到达max_fails
后,该server不能访问的时间。
1.2.2 最小连接优先负载均衡算法
默认编译进nginx,通过--without-http_upstream_ip_hash_module
禁用。
语法:
Syntax: least_conn;
Default: --
Context: upstream
1.2.3 哈希算法
ngx_http_upstream_ip_hash_module
模块 默认编译进nginx,通过--without-http_upstream_ip_hash_module
禁用模块。
功能:以客户端的IP地址作为hash算法的关键字,映射到特定的上游服务器中。 > 对IPV4地址使用前3个字节作为关键字,对IPV6则使用完整地址 > 可以基于realip模块修改用于执行算法的IP地址
语法:
Syntax: ip_hash;
Default: --
Context: upstream
upstream_hash
模块 默认编译进nginx,通过--without-http_upstream_ip_hash_module
禁用。
功能: 和ip_hash
模块的区别是,它的key可以是任意的,它的值可以包含变量、字符串。
语法:
Syntax: hash key [consistent];
Default: --
Context: upstream
示例:
upstream iphashups {
#ip_hash;
# $arg_username表示uri问号后面的username参数的值
hash user_$arg_username;
#由于使用hash模块,所以下面的weight参数不会生效。
server 127.0.0.1:8011 weight=2 max_conns=2 max_fails=2 fail_timeout=5;
server 127.0.0.1:8012 weight=1;
}
server {
set_real_ip_from 116.62.160.193;
real_ip_recursive on;
real_ip_header X-Forwarded-For;
server_name iphash.taohui.tech;
error_log myerror.log info;
access_log logs/upstream_access.log varups;
location / {
proxy_pass http://iphashups;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
- 一致性哈希算法 hash算法的问题:
# 使用hash算法:key % 5
key=5 -> server0
key=6 -> server1
key=7 -> server2
key=8 -> server3
key=9 -> server4
# 若发生宕机或者扩容,hash算法会引发大量路由变更,
# 这会导致缓存大范围失效。
# 假设server4宕机了,这个时候hash算法就变成了: key % 4
key=5 -> server1
key=6 -> server2
key=7 -> server3
key=8 -> server0
key=9 -> server1
一致性hash算法: 假设我们有k个机器(k是变化的),数据的hash值的范围是[0,MAX],hash值的范围相对是恒定的。 我们将整个范围分为m个小区间(m远大于k,当不划分区间的时候,相当于区间的宽度为1),每个机器负责m/k个小区间。 当有新机器加入的时候,我们需要选中某个比较繁忙的机器,假设它的小区间范围是[left, right]。 这时,我把[left, mid]分配给之前的机器,把(mid, right]分配给新加入的机器,这个时候, (mid, right]对应的请求会失效,但是这个范围是非常小的。
node3 node1
\ /
hash 0 / 2^32 hash
键 \ V /
\ (+)-*->-----*-->(+) 键
hash | * /
\ ^ v hash
* | /
| *
| v
(+)-<-**----<-**(+)
/ \
hash hash
/ \
node4 node2
对node4进行扩容,因为它的负载比较繁忙
node3 node1
\ /
hash 0 / 2^32 hash
键 \ V /
\ (+)-*->-----*-->(+) 键
hash | * /
\ ^ v hash
* | /
| *
| v
(+)-<-**-(+)<***(+)
/ | ^ \
hash hash | hash
/ | | \
node4 node5 | node2
|
只对这三个连接有影响,并迁移到node5下。
1.2.4 upstream_zone模块
默认编译进nginx,通过--without-http_upstream_zone_module
禁用。
功能: 分配出共享内存,将其他upstream模块定义的负载均衡策略数据、运行时每个上游服务的状态数据存放在共享内存上,以对所有nginx worker进程生效。
语法:
Syntax: zone name [size];
Default: --
Context: upstream
1.2.5 upstream模块间的顺序
启动的时候,是从下至上的。
1.3 proxy模块
http反向代理的流程:
V +------>{接收响应头部}
{处理content阶段: proxy_pass指令} | V
V | {处理响应头部}
<?>----cache命中-------+-+ V proxy_buffering on
| | | <?>---------->{接收完整的}
cache未命中或未开启cache | | |off {响应包体 }
V | | V /
{根据指令生成发往上游的http头部及包体} | +---->{发送响应头部}<-------
| | |
proxy_request_bu V | V
+-ffering on ------<?> | {发送响应包体}
V | | {边读包体边发}
{读取请求} V | |
{完整包体} proxy_request_buffering off | V
| V | +-关闭cache-<?>
+--------->{根据负载均衡策略} | | |
{ 选择上游服务器 } | | 打开cache
V ^ V V
{根据参数连接上游服务器} | | {包体加入缓存}
V | | V
{发送请求(边}-------->-----+ +-->{关闭或者复用连接}
{读包体边发)}
1.3.1 proxy_pass指令
默认编译进nginx,通过--without-http_proxy_module
禁用。
- 指令:
Syntax: proxy_pass URL;
Default: --
Context: location,if in location,limit_except
- URL参数规则:
- URL必须以http://或者https://开头,接下来是域名、IP、unix socket地址或者upstream的名字,前两者可以在域名或者IP后加端口。最后是可选的URI。
- 当URL参数中携带URI与否,会导致发向上游请求的URL不同:
不携带URI,则将客户端请求中的URL直接转发给上游 * location后使用正则表达式、@名字时,应采用这种方式 携带URI,则对用户请求中的URL作如下操作: * 将location参数中匹配上的一段替换为该URI
- 该URL参数中可以携带变量
- 更复杂的URL替换,可以在location内的配置添加rewrite break语句
- 测试携带URI与否的不同效果 服务端的配置(使用Nginx来模拟上游服务端):
server {
listen 8012;
default_type text/plain;
return 200 '8012 server response.
uri: %uri\n';
}
反向代理端的配置:
server {
location /a {
proxy_pass http://proxyups;
#proxy_method POST;
proxy_pass_request_headers off;
#proxy_pass_request_body off;
proxy_set_body 'hello world!';
proxy_set_header name '';
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
访问和结果:
在proxy_pass
后面加上字符串,会怎样呢?
server {
location /a {
#在后面加上一个www
proxy_pass http://proxyups/www;
#proxy_method POST;
proxy_pass_request_headers off;
#proxy_pass_request_body off;
proxy_set_body 'hello world!';
proxy_set_header name '';
proxy_http_version 1.1;
proxy_set_header Connection "keepalive";
}
}
访问和结果:
可以看到,location后面的/a被/www替换掉了
1.3.2 生成发往上游的请求
- 生成请求Line
Syntax: proxy_method method;
Default: --
Context: http,server,location
# 在使用keepalive的使用,需要该为http 1.1,因为1.0不支持
Syntax: proxy_http_version 1.0 | 1.1
Default: proxy_http_version 1.0;
Context: http,server,location
- 生成请求Head
Syntax: proxy_set_header field value;
Default: proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context: http,server,location
注意:若value的值为空字符串,则整个header都不会向上游发送
功能:修改或添加http头部。
Syntax: proxy_pass_request_headers on | off;
Default: proxy_pass_request_headers on;
Context: http,server,location
功能:是否把浏览器端发来的请求头部发给上游服务器
- 生成请求体
Syntax: proxy_pass_request_body on | off;
Default: proxy_pass_request_body on;
Context: http,server,location
功能:是否把浏览器端发来的请求包体发给上游服务器
Syntax: proxy_set_body value;
Default: --
Context: http,server,location
功能:手动构造发往上游服务器的内容,value的值就是请求包体
- 接收用户请求包体的方式
Syntax: proxy_request_buffering on |off;
Default: proxy_request_buffering on;
Context: http,server,location
功能: 指定收完再转发还是边收边转发
on: > 客户端网速较慢
> 上游服务并发处理能力低
> 适应高吞吐量场景
off: > 更及时的响应
> 降低nginx读写磁盘的消耗
> 一旦开始发送内容,proxy_next_upstream
功能失败
设置接收包体所分配的内存:
Syntax: client_body_buffer_size size;
Default: client_body_buffer_size 8k|16k;
Context: http,server,location
# 因为接收head的时候,可能也收到了一点点的body
# 1. 如果接收到的body已经包含了完整的包体,则不分配client_body_buffer_size这块内存。
# 2. 如果Content-Length表示还有部分内容没有接收到,并且剩余的长度小于client_body_buffer_size,
# 则仅分配所需要内存,而不是一次把8k|16k分配完。
# 3. 如果剩余的长度远大于client_body_buffer_size,就会分多次接收,还是使用client_body_buffer_size这段内存。
# 4. 接收到以后,会根据client_body_in_single_buffer开关,来决定
# 是直接返回给上游,还是等包体全部接受完再发送给上游。
# 如果client_body_buffer_size用完了,就使用临时硬盘文件。
Syntax: client_body_in_single_buffer on|off;
Default: client_body_in_single_buffer off;
Context: http,server,location
功能: 如果设置为on,表示请求的body全部放在内存中。
最大包体长度限制:
Syntax: client_max_body_size size;
Default: client_max_body_size 1m;
Context: http,server,location
仅对请求头部中含有Content-Length有效超出最大长度后,返回413错误
临时文件路径格式:
Syntax: client_body_temp_path path [level1 [level2 [level3]]];
Default: client_body_temp_path client_body_temp;
Context: http,server,location
功能:指定在哪个目录下存放请求包体
level1、level2、level3表示多级子目录,会从临时文件名末尾开始数,
每n为作为一级子目录。之所以这样做,是因为,一个目录下不能存放太多的文件。
Syntax: client_body_in_file_only on |clean |off;
Default: client_body_in_file_only off;
Context: http,server,location
功能:off表示包体比较大的时候必须存放在文件中,如果包体的大小非常小,
完全可以存放在client_body_buffer_size下,这个时候是不会存放在文件中的。
on表示包体必须存放在文件中,而且文件会一直保存下去
clean表示包体必须存放在文件中,请求结束后就会删除该文件。
读取包体时的超时:
Syntax: client_body_timeout time;
Default: client_body_timeout 60s;
Context: http,server,location
读取包体时超时,则返回408错误
1.3.3 接收上游的响应
- 与上游服务建立连接 设置TCP握手超时时间:
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http,server,location
超时后,会向客户端生成http响应,响应码为502:
设置当出现502错误的时候,就换一个上游服务器
Syntax: proxy_next_upstream http_502|...;
Default: proxy_next_upstream error timeout;
Context: http,server,location
上游连接启用TCP keepalive:
Syntax: proxy_socket_keepalive on | off;
Default: proxy_socket_keepalive off;
Context: http,server,location
修改TCP连接中的local address:
Syntax: proxy_bind address [transparent] | off;
Default: --
Context: http,server,location
- 可以使用变量:
proxy_bind $remote_addr;
- 可以使用不属于所在机器的IP地址:
proxy_bind $remote_addr transparent;
当客户端关闭连接时,是否继续保持nginx与上游服务的连接:
Syntax: proxy_ignore_client_abort on|off;
Default: proxy_ignore_client_abort off;
Context: http,server,location
向上游发送HTTP请求的超时时间:
Syntax: proxy_send_timeout time;
Default: proxy_send_timeout 60s;
Context: http,server,location
- 接收上游的响应
Syntax: proxy_buffer_size size;
Default: proxy_buffer_size 4k|8k;
Context: http,server,location
功能: 能接收的上游响应头部的最大长度
如果上游响应的头部过长,就会导致nginx无法正常处理,并在error.log上打印这条日志: upstream sent too big header
Syntax: proxy_buffers number size;
Default: proxy_buffers 8 4k|8k;
Context: http,server,location
功能: 能接收的上游响应包体的最大长度
如果是接收到完整的响应包体后再返回,并且包体超过了proxy_buffers的大小,
就会存放在磁盘中
接收上游的HTTP包体:
Syntax: proxy_buffering on|off; X-Accel-Buffering:是nginx特定的Head
Default: proxy_buffering on; yes:表示强制nginx先接受完上游的响应包体再发送
Context: http,server,location no:
Syntax: proxy_max_temp_file_size size;
Default: proxy_max_temp_file_size 1024m;
Context: http,server,location
限制写入磁盘中文件的最大值,如果上游服务了一个非常大的文件,超出了
proxy_max_temp_file_size的话,就会出错
Syntax: proxy_temp_file_write_size size;
Default: proxy_temp_file_write_size 8k|16k;
Context: http,server,location
限制每次向磁盘文件写入的字节数
Syntax: proxy_temp_path path [level1 [level2 [level3]]];
Default: proxy_temp_path proxy_temp;
Context: http,server,location
设定临时文件存放目录,以及使用几级目录
Syntax: proxy_busy_buffers_size size;
Default: proxy_busy_buffers_size 8k|16k;
Context: http,server,location
比如说,我们要收到1G的文件,当接收到前8k或者前16k的时候,我就先
向客户端响应我接收到的这部分响应
接收上游时网络速度相关指令:
Syntax: proxy_read_timeout time;
Default: proxy_read_timeout 60s;
Context: http,server,location
两次读取上游响应之间的最长时间间隔
Syntax: proxy_limit_rate rate;
Default: proxy_limit_rate 0;
Context: http,server,location
限制读取上游响应的网速
上游包体的持久化:
Syntax: proxy_store_access users:permissions ...;
Default: proxy_store_access user:rw;
Context: http,server,location
Syntax: proxy_store on|off|string;
Default: proxy_store off;
Context: http,server,location
上游包体持久化的例子:
upstream proxyups {
server 127.0.0.1:8012 weight=1;
}
server {
server_name store.taohui.tech;
error_log logs/myerror.log debug;
root /tmp;
location / {
proxy_pass http://proxyups;
# 从上面http://proxyups收到的响应会被存放在root /tmp指令指定的/tmp目录下
proxy_store on;
proxy_store_access user:rw group:rw all:r;
}
listen 80; # managed by Certbot
}
- 处理上游的响应头部
Syntax: proxy_ignore_headers field ...;
Default: --
Context: http,server,location
- 功能:某些响应头部可以改变nginx的行为,使用
proxy_ignore_headers
可以禁止它们生效 - 可以禁用功能的头部
X-Accel-Redirect: 由上游服务指定在nginx内部重定向,控制请求的执行 X-Accel-Limit-Rate: 由上游设置发往客户端的速度限制,等同
limit_rate
指令 X-Accel-Buffering: 由上游控制是否缓存上游的响应 X-Accel-Charset: 由上游控制Content-Type中的Charset 缓存相关:- X-Accel-Expires: 设置响应在nginx中的缓存时间,单位秒;@开头表示一天内某时刻
- Expires: 控制nginx缓存时间,优先级低于X-Accel-Expires
- Cache-Control: 控制nginx缓存时间,优先级低于X-Accel-Expires
- Set-Cookie: 响应中出现Set-Cookie则不缓存,可通过
proxy_ignore_headers
禁止生效 - Vary: 响应中出现
Vary: *
则不缓存,同样可禁止生效
Syntax: proxy_hide_header field;
Default: --
Context: http,server,location
功能:对于上游响应中的某些头部,设置不向客户端转发
proxy_hide_header
默认不转发响应头部:Date: 由
ngx_http_header_filter_module
过滤模块填写,值为nginx发送响应头部时的时间 Server: 由ngx_http_header_filter_module
过滤模块填写,值为nginx版本 X-Pad: 通常是Apache为避免浏览器BUG生成的头部,默认忽略 X-Accel-: 用于控制nginx行为的响应,不需要向客户端转发
Syntax: proxy_pass_header field;
Default: --
Context: http,server,location
功能:对于已经被proxy_hide_header
的头部,设置向上游转发
修改返回的Set-Cookie头部:
Syntax: proxy_cookie_domain off;
proxy_cookie_domain domain replacement;
Default: proxy_cookie_domain off;
Context: http,server,location
Syntax: proxy_cookie_path off;
proxy_cookie_path path replacement;
Default: proxy_cookie_path off;
Context: http,server,location
修改返回的Location头部:
Syntax: proxy_redirect default;
proxy_redirect off;
proxy_redirect redirect replacement;
Default: proxy_redirect default;
Context: http,server,location
演示:
upstream proxyupstream {
server 127.0.0.1:8012 weight=1;
}
server {
server_name proxy.taohui.tech;
error_log logs/myerror.log debug;
location / {
proxy_pass http://proxyupstream;
#proxy_method POST;
proxy_hide_header aaa;
#proxy_pass_header server;
#proxy_ignore_headers X-Accel-Limit-Rate;
#proxy_pass_request_headers off;
#proxy_pass_request_body off;
#proxy_set_body 'hello world!';
#proxy_set_header name '';
proxy_http_version 1.1;
proxy_set_header Connection "";
}
listen 80; # managed by Certbot
}
1.3.4 上游出现失败时的容错方案
上游返回失败时的处理办法:
Syntax: proxy_next_upstream error| timeout| invalid_header| http_500| http_502| http_503| http_504| http_403| http_404| http_429| non_idempotent| off ...;
Default: proxy_next_upstream error timeout;
Context: http,server,location
error: 主要指网络错误
timeout:
invalid_header:收到的上游服务的http head是不合法的
http_
限制proxy_next_upstream
的时间与次数:
Syntax: proxy_next_upstream_timeout time;
Default: proxy_next_upstream_timeout 0;
Context: http,server,location
Syntax: proxy_next_upstream_tries number;
Default: proxy_next_upstream_tries 0;
Context: http,server,location
用error_page
拦截上游失败响应:
当上游响应的响应码大于等于300时,将响应返回给客户端还是按error_page
指令处理
Syntax: proxy_intercept_errors on| off;
Default: proxy_intercept_errors off;
Context: http,server,location
2. 搭建websocket反向代理
模块:由ngx_http_proxy_module
模块实现
配置:
```ng
server {
listen 80;
server_name websocket.taohui.tech;
default_type text/plain;
access_log logs/ws.log;
location / {
# 加上这3行就可以将http转换为上游的websocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://echo.websocket.org;
}
}
```
特点: 数据分片必须有序传输,所以不支持多路复用
3. http2
- 模块:默认没有被编译进nginx中,需要通过
--with-http_v2_module
编译进nginx - 功能:对客户端使用http2协议提供基本功能
- 前提:开启TLS协议
- 使用方法: listen 443 ssl http2;
3.1 推送资源
Syntax: http2_push_preload on|off;
Default: http2_push_preload off;
Context: http,server,location
Syntax: http2_push uri|off;
Default: http2_push off;
Context: http,server,location
Syntax: http2_max_concurrent_pushes number;
Default: http2_max_concurrent_pushes 10;
Context: http,server
测试nginx http2协议的客户端工具:
- github: https://github.com/nghttp2/nghttp2
- centos下使用yum安装:yum install nghttp2
测试:
server {
server_name http2.taohui.tech;
root html;
location / {
#
http2_push /mirror.txt;
http2_push /video.mp4;
}
location /test {
# 只要发的头部中,含有/style.css,我们就会主动去推style.css
add_header Link "</style.css>; as=style; rel=preload";
http2_push_preload on;
}
listen 4430 ssl http2;
ssl_certificate XXX;
ssl_certificate_key xxx;
...
}
3.2 超时控制
Syntax: http2_recv_timeout time;
Defalut: http2_recv_timeout 30s;
Context: http,server
Syntax: http2_idle_timeout time;
Default: http2-idle_timeout 3m;
Context: http,server
3.3 并发请求控制
Syntax: http2_max_concurrent_pushes number;
Default: http2_max_concurrent_pushes 10;
Context: http,server
Syntax: http2_max_concurrent_streams number;
Default: http2_max_concurrent_streams 128;
Context: http,server
Syntax: http2_max_field_size size;
Default: http2_max_field_size 4k;
Context: http,server
3.4 连接最大处理请求数
Syntax: http2_max_requests number;
Default: http2_max_requests 1000;
Context: http,server
Syntax: http2_chunk_size size;
Default: http2_chunk_size 8k;
Context: http,server,location
3.5 设置缓冲区大小
Syntax: http2_recv_buffer_size size;
Default: http2_recv_buffer_size 256k;
Context: http
Syntax: http2_max_header_size size;
Default: http2_max_header_size 16k;
Context: http,server
Syntax: http2_body_preread_size size;
Default: http2_body_preread_size 64k;
Context: http,server
4. 四层反向代理
4.1 stream四层反向代理的7个阶段及常用变量
stream模块处理请求的7个阶段
阶段 | 模块 |
---|---|
POST_ACCEPT | realip |
PREACCESS | limit_conn |
ACCESS | access |
SSL | ssl |
PREREAD | ssl_preread |
CONTENT | return,stream_proxy |
LOG | access_log |
stream中的ssl:
Syntax: stream {...}
Default: --
Context: main
Syntax: server {...}
Default: --
Context: stream
Syntax: listen address:port [ssl] [udp] [proxy_protocol]
[backlog=number] [rcvbuf=size] [sndbuf=size] [bind]
[ipv6only=on|off] [reuseport]
[so_keepalive=on|off [keepidle]:[keepintvl]:[keepcnt]];
Default: --
Context: server
传输层相关的变量:
binary_remote_addr: 客户端地址的整型格式,对于IPv4是4字节,对于IPv6是16字节
connection: 递增的连接序号
remote_addr: 客户端地址
remote_port: 客户端端口
proxy_protocol_addr: 若使用了proxy_protocol协议则返回协议中的地址,否则返回空
proxy_protocol_port: 若使用了proxy_protocol协议则返回协议中的端口,否则返回空
protocol: 传输层协议,值为TCP或者UDP
server_addr: 服务器端地址
server_port: 服务器端端口
bytes_received: 从客户端接收到的字节数
bytes_sent: 已经发送到客户端的字节数
status: > 200: session成功结束
> 400: 客户端数据无法解析,例如proxy_protocol协议的格式不正确
> 403: 访问权限不足被拒绝,例如access模块限制了客户端IP地址
> 500: 服务器内部代码错误
> 502: 无法找到或者连接上游服务
> 503: 上游服务不可用
Nginx系统变量:
time_local: 以本地时间标准输出的当前时间,例如14/Nov/2018:15:55:37 +0800
time_iso8601: 使用ISO 8601标准输出的当前时间,例如2018-11-14T15:55:37+08:00
ngixn_version: Nginx版本号
pid: 所属worker进程的进程id
pipe: 使用了管道则返回p,否则返回.
hostname: 所在服务器的主机名,与hostname命令输出一致
mesc: 1970年1月1日到现在的时间,单位为秒,小数点后精确到毫秒
content阶段: return模块
Syntax: return value;
Default: --
Context: server
演示:
stream {
error_log logs/stream.log debug;
server {
listen 10002 proxy_protocol;
return '10002 server get ip: $remote_addr!\n';
}
server {
listen 10003 proxy_protocol;
return '10003 server get ip: $remote_addr!\n';
}
server {
listen 10004;
#listen 10004 proxy_protocol;
return '10004 vars:
bytes_received: $bytes_received
bytes_sent: $bytes_sent
proxy_protocol_addr: $proxy_protocol_addr
proxy_protocol_port: $proxy_protocol_port
remote_addr: $remote_addr
remote_port: $remote_port
server_addr: $server_addr
server_port: $server_port
session_time: $session_time
status: $status
protocol: $protocol
';
}
}
4.2 proxy protocol协议与realip模块
https://trac.nginx.org/nginx/ticket/1639
proxy_protocol
协议
-
v1协议
- PROXY TCP4 202.112.144.236 10.210.12.10 5678 80\r\n
- PROXY TCP6 2001:da8:205::100 2400:89c0:2110:1::21 6324 80\r\n
- PROXY UKNOWN\r\n
-
v2协议
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
typedef struct { //12字节签名: \r\n\r\n\0\r\nQUIT\n u_char signature[12]; //4位协议版本号: 2 //4位命令:0表示LOCAL,1表示PROXY,nginx仅支持PROXY u_char version_command; //4位地址族:1表示IPV4,2表示IPV6 //4位传输层协议:1表示TCP,2表示UDP,nginx仅支持TCP协议 u_char family_transport; //2字节地址长度 u_char len[2]; } ngx_proxy_protocol_header_t; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | Proxy Protocol V2 Signature | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |version|command| AF |Proto. | Address Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | IPv4 Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | IPv4 Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | Proxy Protocol V2 Signature | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |version|command| AF |Proto. | Address Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | IPv6 Source Address | + + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | IPv6 Destination Address | + + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 读取
proxy_protocol
协议的超时控制
Syntax: proxy_protocol_timeout timeout;
Default: proxy_protocol_timeout 30s;
Context: stream,server
- stream处理
proxy_protocol
的流程
{连接建立成功,是否携带listen proxy_protocol?}
V
+--------------N--<?>
| y|
| v
| {加入读定时器proxy_protocol_timeout(默认30秒)}
| v
| {读取107字节(proxy_protocol最大长度)}
| v
| {判断前12字节是否匹配V2协议的头部}
| v
| +-----------Y-<?>
| | N|
| | {读取v1协议头部的真实IP地址}----+
| | |
| +>{读取v2协议头部的真实IP地址} |
| v |
+---->{进入7个阶段的stream模块处理}<--+
post_accept
阶段:realip模块 功能: 通过proxy_protocol
协议取出客户端真实地址,并写入remote_addr
及remote_port
变量。同时使用realip_remote_addr
和realip_remote_port
保留 TCP连接中获得的原始地址。 模块:默认不编译进nginx,使用--with-stream_realip_module
启动该功能 指令:
Syntax: set_real_ip_from address |CIDR |unix;
Default: --
Context: stream, server
- docker容器中获取到的x-forwarded-for是docker网桥的ip,原因?
4.3 限并发连接、限IP、记日志
- PREACCESS阶段的
limit_conn
模块 功能: 限制客户端的并发连接数。使用变量自定义限制依据,基于共享内存, 所有worker进程同时生效。 模块: 默认编译进nginx,通过--without-stream_limit_conn_module
禁用模块。 指令:
Syntax: limit_conn_zone key zone=name:size;
Default: --
Context: stream
Syntax: limit_conn zone number;
Default: --
Context: stream,server
Syntax: limit_conn_log_level info|notice|warn|error;
Default: limit_conn_log_level error;
Context: stream,server
- ACCESS阶段的access模块
功能:
根据客户端地址(realip模块可以修改地址)决定连接的访问权限
模块:模块编译进nginx,通过
--without-stream_access_module
禁用。 指令:
Syntax: allow address|CIDR|unix:|all;
Default: --
Context: stream,server
Syntax: deny address|CIDR|unix|all;
Default: --
Context: stream,server
- log阶段:
stream_log
模块
Syntax: access_log path format [buffer=size] [gzip[=level]] [flush=time] [if=condition];
access_log off;
Default: access_log off;
Context: stream, server
注意,这里的format指向log_format指令指定的name
Syntax: log_format name [escape=default|json|none] string ...;
Default: --
Context: stream
Syntax: open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
Default: open_log_file_cache off;
Context: stream,server
4.4 stream四层反向代理处理SSL下游流量
-
stream中的ssl 功能:使stream反向代理对__下游__支持TLS/SSL协议 模块:默认不编译进nginx,通过
--with-stream_ssl_module
加入 -
对比stream ssl指令和http ssl指令
stream ssl http ssl 配置服务器证书 ssl_certificate ssl_certificate 配置服务器证书私钥 ssl_certificate_key ssl_certificate_key 指定安全套件 ssl_ciphers ssl_ciphers 指定吊销证书链CRL ssl_crl ssl_crl 密码交换DH算法参数 ssl_dhparam ssl_dhparam 指定密码交换时使用哪条椭圆曲线 ssl_ecdh_curve ssl_ecdh_curve TLS握手的超时时间 ssl_handshake_timeout 指定私钥的密码文件 ssl_password_file ssl_password_file 是否启用服务器偏好的安全套件 ssl_prefer_server_ciphers ssl_prefer_server_ciphers 指定支持的TLS协议 ssl_protocols ssl_protocols 使用session缓存提升性能 ssl_session_cache ssl_session_cache 指定使用ticket票据时的加解密文件,默认使用随机字串 ssl_session_ticket_key ssl_session_ticket_key 是否启用ticket票据 ssl_session_ticket_key ssl_session_ticket_key 指定session重用的超时时间 ssl_session_timeout ssl_session_timeout 是否验证客户端的证书 ssl_verify_client ssl_verify_client 可信CA证书,用于验证客户端证书 ssl_client_certificate ssl_client_certificate 验证客户端证书是否可信 ssl_trusted_certificate ssl_trusted_certificate 验证客户端证书链的深度 ssl_verify_depth ssl_verify_depth -
stream ssl模块提供的变量
- 安全套件
ssl_cipher
: 本地通信选用的安全套件,例如ECDHE-RSA-AES128-GCM-SHA256ssl_ciphers
: 客户端支持的所有安全套件ssl_protocol
: 本次通讯选用的TLS版本,例如TLSv1.2ssl_curves
: 客户端支持的椭圆曲线,例如secp384r1:secp521r1
- 证书
ssl_client_raw_cert
: 原始客户端证书内容ssl_client_escaped_cert
: 返回客户端证书做urlencode编码后的内容ssl_client_cert
: 对客户端证书每一行内容前加tab制表符空白,增强可读性。ssl_client_fingerprint
: 客户端证书的SHA1指纹。
- 证书结构化信息
ssl_server_name
: 通过TLS插件SNI(Server Name Indication)获取到的服务域名ssl_client_i_dn
: 依据RFC2253获取到证书issuer dn信息,例如:CN=…,O=…,L=…,C=…ssl_client_i_dn_legacy
: stream模块不再支持这种比较老的格式了ssl_client_s_dn
: 依据RFC2253获取到证书subject dn信息,例如:CN=…,OU=…,O=…,L=…,ST=…,C=…ssl_client_s_dn_legacy
: stream模块不再支持这种比较老的格式了
- 证书有效期
ssl_client_v_end
: 返回客户端证书的过期时间,例如Dec 1 11:56:11 2028 GMTssl_client_v_remain
: 返回还有多少天客户端证书过期,例如针对上面的ssl_client_v_end
其值为3649ssl_client_v_start
: 客户端证书的颁发日期,例如Dec 4 11:56:11 2018 GMT
- 连接有效性
ssl_client_serial
: 返回连接上客户端证书的序列号,例如8BE947674841BD44ssl_early_data
: stream模块目前还未提供,TLS1.3专用ssl_client_verify
: 如果验证失败则为FAILED:原因,如果没有验证证书则为NONE,验证成功则为SUCCESSssl_session_id
: 已建立连接的sessionidssl_session_reused
: 如果session被复用(参考session缓存)则为r,否则为.
4.5 stream_preread模块取出SSL关键信息
-
模块:默认不会被加载到nginx中,需要使用
--with-stream_ssl_preread_module
来启用 -
功能:解析下游TLS证书中信息,以变量方式赋能其他模块(不会剥离TLS证书)
-
提供的变量:
$ssl_preread_protocol
- 客户端支持的TLS版本中最高的版本,例如TLSv1.3
$ssl_preread_server_name
- 从SNI中获取的服务器域名
$ssl_preread_alpn_protocols
- 通过ALPN中获取到的客户端建议使用的协议,例如h2, http/1.1
-
指令
Syntax: preread_buffer_size size;
Default: preread_buffer_size 16k;
Context: stream,server
Syntax: preread_timeout timeout;
Default: preread_timeout 30s;
Context: stream,server
Synatx: ssl_preread on|off;
Default: ssl_preread off;
Context: stream,server
4.6 stream proxy四层反向代理的用法
- 模块:
ngx_stream_proxy_module
,默认在Nginx中 - 功能:
- 提供TCP/UDP协议的反向代理
- 支持与上游的连接使用TLS/SSL协议
- 支持与上游的连接使用proxy protocol协议
- proxy模块对上下游的限速指令
限制读取上游服务数据的速度:
Syntax: proxy_download_rate rate;
Default: proxy_download_rate 0;
Context: stream,server
限制读取客户端数据的速度:
Syntax: proxy_upload_rate rate;
Default: proxy_upload_rate 0;
Context: stream,server
{客户端}
1| ^2
v |
{nginx} 1. proxy_upload_rate
3| ^4 4. proxy_download_rate
v | 2,3是无法做限速的
{上游服务}
-
Stream反向代理指令
stream反向代理 http反向代理 指定上游 proxy_pass proxy_pass 连接绑定地址 proxy_bind proxy_bind 该值同时用于定义接收上游数据、接收下游数据的缓存区大小 proxy_buffer_size proxy_buffer_size 连接上游超时时间 proxy_connect_timeout proxy_connect_timeout TCP连接使用proxy_protocol协议 proxy_protocol 出错时更换上游 proxy_next_upstream proxy_next_upstream 更换上游超时 proxy_next_upstream_timeout proxy_next_upstream_timeout 更换上游重试次数 proxy_next_upstream_tries proxy_next_upstream_tries 读取响应超时时间 proxy_timeout proxy_read_timeout 发送请求超时时间 proxy_tmeout proxy_send_timeout 使用TCPkeepalive proxy_socket_keepalive proxy_socket_keepalive -
stream ssl指令与http proxy模块对照表
stream http反向代理 是否对上游使用ssl proxy_ssl 配置服务器证书 proxy_ssl_certificate proxy_ssl_certificate 配置服务器证书私钥 proxy_ssl_certificate_key proxy_ssl_certificate_key 指定安全套件 proxy_ssl_ciphers proxy_ssl_ciphers 指定吊销证书链CRL proxy_ssl_crl proxy_ssl_crl 指定域名验证上游证书中域名 proxy_ssl_name proxy_ssl_name 当私钥有密码时指定密码文件 proxy_ssl_password_file proxy_ssl_password_file 指定具体某个版本的协议 proxy_ssl_protocols proxy_ssl_protocols 传递SNI信息至上游 proxy_ssl_server_name proxy_ssl_server_name 是否重用SSL连接 proxy_ssl_session_reuse proxy_ssl_session_reuse 验证上游服务的证书 proxy_ssl_trusted_certificate proxy_ssl_trusted_certificate 是否验证上游服务的证书 proxy_ssl_verify proxy_ssl_verify 设置验证证书链的深度 proxy_ssl_verify_depth proxy_ssl_verify_depth -
实验
# 1. 上游服务的配置
server {
error_log logs/myerror.log debug;
server_name "";
listen 9001 proxy_protocol;
location / {
/return 200 'proxy_protocol_addr: $proxy_protocol_addr,proxy_protocol_port: $proxy_protocol_port\n';
}
}
# 2. 反向代理的配置
log_format ssllog '$connection $remote_add [$time_total] '
'$protocol $status $bytes_sent $bytes_received $session_time';
error_log logs/stream_error.log debug;
access_log logs/stream_access.log ssllog;
server {
listen 4435;
proxy_pass localhost:9001;
proxy_protocol on;
}
4.7 UDP反向代理
Syntax: proxy_requests number;
Default: proxy_requests 0;
Context: stream,server
功能: 指定一次会话session中最多从客户端接收到多少报文就结束session。(1.15.7非稳定版本)
* 仅会话结束时才会记录access日志
* 同一个会话中,nginx使用同一个端口连接上游服务
* 设置为0表示不限制,每次请求都会记录access日志
Syntax: proxy_responses number;
Default: --
Context: stream,server
功能:指定对应一个请求报文,上游应返回多少个响应报文。
* 与proxy_timeout结合使用,控制上游服务是否不可用
测试:
log_format udplog '$connection $remote_addr [$time_total]'
'$protocol $status $bytes_sent $bytes_received $session_time';
server {
listen 4436 udp;
proxy_pass localhost:9999;
proxy_requests 1;
proxy_responses 2;
proxy_timeout 2s;
access_log logs/udp_access.log udplog;
}
4.8 透传IP地址的3个方案
-
使用
proxy_protocol
协议 -
修改IP报文:
- 步骤
- 修改IP报文中的源地址
- 修改路由规则
- 方案
- IP地址透传:经由nginx转发上游返回的报文给客户端(TCP/UDP)
- DSR: 上游直接发送报文给客户端(仅UDP)
- 步骤
-
nginx如何实现ip地址透传
{客户端: IP地址是A}
源地址:A | ^
目标地址:B| |源地址:B
v |目的地址:A
+--------------------------------------------+
| { nginx } |
| | ^设源地址为C的报文转发 |
| | |本机nginx监听端口 |
+--------------------------------------------+
源地址:B->A| ^源地址:C
目标地址:C v |目标地址: A
+--------------------------------------------+
| | |网关改为B |
| v | |
| { 上游服务进程 } |
+--------------------------------------------+
proxy_bind $remote_addr transparent;
- 实现上图中的
源地址:B->A
- 实现上图中的
- 调节上游服务所在主机上的网关为nginx所在主机:
- 调节nginx所在主机上的路由规则,使它把接收自上游的、目标IP是客户端IP的报文转发给nginx进程
- nginx如何实现DSR
# 上游服务没有公网,需要借助nginx的公网ip
{客户端: IP地址是A}
源地址:A | ^
目标地址:B | |源地址:B
v |目的地址:A
+---------------------------------------------+
| { nginx } | |
| | | |
| | |源地址:C->B,并转发 |
+---------------------------------------------+
源地址:B->A | ^
(源端口修改)| |源地址:C
目标地址:C v |目标地址: A
+---------------------------------------------+
| | |网关改为B |
| v | |
| { 上游服务进程 } |
+---------------------------------------------+
###############################################
###############################################
# 上游服务有公网IP
{客户端: IP地址是A}
源地址:A | ^
目标地址:B | |
v |
+-------------------+ |
| { nginx } | |
| | | |源地址: C->B
| | | |目标地址: A
+-------------------+ |
源地址:B->A | |
(源端口修改)| |
目标地址:C v |
+----------------------------------+
| | | |
| v | |
| { 上游服务进程 } |
+----------------------------------+
- 加
proxy_responses 0
proxy_bind $remote_addr:$remote_port transparent;
- 对应上图的
源地址:B->A(源端口修改)
- 对应上图的
- 若上游服务在内网无公网ip,则可由nginx所在主机转发
- 在上游服务所在主机上添加路由
route add default gw nginx-ip-address
- 在上游服务所在主机上添加路由
- 允许操作系统转发ip报文
sysctl -w net.ipv4.ip_forward=1
- 转发时修改源地址为nginx所在主机的地址(
源地址:C->B
)1 2 3 4 5
$ tc qdisc add dev eth0 root handle 10: htb $ tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.11 match ip sport 53 action nat egress 172.16.0.11 192.168.99.10 $ tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.12 match ip sport 53 action nat egress 172.16.0.12 192.168.99.10 $ tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.13 match ip sport 53 action nat egress 172.16.0.13 192.168.99.10 $ tc filter add dev eth0 parent 10: protocol ip prio 10 u32 match ip src 172.16.0.14 match ip sport 53 action nat egress 172.16.0.14 192.168.99.10
- 问题:
- nginx检查不到上游服务是否回包
- 负载均衡策略受限
附录: 对上游使用SSL连接
双向认证时的指令示例:
指定自身使用的证书: 验证客户端证书:
proxy_ssl_certificate ssl_verify_client
http proxy_ssl_certificate_key https双向认证 ssl_client_certificate
客户端----------> nginx --------------------> nginx
<---------- <--------------------
验证服务器证书: 指定自身使用的证书:
proxy_ssl_verify ssl_certificate
proxy_ssl_trusted_certificate ssl_certificate_key
对下游使用证书:
Syntax: ssl_certificate file;
Default: --
Context: http,server
Syntax: ssl_certificate_key file;
Default: --
Context: http,server
验证下游证书:
Syntax: ssl_verify_client on| off| optional| optional_no_ca;
Default: ssl_verify_client off;
Context: http,server
Syntax: ssl_client_certificate file;
Default: --
Context: http,server
功能: 指定验证用的ca根证书的位置
对上游使用证书:
Syntax: proxy_ssl_certificate file;
Default: --
Context: http,server,location
Syntax: proxy_ssl_certificate_key file;
Default: --
Context: http,server,location
验证上游的证书:
Syntax: proxy_ssl_trusted_certificate file;
Default: --
Context: http,server,location
功能: 指定验证用的ca根证书的位置
Syntax: proxy_ssl_verify on| off;
Default: proxy_ssl_verify off;
Context: http,server,location
ssl模块提供的变量:
- 安全套件:
ssl_cipher
: 本次通讯选用的安全套件,例如ECDHE-RSA-AES128-GCM-SHA256
ssl_ciphers
: 客户端支持的所有安全套件ssl_protocol
: 本地通讯选用的TLS版本,例如TLSv1.2ssl_curves
: 客户端支持的椭圆曲线,例如secp384r1:secp521r1 - 证书:
ssl_client_raw_cert
: 原始客户端证书内容ssl_client_escaped_cert
: 返回客户端证书做urlencode编码后的内容ssl_client_cert
: 对客户端证书每一行内容前加tab制表符空白,增强可读性ssl_client_fingerprint
: 客户端证书的SHA1指纹 - 证书结构化信息:
ssl_server_name
: 通过TLS插件SNI(Server Name Indication)获取到的服务域名ssl_client_i_dn
: 依据RFC2253获取到证书issuer dn信息,例如:CN=…,O=…,L=…,C=…ssl_client_i_dn_legacy
: 依据RFC2253获取到证书issuer dn信息,例如: /C=…/L=…/O=…/CN=…ssl_client_s_dn
: 依据RFC2253获取到证书subject dn信息,例如:CN=…,OU=…,O=…,L=…,ST=…,C=…ssl_client_s_dn_legacy
: 同样获取subject dn信息,格式为:/C=…/ST=…/L=…/O=…/OU=…/CN=… - 证书有效期:
ssl_client_v_end
: 返回客户端证书的过期时间,例如Dec 1 11:56:11 2028 GMTssl_client_v_remain
: 返回还有多少天客户端证书过期,例如针对上面的ssl_client_v_end
其值为3649ssl_client_v_start
: 客户端证书的颁发日期,例如Dec 4 11:56:11 2018 GMT - 连接有效性:
ssl_client_serial
: 返回连接上客户端证书的序列号,例如8BE947674841BD44ssl_early_data
: 在TLS1.3协议中使用了early data且握手未完成则返回1,否则返回空字符串ssl_client_verify
: 如果验证失败为FAILED:原因,如果没有验证证书则为NONE,验证成功则为SUCCESSssl_session_id
: 已建立连接的sessionidssl_session_reused
: 如果session被复用(参考session缓存),则为r,否则为.
创建证书命令示例:
- 创建根证书:
创建CA私钥: openssl genrsa -out ca.key 2048 制作CA公钥:openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
- 签发证书:
创建私钥: openssl genrsa -out a.key 1024 生成签发请求 openssl req -new -key a.key -out a.csr 使用CA证书进行签发: openssl x509 -req -sha256 -in a.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out a.crt 验证签发证书是否正确 openssl verify -CAfile ca.crt a.crt
上游配置a:
server {
server_name cache.taohui.tech;
root html/;
error_code logs/cacherr.log debug;
listen 443 ssl;
ssl_certificate examples/cert/a.crt;
ssl_certificate_key examples/cert/a.key;
ssl_verify_client optional;
ssl_verify_depth 2;
ssl_client_certificate examples/cert/ca.crt;
location /test {
default_type text/plain;
return 200 '
ssl_client_escaped_cert: $ssl_client_escaped_cert
ssl_client_cert: $ssl_client_cert
ssl_client_raw_cert: $ssl_client_raw_cert
ssl_cipher: $ssl_cipher
ssl_ciphers: $ssl_ciphers
ssl_client_fingerprint: $ssl_client_fingerprint
ssl_client_i_dn: $ssl_client_i_dn
ssl_client_i_dn_legacy: $ssl_client_i_dn_legacy
ssl_client_s_dn: $ssl_client_s_dn
ssl_client_s_dn_legacy: $ssl_client_s_dn_legacy
ssl_client_serial: $ssl_client_serial
ssl_client_v_end: $ssl_client_v_end
ssl_client_v_remain: $ssl_client_v_remain
ssl_client_v_start: $ssl_client_v_start
ssl_client_verify: $ssl_client_verify
ssl_curves: $ssl_curves
ssl_protocol: $ssl_protocol
ssl_server_name: $ssl_server_name
ssl_session_id: $ssl_session_id
ssl_session_reused: $ssl_session_reused
';
}
}
下游配置b:
server {
listen 8090;
location /test {
error_log logs/error.log debug;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate examples/cert/ca.crt;
proxy_ssl_name a;
proxy_ssl_verify_depth 4;
proxy_ssl_certificate examples/cert/b.crt;
proxy_ssl_certificate_key examples/cert/b.key;
proxy_ssl_server_name on;
proxy_pass https://cache.taohui.tech;
}
}
本文发表于 0001-01-01,最后修改于 0001-01-01。
本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。