Nginx 最强大的地方是在于其 HTTP 请求的反向代理,也即常说的七层反向代理。在这一层代理中,通过 Nginx 框架提供的相关配置,我们能在该层将发送过来的 http 协议转换成各种其他的协议比如 fastcgi 协议、uwsgi协议、grpc、http(高版本协议)、websocket协议等。这样使用 Nginx 框架,我们可以支持多种应用服务(java web、python web等)的反向代理。
Nginx 从1.9.0开始,新增加了一个 stream 模块,用来实现四层协议( TCP 或 UDP 协议)的转发、代理或者负载均衡。这层比较简单,只是单纯将 TCP 或 UDP 层的流量转发到上游服务器中。接下来,我们将分别介绍这两种反向代理的基本用法。
前面我们刚开始使用 Nginx 时只是用了 http 指令块,因为是针对 http 请求进行处理。这进行的是四层反向代理,转发 TCP 或者 UDP 协议的报文。针对该层的处理,Nginx 是使用了 stream 模块进行处理,对应的是 stream 指令块,它和 http 指令块非类似,用法几乎一致。stream 指令块里面可以包含 server 指令块,server 指令块里面也可以包含 listen 指令块指定监听的端口、还可以包含 proxy_pass
指令,对该端口监听的 tcp 或者 udp 报文进行转发。总之,和 http 指令块大部分用法一致。
... stream { ... server { listen 3440; # 转发四层流量 proxy_pass 192.168.1.103:3440; } ... } ...
代码块预览 复制
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
此外,从nginx-1.11.2版开始, ngx_stream_core_module,也同 http 模块一样支持变量,部分支持变量如下,这和 http 模块也是类似的,甚至连变量名都非常相似:
$binary_remote_addr: 二进制格式的客户端地址 $bytes_received: 从客户端接收到的字节数 $bytes_sent: 发往客户端的字节数 $hostname: 连接域名 $msec: 毫秒精度的当前时间 $nginx_version: nginx的版本 $pid: worker进程号 $protocol: 通信协议(UDP or TCP) $remote_addr: 客户端ip $remote_port: 客户端端口 $server_addr: 接受连接的服务器ip,计算此变量需要一次系统调用。所以避免系统调用,在listen指令里必须指定具体的服务器地址并且使用参数bind。 $server_port: 接受连接的服务器端口 $session_time: 毫秒精度的会话时间(版本1.11.4开始) $status: 会话状态(版本1.11.4开始), 可以是一下几个值: 200 成功 400 不能正常解析客户端数据 403 禁止访问 500 服务器内部错误 502 网关错误,比如上游服务器无法连接 503 服务不可用,比如由于限制连接等措施导致 $time_iso8601: ISO 8601时间格式 $time_local: 普通日志格式的时间戳
代码块预览 复制
- 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
nginx 七层方向代理处理的是 http 请求,对应的是 http 协议。如果只是转发 http 请求,可以简单使用 proxy_pass 指令即可。这和我们之前简单的反向代理示例一致。
# 在转发 http 请求时,URL必须以 http 或者 https 开头 Syntax: proxy_pass URL; Default: — Context: location, if in location, limit_except
代码块预览 复制
- 1
- 2
- 3
- 4
- 5
在使用 prxoy_pass 指令对 http 或者 https 协议进行反向代理时,需要注意一下问题:
- 在 URL 不携带 URI 时,会将对应的 URL 直接转发到上游服务器
- 在 URL 携带 URI 时,会将 location 参数中匹配上的那一段替换为该URL
看下面的示例配置:
... http { server { listen 8000; location /test { proxy_pass http://ip:port/xyz; } } server { listen 9000; location /test { proxy_pass http://ip:port; } } } ...
代码块预览 复制
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
在代理 http 请求 http://主机ip:8000/test/abc 时,由于 proxy_pass 指令后面的 URL 带了 /xyz 这样的路径,所以转发的请求是 http:// ip:port/xyz/abc,其中匹配的 /test 已经被替换掉了。而对于第二个 http 请求 http://主机ip:9000/test/abc 时,由于 proxy_pass指令后面直接是上游服务器地址,没有带 URI,所以转发的请求为 http://ip:port/test/abc,其中匹配到的/test并没有被替换。
本节实战中,我们准备好两个案例测试,一个是测试使用 stream 模块进行四层方向代理测试;另一个案例测试前面提到的七层代理中 proxy_pass 指令的用法,主要实战前面提到的注意点。
在nginx.conf的中加入如下配置:
... stream { server { listen 3000; return '3000 server get ip: $remote_addr!\n'; } server { listen 30; # 注意,只写ip和port,不要加上[http:]之类的,这里是四层的协议 proxy_pass 127.0.0.1:3000; } } ...
代码块预览 复制
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
启动 nginx 后,我们在外面通过 telnet 命令访问该主机的 3000 和 30端口,可以看到如下结果:
[shen@shen ~]$ telnet 180.76.152.113 3000 Trying 180.76.152.113... Connected to 180.76.152.113. Escape character is '^]'. 3000 server get ip: 103.46.244.108! [shen@shen ~]$ telnet 180.76.152.113 30 Trying 180.76.152.113... Connected to 180.76.152.113. Escape character is '^]'. 3000 server get ip: 127.0.0.1! Connection closed by foreign host.
代码块预览 复制
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
可以看到,访问30端口时,nginx 帮我们转发 tcp 层流量到 3000端口,最后返回了相关响应字符串。
在 nginx.conf 中加入如下的测配置:
... http { server { listen 8000; return 200 '$uri\n'; } server { listen 9001; location /test { proxy_pass http://127.0.0.1; } } server { listen 9002; location /test { proxy_pass http://127.0.0.1/xyz; } } } ...
代码块预览 复制
- 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
启动 nginx 后,通过请求服务器的8000端口,我们可以知道请求的 uri 值,然后测试经过两种类型的 proxy_pass 配置后最后的 uri 的值。具体操作以及结果如下:
# 测试8000端口显示的uri值 [shen@shen ~]$ curl http://180.76.152.113:8000/test/abc /test/abc # 9001端口配置中proxy_pass后面的URL不带URI [shen@shen ~]$ curl http://180.76.152.113:9001/test/abc /test/abc # 9002端口配置中proxy_pass后面的URL带URI,会替换到匹配的/test [shen@shen ~]$ curl http://180.76.152.113:9002/test/abc /xyz/abc
代码块预览 复制
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
本节中介绍了 Nginx 的四层反向代理和七层反向代理,并用案例进行了演示。刚开始使用时只是用了 http 指令块,因为是针对 http 请求进行处理。这进行的是四层反向代理。nginx 七层方向代理处理的是 http 请求,对应的是 http 协议。如果只是转发 http 请求,可以简单使用 proxy_pass 指令即可。这和我们之前简单的反向代理示例一致。