Nginx代理服务器
导航: 这里将Nginx的一些配置进行整合。根据导航比较容易找到对应的文档。资料来自于weixueyuan 5.Nginx 缓存 |
Nginx 不仅可以搭建 Web 服务器对外提供内容服务,还可以实现对客户端访问的代理功能。
代理是客户端请求数据处理的中间角色,它本身并不产生响应数据,只是将客户端的请求转发给目标应用服务器,然后目标应用服务器再将响应数据通过代理返回客户端。Nginx 不仅可以实现 HTTP 协议的代理,还支持 TCP/UDP 及基于 HTTP/2 的 gRPC 代理。
1.Nginx HTTP代理服务器
代理功能根据应用方式的不同可以分为正向代理和反向代理。正向代理是客户端设置代理地址后,以代理服务器的 IP 作为源 IP 访问互联网应用服务的代理方式;反向代理则是客户端直接访问代理服务器,代理服务器再根据客户端请求的主机名、端口号及 URI 路径等条件判断后,将客户端请求转发到应用服务器获取响应数据的代理方式。
1.模块指令
Nginx 的 HTTP 代理功能是通过 ngx_http_proxy_module 模块实现的,该模块会被默认构建,无须特殊配置编译参数。配置指令如下表所示。
指令名称 | 指令值格式 |
默认值 | 指令说明 |
proxy_bind | address[transparent] 或 off | -- |
设置从指定的本地 IP 地址及端口与被代理服务器建立连接,指令值可以是变量。指令值参数为 transparent 时,允许将客户端的真实 IP 透传给被代理服务器, 并将客户端的真实 IP 设置为访问被代理服务器的源 IP;指令值参数为 off 时,取消上一层指令域同名指令的配置 |
proxy_buffering | on 或 off | on | 设置是否启用响应数据缓冲区 |
proxy_buffers | number size | 4k 或 8k |
设置每个连接从被代理服务器接收响应数据的缓冲区数量及单个缓冲区的大小。默认单个缓冲区的大小与操作系统的单个内存页(Page Size)的大小相等。 缓冲区至少有 2 个 |
proxy_buffer_size | size | 4k 或 8k | 设置用于读取被代理服务器响应数据第一部分的缓冲区大小,默认值等于操作系统的单个内存页的大小 |
proxy_busy_buffers_size | size | 8k 或 16k |
当每个连接从被代理服务器接收响应数据时,限制 proxy_buffers 设置的缓冲区中可用于向客户端发送响应数据的缓冲区大小,以使其余的缓冲区用于从被 代理服务器接收响应数据。该值必须大于单个缓冲区或 proxy_buffer_size 的大小,小于总缓冲区减掉一个缓冲区的大小。默认值为单个缓冲区大小的 2 倍 |
proxy_limit_rate | rate | 0 | 限制从被代理服务器读取响应的每个请求的流量速度,单位是字节/秒,指令值为“0”时表示不限制。该指令只有在 proxy_buffering 启用时才有效 |
proxy_max_temp_file_size | size | 1024m |
当响应数据超出响应数据缓冲区的大小时,超出部分数据将存储到临时文件中。该指令设置临时文件的最大值,指令值为“0”时,关闭存储临时文件的功能。该值必 须大于单个缓冲区或 proxy_buffer_size 的大小 |
proxy_temp_file_write_size | size | 8k 或 16k |
限制一次写入临时文件的数据大小,默认值为 2 个缓冲区的大小。在默认配置下,缓冲区大小由 proxy_buffer_size 和 proxy_buffers 指令配置限制,最大值是 proxy_max_temp_file_size 指令的值 |
proxy_temp_path | path [level1 [level2 [level3]]] | proxy_temp | 设置临时文件存储目录 |
proxy_request_buffering | on 或 off | on |
设置是否将请求转发给被代理服务器之前,先从客户端读取整个请求体。若禁用该功能,Nginx 接收到请求体时会立即转发给被代理服务器,已经发送请求体的请求, 将无法使用 proxy_next_upstream 指令功能。对于基于 HTTP/1.1 协议的分块传输请求,会强制读取完整请求体 |
proxy_pass | address | -- | 设置连接被代理服务器的协议、IP 地址或套接字,也可以是域名或 upstream 定义的服务器组 |
proxy_method | method | -- | 将当前客户端的请求方法改为指令值设定的请求方法,并向被代理服务器发送请求 |
proxy_pass_request_body | on 或 off | on | 设置是否将客户端请求体传递给被代理服务器 |
proxy_pass_request_headers | on 或 off | on | 设置是否将客户端请求头传递给被代理服务器 |
proxy_set_header | field value | -- | 在转发给被代理服务器前,修改或添加客户端的请求头属性字段 |
proxy_set_body | value | -- | 修改客户端的请求体为指令值指定的内容,指令值可以是文本、变量及其组合 |
proxy_redirect | default 或 off 或 redirect replacement | default | 替换被代理服务器返回的响应头中属性字段 location 或 Refresh 的值,并返回给客户端。指令值为 default 时,使用 proxy_pass 指令值的内容进行替换 |
proxy_cookie_domain | off 或 domain replacement | off | 修改被代理服务器返回的响应头属性字段 Set-Cookie 中 domain 的内容,支持正则及变量 |
proxy_cookie_path | off 或 path replacement | off | 修改被代理服务器返回的响应头属性字段 Set-Cookie 中 path 的内容,支持正则及变量 |
proxy_force_ranges | on 或 off | off | 无论被代理服务器的 HTTP 响应头中是否有属性字段 Accept-Ranges,都启用 byte-range 请求支持 |
proxy_hide_header | field | -- | 指定被代理服务器响应数据中不向客户端传递的 HTTP 头字段名称 |
proxy_pass_header | field | -- | 默认配置下 Nginx 不会将头属性字段 Status 和 X-Accel-... 传递给客户端,可通过该指令开放传递 |
proxy_headers_hash_bucket_size | size | 64 | 设置指令 proxy_set_header 及 proxy_hide_header 使用哈希表的桶的大小 |
proxy_headers_hash_max_size | size | 512 | 设置指令 proxy_set_header 及 proxy_hide_header 使用哈希表的大小 |
proxy_ignore_headers | field... | -- | 设置 Nginx 对被代理服务器响应头包含指定字段时,不执行响应操作。如 Expires 和 Cache-Control |
proxy_send_lowat | size | 0 | 设置 FreeBSD 系统中,使用 kqueue 驱动时 socket 接口 SO_SNDLOWAT 选项的大小。在 Linux、Solaris 及 Windows 平台,该指令无效 |
proxy_connect_timeout | time | 60s | Nginx 与被代理服务器建立连接的超时时间,通常不应该超过 75s,与请求是否返回响应无关 |
proxy_read_timeout | time | 60s | 在连续两个从被代理服务器接收数据的读操作之间的间隔时间超过设置的时间时,将关闭连接 |
proxy_send_timeout | time | 60s | 在连续两个发送到被代理服务器的操作之间的间隔时间超过设置的时间时,将关闭连接 |
proxy_ignore_client_abort | on 或 off | off | 设置当客户端未接收响应就关闭连接时,是否关闭 Nginx 与被代理服务器的连接。默认配置下,Nginx 会记录日志响应码 499,并关闭连接 |
proxy_http_version | 1.0 | 1.0 或 1.1 | 设置用于代理的 HTTP 协议版本,若使用 keepalive 或 NTLM 认证,建议指令值设置为 1.1 |
proxy_socket_keepalive | on 或 off | off | 设置 Nginx 与被代理服务器的 TCP keepalive 行为的心跳检测机制,默认使用操作系统的 socket 配置。若指令值为 on,则开启 SO_KEEPALIVE 选项进行心跳检测 |
proxy_intercept_errors | on 或 off | off | 当指令值为 on 时,将拦截被代理服务器响应码大于或等于 300 的结果,error_page 指令可对该结果做后续处理;当指令值为 off 时,直接返回给客户端 |
proxy_next_upstream | error、timeout、 invalid_header、 http_500、http_502、 http_503、http_504、 http_403、http_404、 http_429、 non_idempotent、 off... |
enror timeout | 当出现指令值中指定的条件时,将未返回响应的客户端请求传递给 upstream 中的下一个服务器 |
proxy_next_upstream_timeout | time | 0 | 设置将符合条件的客户端请求传递给 upstream 中下一个服务器的超时时间。“0”为不做超时限制,此时须遍历完所有上游服务器组中的服务器 |
proxy_next_upstream_tries | number | 0 | 设置将符合条件的客户端请求传递给 upstream 中下一个服务器的尝试次数,包括第一次失败次数。“0”为不做尝试次数限制,此时须遍历完所有上游服务器组中的服务器 |
proxy_ssl_protocols | [SSLv2][SSLv3] [TLSv1][TLSv1.1] [TLSv1.2][TLSv1.3] |
TLSv1 TLSv1.1 TLSv1.2 | 指定可用于 Nginx 与被代理服务器建立 SSL 连接的 SSL 协议版本 |
proxy_ssl_server_name | on 或 off | off | 在与被代理服务器建立 HTTPS 连接时,设置是否启用通过 SNI 或 RFC 6066 传递主机名 |
proxy_ssl_ciphers | ciphers | DEFAULT | 设置与被代理服务器建立 SSL 连接时用于协商使用的加密算法组合,又称密码套件,指令值内容为 openssl 的密码套件名称,多个套件名称由“:”分隔 |
proxy_ssl_session_reuse | on 或 off | off | 决定是否启用与被代理服务器 HTTPS 连接的 SSL 会话重用功能 |
proxy_ssl_certificate | file | -- | 指定被代理服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书文件 |
proxy_ssl_certificate_key | file | -- | 指定被代理服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书私钥文件 |
proxy_ssl_password_file | file | -- | 存放被代理服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书私钥文件的密码文件,一个密码一行。有多个密码时,Nginx 会依次尝试 |
proxy_ssl_verify | on 或 off | off | 设置是否启用对被代理服务器的 SSL 证书验证功能 |
proxy_ssl_crl | file | -- | 证书吊销列表文件,用以验证被代理服务器 SSL 证书有效性的 PEM 格式文件 |
proxy_ssl_trusted_certificate | file | -- | 指定一个 PEM 格式 CA 证书(根或中间证书)文件,该证书用作被代理服务器的证书链验证 |
proxy_ssl_name | name | $proxy_host | 指定对被代理服务器 SSL 证书验证的主机名 |
proxy_ssl_verify_depth | number | 1 | 设置对被代理服务器 SSL 证书链的验证深度 |
关于上表,有以下几点需要说明。
-
- 在 ngx_http_proxy_module 模块指令列表中,除 proxy_pass 指令以外,其余指令使用的指令域范围都是 http、server 或 location;
- 缓冲区的大小默认为操作系统中单个内存页的大小,在 CentOS 下可通过如下命令查询:
getconf PAGE_SIZE
-
- proxy_next_upstream 指令值中,当 non_idempotent 参数启用时,请求方法 POST、LOCK、PATCH 在出现错误时,也可以向下一个服务器重复提交。
2.正向代理
正向代理是客户端设置代理地址后,通过将代理服务器的 IP 作为源 IP 访问互联网应用服务的代理方式。通过对正向代理访问设置,可以实现限制客户端的访问行为、下载速度、访问记录统计、隐藏客户端信息等目的。实现原理如下图所示。
图:正向代理
1) HTTP 的正向代理
Nginx 的 proxy 模块可以实现基础的 HTTP 代理功能。配置样例如下:
map $host $deny { hostnames; default 0; www.google.com 1; # 禁止访问www.google.com } server { listen 8080; resolver 114.114.114.114; resolver_timeout 30s; access_log logs/proxy_access.log; # 记录访问日志 location / { if ( $deny ) { return 403; # 被禁止访问的网址返回403错误 } proxy_limit_rate 102400; # 限制客户端的下载速率是100KB/s proxy_buffering on ; # 启用代理缓冲 proxy_buffers 8 8k; # 代理缓冲区大小为64KB proxy_buffer_size 8k; # 响应数据第一部分的缓冲区大小为8KB proxy_busy_buffers_size 16k; # 向客户端发送响应的缓冲区大小16KB proxy_temp_file_write_size 16k; # 一次写入临时文件的数据大小为16KB # 设置所有代理客户端的agent proxy_set_header User-Agent "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14" ; proxy_set_header Host $http_host; proxy_connect_timeout 70s; # 代理连接超时时间 proxy_http_version 1.1; # 代理协议为http/1.1 proxy_pass $scheme://$http_host$request_uri; # 代理到远端服务器 } }
2) HTTPS 的正向代理
Nginx 默认不支持 HTTP 的 CONNECT 方法,所以无法实现 HTTPS 的正向代理的功能,若要实现 Nginx 的 HTTPS 的正向代理功能,需要添加一个第三方模块 ngx_http_proxy_connect_module,实现 HTTPS 的正向代理支持。对于该模块,官网提示可支持到 Nginx 1.15.8 版本,但实测 Nginx 的 1.17.0 版本也可以编译通过。模块配置指令如下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
proxy_connect | -- | -- | 启用 HTTP 的 CONNECT 方法支持 |
proxy_connect_allow | all 或端口或端口范围 | 443 563 | 设置允许 CONNECT 方法的访问端口 |
proxy_connect_timeout | time | -- | 设置与被代理服务器建立连接的超时时间 |
proxy_connect_read_timeout | time | 60s | 在连续两个从被代理服务器接收数据的操作之间的间隔时间超过设置的时间时,将关闭连接 |
proxy_connect_send_timeout | time | 60s | 在连续两个发送到被代理服务器的操作之间的间隔时间超过设置的时间时,将关闭连接 |
proxy_connect_address | address 或 off | none | 设置代理服务器的 IP 地址,指令值可以是变量。指令值 off 等于 none |
proxy_connect_bind | address[tran-sparent] 或 off | none |
设置从指定的本地 IP 地址及端口号与被代理服务器建立连接,指令值不能是变量。transparent 参数启用时, 将会允许以非 Nginx 的客户端 IP 为源 IP 访问被代理服务器。指令值 off 等于 none |
proxy_connect 模块指令使用的指令域范围为 server。模块编译如下:
yum -y install patch git clone https://github.com/chobits/ngx_http_proxy_connect_module.git cd nginx patch -p1 < ../ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_101504.patch ./configure --add-module=../ngx_http_proxy_connect_module
配置样例如下:
server { listen 8080; resolver 114.114.114.114; resolver_timeout 30s; access_log logs/proxy_access.log # 记录访问日志 proxy_connect; # 启用HTTP的CONNECT方法支持 proxy_connect_allow all; # 允许所有端口 proxy_connect_connect_timeout 60s; # 与互联网网站建立连接的超时时间 location / { proxy_buffering on ; # 启用代理缓冲 proxy_buffers 8 8k; # 代理缓冲区的大小为64KB proxy_buffer_size 8k; # 响应数据第一部分的缓冲区的大小为8KB proxy_busy_buffers_size 16k; # 向客户端发送响应的缓冲区的大小16KB proxy_limit_rate 102400; # 限制客户端的下载速率是100KB/s proxy_temp_file_write_size 16k; # 一次写入临时文件的数据大小为16KB # 设置所有代理客户端的agent proxy_set_header User-Agent “Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14” ; proxy_set_header Host $host; proxy_connect_timeout 70s; # 代理连接 proxy_http_version 1.1; # 代理协议为http/1.1 proxy_pass $scheme://$http_host$request_uri;# 代理到远端服务器 } } ## 本地测试 curl -x 127.0.0.1:8080 https://www.baidu.com
各浏览器可以通过代理功能配置使用 Nginx 代理服务器访问互联网服务器。
3.HTTP 的反向代理
反向代理是用户客户端访问代理服务器后,被反向代理服务器软件按照一定的规则从一个或多个被代理服务器中获取响应资源并返回给客户端的代理模式,客户端只知道代理服务器的 IP,并不知道后端服务器的 IP,原因是代理服务器隐藏了被代理服务器的信息。
因为编写 Nginx 的反向代理配置时,被代理服务器通常会被编写在 upstream 指令域中,所以被代理服务器也被称为上游服务器。实现原理如下图所示。
图:反向代理
为方便反向代理的配置,此处把通用的代理配置写在 proxy.conf 文件中。在使用时,通过主配置文件 nginx.conf 用 include 指令引入。文件 proxy.conf 的内容如下:
cat >proxy.conf<<EOF proxy_buffering on; # 启用响应数据缓冲区 proxy_buffers 8 8k; # 设置每个HTTP请求读取上游服务器响应数据缓冲区的大小为64KB proxy_buffer_size 8k; # 设置每个HTTP请求读取响应数据第一部分缓冲区的大小为8KB proxy_busy_buffers_size 16k; # 接收上游服务器返回响应数据时,同时用于向客户端发送响应的缓 # 冲区的大小为16KB proxy_limit_rate 0; # 不限制每个HTTP请求每秒读取上游服务器响应数据的流量 proxy_request_buffering on; # 启用客户端HTTP请求读取缓冲区功能 proxy_http_version 1.1; # 使用HTTP 1.1版本协议与上游服务器建立通信 proxy_connect_timeout 5s; # 设置与上游服务器建立连接的超时时间为5s proxy_intercept_errors on; # 拦截上游服务器中响应码大于300的响应处理 proxy_read_timeout 60s; # 从上游服务器获取响应数据的间隔超时时间为60s 60sproxy_send_timeout 60s; # 向上游服务器发送请求的间隔超时时间为60s # 设置发送给上游服务器的头属性字段Host为客户端请求头头字段Host的值 proxy_set_header Host $host:$server_port; # 设置发送给上游服务器的头属性字段Referer为客户端请求头头字段的值Host proxy_set_header Referer $http_referer; # 设置发送给上游服务器的头属性字段Cookie为客户端请求头头字段的值Host proxy_set_header Cookie $http_cookie; # 设置发送给上游服务器的头属性字段X-Real-IP为客户端的IP proxy_set_header X-Real-IP $remote_addr; # 设置发送给上游服务器的头属性字段X-Forwarded-For为客户端请求头的X-Forwarded-For的 # 值,如果没有该字段,则等于$remote_addr proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 设置发送给上游服务器的头属性字段X-Forwarded-Proto为请求协议的值 proxy_set_header X-Forwarded-Proto $scheme; EOF
在 nginx.conf 的 http 指令域中引入该文件,配置样例如下:
http { ... include proxy.conf include conf.d/*.conf }
Nginx 的指令支持在指令域中对上级指令域指令的继承和修改,若对 proxy.conf 有特殊配置需求的,可在对应的 server 指令域中添加同名指令。
反向代理的配置样例如下:
server { listen 8088; access_log logs/proxy.access.log main; tcp_nodelay off; # 因启用缓冲区功能,所以关闭立刻发送功能 location ~ ^/ { proxy_force_ranges on; # 强制启用字节范围请求支持 proxy_pass http://192.168.2.145:8082; break; } }
4.HTTPS 的反向代理
HTTPS 通过加密通道保护客户端与服务端之间的数据传输,已成为当前网站部署的必选配置。在部署有 Nginx 代理集群的 HTTPS 站点,通常会把 SSL 证书部署在 Nginx 的服务器上,然后把请求代理到后端的上游服务器。这种部署方式由 Nginx 服务器负责 SSL 请求的运算,相对减轻了后端上游服务器的 CPU 运算量,这种方式也被称为 SSL 终止(SSL Termination)。
因 Nginx 启用了对 TSL SNI(Server Name Identification)技术的支持,所以在同一服务器上可以安装多个绑定不同域名的 SSL 证书,使其可以在 Nginx 服务器上统一部署,同时也极大地方便了证书的管理和维护。
由 Nginx 服务器实现 SSL 终止的 HTTPS 的反向代理的常见方式有两种,一种是由 Nginx 通过 HTTP 方式与被代理服务器建立连接;另一种是由 Nginx 通过 HTTPS 方式与被代理服务器建立连接。由 Nginx 通过 HTTP 方式与被代理服务器建立连接的部署方式为客户端 → Nginx 服务器(HTTPS)→ 上游服务器(HTTP),配置样例如下:
server { listen 443 ssl; server_name www.nginxbar.org; charset utf-8; access_log logs/sslproxy.access.log main; tcp_nodelay off; # 因启用缓冲区功能,所以关闭立刻发送功能 ssl_certificate ssl/www_nginxbar_org.pem; # 网站证书文件 ssl_certificate_key ssl/www_nginxbar_org.key; # 网站证书密钥文件 ssl_session_cache shared:SSL:10m; # 会话缓存的存储大小为10MB ssl_session_timeout 10m; # 会话缓存的超时时间为10分钟 ssl_session_tickets on; # 设置会话凭证为会话缓存机制 ssl_session_ticket_key ssl/session_ticket.key; # 设置会话凭证密钥文件 location ~ ^/ { proxy_pass http://192.168.2.145:8082; break; } }
按照上面的配置,Nginx 服务器与后端的上游服务器之间仍然采用的是 HTTP 透明传输,虽然可以与上游服务器部署在同一内网,但数据传输仍是不安全的。为了提高传输安全性,建议在上游服务器也开启 HTTPS 协议,实现全链路的安全数据传输。由 Nginx 通过 HTTPS 方式与被代理服务器建立连接的配置样例场景如下。
在配置样例的场景中有两个 HTTPS 节点,为方便举例说明配置指令的功能及配置指令中所用的 SSL 证书的区别,共设计了 3 个 SSL 证书并通过自签证书的方式进行签发,部署方式如下图所示。
图:HTTPS代理
www.nginxbar.org (http://www.nginxbar.org) 证书为对外网站的域名证书,用于给用户提供身份验证。
backend.nginxbar.org (htp://backend.nginxbar.org) 证书为被代理服务器的域名证书,用于给 Nginx 服务器提供身份验证。
proxy.nginxbar.com (http://proxy.nginxbar.com) 证书为 Nginx 服务器的域名证书,用于给被代理服务器提供身份验证。
自签证书命令如下:
# 生成自建根域nginxbar.org证书 openssl req -new -x509 -out /etc/nginx/conf/ssl/root.pem -keyout /etc/nginx/conf/ssl/root.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.org/emailAddress= admin@nginxbar.org" # 域名www.nginxbar.org生成请求文件,面向用户端的域名请求文件 openssl req -out /etc/nginx/conf/ssl/www_nginxbar_org.csr -new -sha256 -newkey rsa:2048 -nodes -keyout /etc/nginx/conf/ssl/www_nginxbar_org.key -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=www/CN=www.nginxbar.org/emailAddress= www@nginxbar.org" # 颁发自签域名www.nginxbar.org证书,面向用户端的域名证书 openssl x509 -req -in /etc/nginx/conf/ssl/www_nginxbar_org.csr -out /etc/nginx/conf/ssl/www_nginxbar_org.pem -CA /etc/nginx/conf/ssl/root.pem -CAkey /etc/nginx/conf/ssl/root.key -CAcreateserial -days 3650 # 域名backend.nginxbar.org生成请求文件,后端上游服务器的SSL请求文件 openssl req -out /etc/nginx/conf/ssl/backend_nginxbar_org.csr -new -sha256 -newkey rsa:2048 -nodes -keyout /etc/nginx/conf/ssl/backend_nginxbar_org.key -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=backend/CN=backend.nginxbar.org/emailAddress=backend@nginxbar.org" # 颁发自签域名backend.nginxbar.org证书,后端上游服务器的SSL证书 openssl x509 -req -in /etc/nginx/conf/ssl/backend_nginxbar_org.csr -out /etc/nginx/conf/ssl/backend_nginxbar_org.pem -CA /etc/nginx/conf/ssl/root.pem -CAkey /etc/nginx/conf/ssl/root.key -CAcreateserial -days 3650 # 生成自建根域nginxbar.com证书,该域名仅为方便区分代理端和后端证书使用,实际使用时可以使用一个根证书 openssl req -new -x509 -out /etc/nginx/conf/ssl/proxy_root.pem -keyout /etc/nginx/conf/ssl/proxy_root.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress= admin@nginxbar.com" # 域名proxy.nginxbar.com生成请求文件,Nginx服务器的SSL代理请求文件 openssl req -out /etc/nginx/conf/ssl/proxy_nginxbar_com.csr -new -sha256 -newkey rsa:2048 -nodes -keyout /etc/nginx/conf/ssl/proxy_nginxbar_com.key -subj “/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=proxy/CN=proxy.nginxbar.com /emailAddress=proxy@nginxbar.com” # 颁发自签域名proxy.nginxbar.com证书,Nginx服务器的SSL代理证书 openssl x509 -req -in /etc/nginx/conf/ssl/proxy_nginxbar_com.csr -out /etc/nginx/conf/ssl/proxy_nginxbar_com.pem -CA /etc/nginx/conf/ssl/proxy_root.pem -CAkey /etc/nginx/conf/ssl/proxy_root.key -CAcreateserial -days 3650
Nginx 代理服务器的配置如下:
resolver 114.114.114.114 valid=300s; # DNS服务器地址 resolver_timeout 5s; # DNS解析的超时时间为5s server { listen 443 ssl; server_name www.nginxbar.org; access_log logs/sslproxy2_access.log main; ssl_certificate ssl/www_nginxbar_org.pem; # 网站www.nginxbar.org证书文件 ssl_certificate_key ssl/www_nginxbar_org.key; # 网站www.nginxbar.org证书密钥文件 ssl_session_cache shared:SSL:10m; # 会话缓存的存储大小为10MB ssl_session_timeout 10m; # 会话缓存的超时时间为10分钟 ssl_session_tickets on; # 设置会话凭证为会话缓存机制 ssl_session_ticket_key ssl/session_ticket.key; # 设置会话凭证密钥文件 location / { proxy_pass https://backend.nginxbar.org; # 被代理服务器的地址 proxy_ssl_certificate ssl/proxy_nginxbar_com.pem; # 代理服务器的客户端证书 # 文件 proxy_ssl_certificate_key ssl/proxy_nginxbar_com.key; # 代理服务器的客户端证书 # 密钥文件 proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2; proxy_ssl_ciphers HIGH:!aNULL:!MD5; proxy_ssl_verify on; # 启用验证被代理服务器的证书 proxy_ssl_trusted_certificate ssl/root.pem; # 用于验证被代理服务器的主机名backend. # nginxbar.org的根证书 proxy_ssl_verify_depth 2; # 证书验证深度为2 proxy_ssl_session_reuse on; # SSL连接启用会话重用 } }
Nginx Web 服务器配置如下:
server { listen 443 ssl; server_name backend.nginxbar.org; access_log logs/sslbackend_access.log main; ssl_certificate ssl/backend_nginxbar_org.pem;# 网站backend.nginxbar.org证书文件 ssl_certificate_key ssl/backend_nginxbar_org.key;# 网站backend.nginxbar.org证书密钥 # 文件 ssl_verify_client on; # 启用对Nginx服务的证书验证 ssl_client_certificate ssl/proxy_root.pem; # 用以验证Nginx服务器主机名 # proxy.nginxbar.com的根证书 ssl_verify_depth 2; # 证书验证深度为2 ssl_session_cache shared:SSL:10m; # HTTPS会话缓存的存储大小为10MB ssl_session_tickets off; # 以会话编号机制实现会话缓存 ssl_session_timeout 10m; # 会话缓存的超时时间为10分钟 charset utf-8; root /opt/nginx-web; index index.html index.htm; }
5.反向代理的真实客户端 IP
客户端在访问互联网应用服务器时,与真实的应用服务器之间会因为有多层反向代理,而导致真实应用服务器获取的仅是最近一层的反向代理服务器 IP。为使 Nginx 后端的上游服务器可以获得真实客户端 IP,Nginx 提供了 ngx_http_realip_module 模块用以实现真实客户端 IP 的获取及传递的功能。
通过该模块提供的配置指令,用户可以手动设置上层反向代理服务器的 IP 作为授信 IP,Nginx 服务器根据配置指令的配置排除授信 IP,而甄别出真实的客户端 IP 进行日志记录,并传递给上游服务器。模块配置指令如下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
set_real_ip_from | address 或 CIDR 或 unix | -- | 设置授信 IP,IP 网段或 UNIX 套接字 |
real_ip_header | field 或 X-Real-IP 或 X-For-warded-For 或 proxy_protocol | X-Real-IP | 通过指定的 HTTP 头字段获取真实客户端 IP |
real_ip_recursive | on 或 off | off |
当客户端经多层反向代理到达当前服务器时,指定的 HTTP 头字段中会有多个 IP 地址。 默认会以最后一个 IP 为真实客户端 IP,当指令值为 on 时,会以最后一个非信 IP 为真实客户端 IP |
该模块指令使用的指令域范围为http、server、location。配置样例如下:
server { listen 8088; access_log logs/proxy.access.log main; set_real_ip_from 192.168.2.159; # 设置192.168.2.159为授信IP real_ip_header X-Forwarded-For; # 通过HTTP头字段X-Forwarded-For获取真实客户端IP real_ip_recursive on; # 以最后一个非授信IP为真实客户端IP tcp_nodelay off; # 因启用缓冲区功能,所以关闭立刻发送功能 location ~ ^/ { proxy_force_ranges on; # 强制启用字节范围请求支持 proxy_pass http://192.168.2.145:8082; break; } }
2.Nginx stream模块简述
Nginx 的 TCP/UDP 代理功能的模块分为核心模块和辅助模块、核心模块 stream 需要在编译配置时增加“--with-stream”参数进行编译。核心模块的全局配置指令如下表所示。
参数名称 | 指令值格式 | 默认值 | 参数说明 |
listen | address:port[ssl][udp][proxy protocol] [backlog=number][rcvbuf=size] |
-- | stream 监听协议及端口 |
listen | [sndbuf=size][bind][ipv6only=on 或 off] [reuseport][so_keepalive=on 或 off 或 [keepidle]:[keepintvl]:[keepent]] |
-- | stream 监听协议及端口 |
preread_buffer_size | size | 16k | 设置每个会话数据预读缓冲区的大小 |
preread_timeout | timeout | 30s | 设置每个会话数据预读取的超时时间 |
proxy_protocol_timeout | timeout | 30s | 读取代理协议头的超时时间 |
resolver | address... [valid=time][ipv6=on 或 off] | -- | 域名解析服务器地址 |
resolver_timeout | time | 30s | 域名解析超时时间 |
tcp_nodelay | on 或 off | on | 启用或关闭立即发送数据(tcp_nodelay)选项 |
variables_hash_bucket_size | size | 64 | 设置变量哈希表中桶的大小 |
variables_hash_max_size | size | 1024 | 设置变量哈希表的最大值 |
关于上表有以下几点需要说明。
- 指令 listen 使用的指令域范围为 server;
- 指令 variables_hash_bucket_size 和 variables_hash_max_size 使用的指令域范围为 stream;
- stream 核心模块其余指令使用的指令域范围为 stream、server;
- resolver 指令值可填写多个域名解析服务器地址,各个地址用空格分隔;
- listen 指令值参数如下表所示。
参数名称 | 默认 | 参数说明 |
ssl | -- | 在指定监听端口上启用 SSL 协议支持 |
udp | -- | 在指定监听端口上启用 UDP 协议支持 |
proxy_protocol | -- | 在指定监听端口上启用 proxy_protocol 协议支持 |
backlog | -1/511 | 设置挂起连接队列的最大长度,在 FreeBSD、DragonFly BSD 和 macOS 操作系统上,设置默认值为 -1,其他平台为 511 |
rcvbuf | -- | 设置套接字(socket)接收缓冲区(SO_RCVBUF 选项)的大小,Linux 操作系统下默认值为内核参数 net.core.rmem_default 的值 |
sndbuf | -- | 设置套接字(socket)发送缓冲区(SO_SNDBUF 选项)的大小,Linux 操作系统下默认值为内核参数 net.core.wmem_default 的值 |
bind | -- | address:port 指定 IP 及端口 |
ipv6only | on | 只接收 IPv6 连接,或接收 IPv6 和 IPv4 连接 |
reuseport | -- |
在默认情况下,所有的工作进程都会共享一个 socket 去监听同一 IP 和端口的组合。该参数启用后,允许每个工作进程由独立的 socket 去监听同一 IP 和端口的组合,内核会对传入的连接进行负载均衡。目前,它只适用于 Linux 3.9+、DragonFly BSD 和 FreeBSD 12+ |
so_keepalive | off |
配置监听的端口启用 TCP keepalive 机制时的心跳检测参数。当指令值为 on 时,默认等同于 so_keepalive=30m::10,表示 30 分钟 无数据传输时发送探测包,总共发送 10 次,发送时间间隔为系统内核参数 tcp_keepalive_intvl 的设定值 |
配置样例如下:
stream { resolver 114.114.114.114 valid=300s; resolver_timeout 2s; upstream backend { server 192.168.0.1:333; server www.example.com:333; } server { listen 127.0.0.1:333 udp reuseport; proxy_timeout 20s; proxy_pass backend; } server { listen [::1]:12345; proxy_pass unix:/tmp/stream.socket; }
}
Stream辅助模块
1.ngx_stream_map_module
该模块的功能是在客户端每次连接时,Nginx按照map指令域中源变量的当前值,把设定的对应值赋给新变量。该指令的语法格式如下:
map 源变量 新变量{}
这个指令使用的指令域只有 stream,指令值参数如下表所示。
参数名称 | 参数值 |
default | 为新变量指定一个默认值。若不指定这个参数,新变量默认值为空 |
hostnames | 当源变量为主机名时,允许使用主机名前缀或后缀对源变量值进行匹配 |
include | 引入一个外部文件作为 map 的指令域内容 |
volatile | map 默认创建的是可被缓存的变量,启用该参数后,创建的为不可被缓存的变量 |
map 指令域中,当源变量值存在相同匹配项时,匹配的顺序如下:
-
- 完全匹配的字符串;
- 有主机前缀的最长字符串;
- 有主机后缀的最长字符串;
- 在指令域中按自上而下的顺序最先匹配到的正则表达式;
- default 参数给定的默认值。
map 哈希表大小指令如下表所示。
名称 | map 哈希表大小指令 |
指令 | map_hash_max_size |
作用域 | stream |
默认值 | 2048 |
指令说明 | map 指令中,存储变量的哈希表的大小 |
map 哈希桶大小指令如下表所示。
名称 | map 哈希桶大小指令 |
指令 | map_hash_bucket_size |
作用域 | stream |
默认值 | 32、64 或 128 |
指令说明 | map 指令中,存储变量的哈希桶的大小 |
配置样例如下:
stream{ map $remote_addr $limit { 127.0.0.1 “”; default $binary_remote_addr; } limit_conn_zone $limit zone=addr:10m; limit_conn addr 1; server { listen 33060 reuseport; access_log logs/tcp.log tcp; proxy_timeout 20s; proxy_pass 127.0.0.1:3306; } }
2.ngx_stream_geo_module
该模块的功能是从源变量获取 IP 地址,并根据设定的 IP 与对应值的列表对新变量进行赋值。该模块只有一个 geo 指令,指令格式如下:
geo [源变量]新变量{}
geo 指令的默认源变量是 $remote_addr,新变量默认值为空,这个指令使用的指令域只有 stream,指令值参数如下表所示
参数名 | 参数描述 |
delete | 删除配置中已经存在的相同 IP 地址的设定 |
default | 如果从源变量获取的IP无法匹配任意一个 IP 或 IP 范围时,使用这个参数的值作为新变量赋值 |
include | 引入一个包含 IP 与对应值的外部文件 |
ranges | 以地址段的形式定义 IP 地址,这个参数必须放在最上面 |
配置样例如下:
geo $country { ranges; default CN; 127.0.0.0-127.0.0.0 US; 10.1.0.0-10.1.255.255 RU; 192.168.1.0-192.168.1.255 UK; } geo $country { default ZZ; include conf/geo.conf; delete 127.0.0.0/16; 127.0.0.0/24 US; 10.1.0.0/16 RU; 192.168.1.0/24 UK; }
3.ngx_stream_geoip_module
该模块的功能首先是根据客户端的 IP 地址与 MaxMind 数据库中的城市地址信息做比对,然后再将对应的城市地址信息赋值给内置变量。
国家信息数据库指令如下表所示。
名称 | 国家信息数据库指令 |
指令 | geoip_country |
作用域 | stream |
默认值 | 1 |
指令说明 | 指定国家信息的 MaxMind 数据库文件路径 |
城市信息数据库指令如下表所示。
名称 | 城市信息数据库指令 |
指令 | geoip_city |
作用域 | stream |
默认值 | 1 |
指令说明 | 指定城市信息的 MaxMind 数据库文件路径 |
机构信息数据库指令如下表所示。
名称 | 机构信息数据库指令 |
指令 | geoip_org |
作用域 | stream |
默认值 | 1 |
指令说明 | 指定机构信息的 MaxMind 数据库文件路径 |
配置样例如下:
stream { geoip_country /usr/share/GeoIP/GeoIP.dat; geoip_city /usr/share/GeoIP/GeoLiteCity.dat; map $geoip_city_continent_code $nearest_server { default example.com; EU eu.example.com; NA na.example.com; AS as.example.com; } ... }
4.ngx_stream_split_clients_module
该模块会按照配置指令将一个 0~232 之间的数值根据设定的比例分割为多个数值范围,每个数值范围会被设定一个对应的给定值。用户每次请求时,指定的字符串会被计算出一个数值,该模块会将该数值所在范围对应的给定值赋值给配置中定义的变量。该功能常用来按照用户的来源IP进行访问流量分流。该指令的语法格式如下:
split_clients 字符串 新变量 {}
配置样例如下:
stream { split_clients "${remote_addr}AAA" $upstream { # ${remote_addr}AAA会被计算出一个数值 0.5% backend1; # 数值在0 ~ 21474835之间,$upstream被赋值backend1 80.0% backend2; # 数值在21474836 ~ 3435973836之间,$upstream被赋值backend2 * backend; # 数值在3435973837 ~ 4294967295,$upstream被赋值backend } server { listen 389; proxy_pass $upstream; } }
这个指令使用的指令域只有 stream;客户端每次请求时,指定字符串会被使用 MurmurHash2 算法计算出一个 0~232(0~4294967295)之间的数值,该模块会将该数值所在范围对应的给定值赋值给配置中定义的变量。
5.ngx_stream_ssl_preread_module
该模块可以在预读取阶段从 ClientHello 消息中提取信息,赋值给内置变量后供用户调用。
SSL 信息预读如下表所示。
名称 | SSL 信息预读 |
指令 | ssl_preread |
作用域 | stream、server |
可选项 | on 或 off |
默认值 | off |
指令说明 | 设置是否启用 SSL 信息预读功能 |
内置变量如下表所示
变量名 | 变量说明 |
$ssl_preread_protocol | 客户端支持的最高 SSL 协议版本 |
$ssl_preread_server_name | 通过 SNI 请求的服务器名称 |
$ssl_preread_alpn_protocols | 客户通过 ALPN 公布的协议列表 |
配置样例如下:
stream { map $ssl_preread_protocol $upstream { "" ssh.example.com:22; "TLSv1.2" new.example.com:443; default tls.example.com:443; } server { listen 192.168.0.1:443; proxy_pass $upstream; ssl_preread on; } }
6.ngx_stream_limit_conn_module
该模块对访问连接中含有指定变量且变量值相同的连接数进行计数,当计数值达到 limit_conn 指令设定的值时,Nginx 服务器将关闭此类连接。由于 Nginx 采用的是多进程的架构,因此该模块通过共享内存存储计数状态并实现了多个进程间的计数状态共享。
计数存储区指令如下表所示。
名称 | 计数存储区指令 |
指令 | limit_conn_zone |
作用域 | stream |
默认值 | -- |
指令说明 | 设定用以存储指定变量计数的共享内存区域 |
连接数设置指令如下表所示。
名称 | 连接数设置指令 |
指令 | limit_conn |
作用域 | stream、server |
默认值 | -- |
指令说明 | 设置指定变量并发连接的最大数 |
连接数日志级别指令如下表所示。
名称 | 连接数日志级别指令 |
指令 | limit_conn_log_level |
作用域 | stream、server |
默认值 | error |
可选项 | info、notice、warn、error |
指令说明 | 当指定变量的并发连接数达最大值时,输出日志的级别 |
配置样例如下:
stream { limit_conn_zone $binary_remote_addr zone=addr:10m; # 对客户端IP进行并发计数,计数内存区 # 命名为addr,计数内存区的大小为10MB server { limit_conn addr 1; # 限制客户端的并发连接数为1 ... } }
配置说明如下所示:
-
- limit_conn_zone 的格式如下:
limit_conn_zone key zone=name:size;
-
- limit_conn_zone 的 key 可以是文本、变量或文本与变量的组合;
- $binary_remote_addr 为 IPv4 时,占用 4B;为 IPv6 时,占用 16B;
- limit_conn_zone 中,1MB 的内存空间可以存储 32000 个 32B 或 16000 个 64B 的变量计数状态;
- 变量计数状态在 32 位系统平台占用 32B 或 64B,在 64 位系统平台占用 64B。
7.ngx_stream_access_module
这个模块可以允许或拒绝客户端的源 IP 地址进行连接。
允许连接指令如下表所示。
名称 | 允许连接指令 |
指令 | allow |
作用域 | stream、server |
可选项 | address 或 CIDR 或 unix: 或 all |
默认值 | -- |
指令说明 | 允许指定源 IP 的客户端连接 |
拒绝连续指令如下表所示。
名称 | 拒绝连接指令 |
指令 | deny |
作用域 | stream、server |
可选项 | address 或 CIDR 或 unix: 或 all |
默认值 | -- |
指令说明 | 拒绝指定源 IP 的客户端连接 |
配置样例如下:
stream { server { deny 192.168.1.1; # 禁止192.168.1.1 allow 192.168.0.0/24; # 允许192.168.0.0/24的IP访问 allow 10.1.1.0/16; # 允许10.1.1.0/16的IP访问 allow 2001:0db8::/32; deny all; } }
Nginx 按照自上而下的顺序进行匹配。
8.ngx_stream_return_module
该模块向客户端返回指定值并关闭连接。
返回值指令如下表所示。
名称 | 返回值指令 |
指令 | return |
作用域 | server |
指令说明 | 向客户端返回指定值并关闭连接 |
配置样例如下:
stream { server { listen 12345; return $time_iso8601; # 返回当前连接的时间 } }
3.Nginx TCP/UDP代理简述
Nginx 并不直接提供 TCP/UDP 的应用响应,Nginx Stream 模块的核心功能是将客户端的 TCP/UDP 连接反向代理给后端的被代理服务器。
1.核心配置指令
TCP/UDP 代理功能的核心配置指令如下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
proxy_bind | address[transparent] 或 off | -- |
设置从指定的本地 IP 地址及端口与被代理服务器建立连接,指令值可以是变量。指令值参数为 transparent 时,允许将客户端的真实 IP 透传给被代理服务器, 并以客户端真实 IP 为访问被代理服务器的源 IP;指令值参数为 off 时,则取消上一层指令域同名指令的配置 |
proxy_buffer_size | size | 16k | 设置用于从被代理服务器读取数据的缓冲区的大小,也用于设置从客户端读取会话数据的缓冲区的大小 |
proxy_connect_timeout | time | 60s | 与被代理服务器建立连接的超时时间 |
proxy_timeout | time | 10m | Nginx 服务器与客户端或被代理服务器的两个连续成功的读或写操作的最大间隔时间,如果在间隔时间内没有数据传输,则关闭连接 |
proxy_download_rate | rate | 0 | 限制每个连接每秒从被代理服务器中读取数据的字节数,默认不限制 |
proxy_upload_rate | rate | 0 | 限制每个连接每秒发送到被代理服务器的数据的字节数,默认不限制 |
proxy_next_upstream | on 或 off | on | 当被代理的服务返回错误或超时时,将未返回响应的客户端连接请求传递给 upstream 中的下一个服务器 |
proxy_next_upstream_timeout | time | 0 | 设置将符合条件的客户端连接请求传递给 upstream 中下一个服务器的超时时间。“0”为不做超时限制,即直到遍历完所有上游服务器组中的服务器为止 |
proxy_next_upstream_tries | number | 0 |
设置将符合条件的客户端连接请求传递给 upstream 中下一个服务器的尝试次数,包括第一次的失败次数。“0”为不做尝试次数限制,即直到遍历完所有上游服务器 组中的服务器为止 |
proxy_pass | address | -- | 被代理服务器的地址,支持 IP 或域名加端口、UNIX 域套接字、upstream 名 |
proxy_protocol | on 或 off | off | 设置是否对被代理服务器的连接启用代理协议(proxy_protocol)支持 |
proxy_socket_keepalive | on 或 off | off | 设置 Nginx 与被代理服务器的 TCP keepalive 行为的心跳检测机制,默认使用操作系统的 socket 配置,若指令值为 on,则开启 SO_KEEPALIVE 选项进行心跳检测 |
proxy_ssl | on 或 off | off | 设置是否启用 SSL/TLS 协议与被代理服务器建立连接 |
proxy_ssl_protocols | [SSLv2][SSLv3] [TLSv1][TLSv1.1] [TLSv1.2][TLSv1.3] |
TLSv1 TLSv1.1 TLSv1.2 |
指定可用于 Nginx 与被代理服务器建立 SSL 连接的 SSL 协议版本 |
proxy_ssl_session_reuse | on 或 off | on | 是否启用与被代理服务器 SSL TCP 连接的 SSL 会话重用功能 |
proxy_ssl_ciphers | ciphers | DEFAULT | 设置与被代理服务器建立 SSL 连接时,用于协商使用的加密算法组合,也称为密码套件,指令值内容为 openssl 的密码套件名称,多个套件名称由“:”分隔 |
proxy_ssl_server_name | on 或 off | off | 在与被代理服务器建立 SSL 连接时,设置是否启用通过 SNI 或 RFC 6066 传递主机名 |
proxy_ssl_certificate | file | -- | 指定被代理服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书文件 |
proxy_ssl_certificate_key | file | -- | 指定被代理服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书私钥文件 |
proxy_ssl_password_file | file | -- | 存放被代理服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书私钥文件的密码文件,一个密码一行。有多个密码时,Nginx 会依次尝试 |
proxy_ssl_verify | on 或 off | off | 设置是否启用对被代理服务器的 SSL 证书的验证功能 |
proxy_ssl_name | name | proxy_pass 指令指定的主机名 |
指定对被代理服务器 SSL 证书验证的主机名 |
proxy_ssl_crl | file | -- | 证书品销列表文件,用于验证被代理服务器 SSL 证书有效性的 PEM 格式文件 |
proxy_ssl_trusted_certificate | file | -- | 指定一个 PEM 格式的 CA 证书(根或中间证书)文件,该证书用作被代理服务器的证书链验证 |
proxy_ssl_verify_depth | number | 1 | 设置被代理服务器的证书链的验证深度 |
proxy_requests | number | 0 |
UDP 代理时,设置同一客户端被 Nginx 在每次 UDP 会话中,转发给被代理服务器的数据报的数量。当达到这个数量时,将启用一个新的 UDP 会话继续转发。 可用于 Nginx 对 UDP 虚拟连接会话的控制 |
proxy_responses | number | -- | UDP 代理时,设置允许被代理服务器返回 UDP 数据报的数量,超过指令值时将中止会话。默认无限制,0 为不返回响应数据 |
该模块的指令使用的指令域范围为 stream、server。
2.TCP 反向代理配置样例
配置样例如下:
stream { server { listen 389 ; # 设置监听端口为389 proxy_pass 192.168.2.100:389; # 将连接代理到后端192.168.2.100:389 proxy_timeout 5s; # 与被代理服务器的连续通信间隔大于5s, # 则认为通信超时,将关闭连接 proxy_connect_timeout 5s; # 与被代理服务器建立连接的超时时间为5s access_log logs/ldap_access.log tcp; # 记录日志文件为logs/ldap_access.log, # 日志模板为tcp } }
3.代理 SSL TCP
代理模块 stream 可以实现基于 SSL/TLS 协议的被代理服务器的反向代理,部署方式为客户端 → Nginx 服务器(TCP)→ 被代理服务器(SSL TCP)。配置样例如下:
stream { server{ listen 636; # 设置监听端口为636 access_log logs/ldap_access.log tcp; proxy_pass 192.168.2.100:636; proxy_ssl on; # 启用SSL/TLS协议,与被代理服务器建立连接 proxy_ssl_session_reuse on; # 与被代理服务器SSL TCP连接的SSL会话重用功能 } }
4.UDP 反向代理配置
UDP 协议是一种无连接的协议,发送端与接收端传输数据之前不需要建立连接,发送端会尽最大努力把数据发送出去,不能保证安全地传输到接收端。由于传输数据不建立连接,也不需要维持复杂的链路关系(包括连接状态、收发状态等),因此发送端可同时向多个接收端传输相同的消息。
虽然 UDP 的数据传输是不可靠的,但如果有一个数据报丢失,另一个新的数据报会在几秒内替换它发送到接收端。UDP 协议通常被用在单向传输无须返回响应及信息分发的场景,如日志收集或在屏幕上的航班信息、股票行情等多媒体场景。
stream { server { listen 1514 udp; # 设置监听端口为1514并启用UDP协议 proxy_pass 192.168.2.123:1514; proxy_responses 0; # 会话接收数据报后无须等待返回响应,立即关闭会话 } }
4.Nginx基于SSL的TCP代理服务器
Nginx 可以通过代理模块实现上游服务器 SSL/TLS 协议的连接,同时 Nginx 还通过模块 ngx_stream_ssl_module 提供了基于 SSL/TLS 协议的 TCP 连接监听。Nginx 还可以把 SSL 证书部署在 Nginx 服务器上,这就减轻了后端上游服务器的 CPU 运算量并实现 SSL 证书的统一管理和维护。
ngx_stream_ssl_module 模块默认不会被构建,这就需要在编译的时候通过--with-stream_ssl_module
参数进行启用。相关配置指令如下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
ssl_protocols | [SSLv2][SSLv3] [TLSv1][TLSv1.1] [TLSv1.2][TLSv1.3] |
TLSv1 TLSv1.1 TLSv1.2 | 设置使用的 SSL 协议版本 |
ssl_certificate | file | -- | PEM 格式的 SSL 证书文件,可自建或由 CA 机构颁发 |
ssl_certificate_key | file | -- | PEM 格式的 SSL 证书私钥文件,可自建或由 CA 机构颁发 |
ssl_password_file | file | -- | 存放 SSL 证书私钥文件的密码文件,一个密码一行。有多个密码时,Nginx 会依次尝试 |
ssl_ciphers | ciphers | HIGH:!aNULL:!MD5 | 设置 SSL TCP 建立连接时用于协商使用的加密算法组合,也称为密码套件。指令值内容为 openssl 的密码套件名称,多个套件名称由“:”分隔 |
ssl_prefer_server_ciphers | on 或 off | off | 是否启用 SSLv3 和 TLSv1 协议在 SSL TCP 连接时优先使用服务端设置的密码套件 |
ssl_dhparam | file | -- | DH 密钥交换的 Diffie-Hellman 参数文件 |
ssl_ecdh_curve | curve | auto |
配置 SSL 加密时使用椭圆曲线 DH 密钥交换的曲线参数,多个参数使用“:”分隔。ecdh 是 Elliptic-Curve 和 Diffie-Hellman 的缩写,指令值 为 auto 时,配置的曲线参数是 prime256v1 |
ssl_session_cache | off 或 none 或 [builtin[:size]] [shared:name:size] |
none | SSL TCP 会话缓存设置 |
ssl_session_tickets | on 或 off | on | 是否启用 SSL TCP 会话缓存 session ticket 机制,指令值为 off 时,使用 session ID 会话缓存机制 |
ssl_session_ticket_key | file | -- | 指定会话凭证密钥文件,用以多台 Nginx 间实现 session ticket 共享,否则 Nginx 会随机生成一个会话凭证密钥 |
ssl_session_timeout | time | 5m | 设置客户端可用会话缓存的超时时间 |
ssl_verify_client | on 或 off 或 optional 或 optional_no_ca |
off |
设置是否启用对客户端证书验证功能,指令值为 on 时,启用验证;指令值为 optional 时,如果接收到客户端证书则启用验证;指令值为 optional_no_ca 时, 若接收到客户端证书,则启用客户端证书验证,但不进行证书链校验。验证结果将存储在 $ssl_client_verity 变量中 |
ssl_crl | file | -- | 证书吊销列表文件,用以验证客户端 SSL 证书有效性的 PEM 格式文件 |
ssl_client_certificate | file | -- | 指定一个 PEM 格式的 CA 证书(根或中间证书)文件,该证书用作客户端的证书验证。该证书列表会被发送给客户端 |
ssl_trusted_certificate | file | -- | 指定一个 PEM 格式的 CA 证书(根或中间证书)文件,该证书用作客户端的证书验证。该证书列表不会被发送给客户端 |
ssl_verify _depth | number | 1 | 设置客户端证书链验证深度 |
关于上表有以下几点需要说明。
-
- 该模块指令值使用的指令域范围为 stream、server。
- Nginx 建立 SSL TCP 监听,用户发送 SSL TCP 连接时,由 Nginx 实现 SSL 终止并把 TCP 会话代理到上游服务器,部署方式为客户端 → Nginx 服务器(SSL TCP)→ 上游服务器(TCP)。配置样例如下:
stream { server { listen 636 ssl; # 设置监听端口为636 access_log logs/ldap_access.log tcp; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 设置使用的SSL协议版本 ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5; # 设置服务端使用的密码套件 ssl_certificate ssl/www_nginxbar_org.pem; # 主机名www.nginxbar.org证书文件 ssl_certificate_key ssl/www_nginxbar_org.key; # 主机名www.nginxbar.org证书密钥文件 ssl_session_cache shared:SSL:10m; # SSL TCP会话缓存设置共享内存区域名为 # SSL,区域大小为10MB ssl_session_timeout 10m; # SSL TCP会话缓存超时时间为10分钟 proxy_pass 192.168.2.100:389; } }
-
- 也可以通过代理模块的 proxy_ssl 指令配置与上游服务器实现全链路的安全数据通信。部署方式为客户端 → Nginx 服务器(SSL TCP)→ 被代理服务器(SSL TCP)。配置样例如下:
stream { server { listen 636 ssl; # 设置监听端口为636 access_log logs/ldap_access.log tcp; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 设置使用的SSL协议版本 ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5; # 设置服务端使用的密码套件 ssl_certificate ssl/www_nginxbar_org.pem; # 主机名www.nginxbar.org证书文件 ssl_certificate_key ssl/www_nginxbar_org.key; # 主机名www.nginxbar.org证书密钥文件 ssl_session_cache shared:SSL:10m; # SSL TCP会话缓存设置共享内存区域名为SSL,区域大小为10MB ssl_session_timeout 10m; # SSL TCP会话缓存超时时间为10分钟 proxy_ssl on; # 启用SSL/TLS协议,与被代理服务器建立连接 proxy_ssl_session_reuse on; # 与被代理服务器SSL TCP连接的SSL会话重用功能 } }
5.Nginx gRPC代理服务器
Nginx 从 1.13.10 版本开始就提供了对 gRPC 代理的支持,其可以通过 gRPC 模块的反向代理功能对外发布包括基于 SSL 的 gRPC 服务,且其应用 Nginx 提供的 HTTPv2 模块可实现速率限定、基于 IP 的访问控制以及日志等功能。
通过 Nginx 的 location 指令可检查方法调用,可将不同的调用方法路由到后端的多个不同 gRPC 服务器,以实现单点部署多个 gRPC 服务器的应用场景。并且通过 Nginx 实现 gRPC 服务器负载均衡,还可以使用轮询、最少连接数等算法实现流量分发。
1.gRPC 介绍
gRPC 是一个开源的基于 HTTP/2 协议的高性能、跨语言的远程过程调用(RPC)框架。它提供了双向流、流控、头部压缩、单 TCP 连接上的多复用请求等功能,这些功能使其在移动设备上可更节省空间和降低电量消耗。而且 gRPC 相对于 REST 的数据调用方式,提供了一个更加适合服务间调用数据的通信方案。
基于 gRPC 的客户端应用可以像调用本地对象方法一样直接调用 gRPC 服务端提供的方法,使其更适合分布式应用和服务场景。
2.gRPC 模块指令
Nginx 默认会构建 gRPC 代理的支持,但 gRPC 是基于 HTTP/2 协议的,而 ngx_http_v2_module 模块默认不会被构建,这就需要在编译时通过–with-http_v2_module参数来启用对 HTTP/2 协议的支持。
gRPC 代理模块配置指令下表所示。
指令名称 | 指令值格式 | 默认值 | 指令说明 |
grpc_bind | address[transparent]或 off | -- |
设置从指定的本地 IP 地址及端口与被代理服务器建立连接,指令值可以是变量。指令值参数为 transparent 时, 允许将客户端的真实 IP 透传给被代理服务器,并以客户端真实 IP 为访问被代理服务器的源 IP |
grpc_buffer_size | size | 4k 或 8k | 设置用于从 gRPC 服务器读取响应数据缓冲区的大小,当 Nginx 收到响应数据后将同步传递给客户端 |
grpc_pass | address | -- | 设置 gRPC 服务器的地址及端口,地址可以是 IP、域名或 UNIX 套接字 |
grpc_hide_header | field | -- | 指定 gRPC 服务器响应数据中,不向客户端传递的 HTTP 头字段名称 |
grpc_pass_header | field | -- | 默认配置下 Nginx 不会将头字段属性 Status 和 X-Accel-... 传递给客户端,可通过该指令开放传递 |
grpc_ignore_headers | field... | -- | 设置禁止 Nginx 处理从 gRPC 服务器获取响应的头字段 |
grpc_set_header | field value | Content-Length $content_length |
在转发给 gRPC 服务器前,修改或添加客户端的请求头属性字段 |
grpc_connect_timeout | time | 60s | Nginx 与 gRPC 服务器建立连接的超时时间,通常不应该超过 75s |
grpc_read_timeout | time | 60s | 在连续两个从 gRPC 服务器接收数据的“读”操作之间的间隔时间超过设置的时间时,将关闭连接 |
grpc_send_timeout | time | 60s | 在连续两个发送到 gRPC 服务器的“写”操作之间的间隔时间超过设置的时间时,将关闭连接 |
grpc_socket_keepalive | on 或 off | off |
设置 Nginx 与被代理服务器的 TCP keepalive 行为的心跳检测机制,默认使用操作系统的 socket 配置,若指令值为 on 时, 则开启 SO_KEEPALIVE 选项进行心跳检测 |
grpc_intercept_errors | on 或 off | off |
指令值为 on 时,将拦截 gRPC 服务器啊应码大于或等于 300 的结果,error page 指令可对该结果做后续处理;指令值为 off 时, 则直接返回给客户端 |
grpc_next_upstream | error、timeout、 invalid_header、 http_500、http_503、 http_403、http_404、 http_429、 non_idempotent、 off... |
error timeout | 当出现指令值中指定的条件时,将未返回响应的客户请求传递给 upstream 中的下一个服务器 |
grpc_next_upstream_timeout | time | 0 |
设置将符合条件的客户端请求传递给 upstream 的过程中,下一个服务器的超时时间。指令值为 0 不做超时限制, 直到遍历完所有上游服务器组中的服务器为止 |
grpc_next_upstream_tries | number | 0 |
设置符合条件的客户端请求传递给 upstream 的过程中,下一个服务器的尝试次数,包括第一次的失败次数。指令值为 0 不做尝试次数限制, 直到遍历完所有上游服务器组中的服务器为止 |
grpe_ssl_protocols | [SSLv2][SSLv3] [TLSv1][TLSv1.1] [TLSv1.2][TLSv1.3] |
TLSv1 TLSv1.1 TLSv1.2 |
指定可用于 Nginx 与 gRPC 服务器建立 SSL 连接的 SSL 协议的版本 |
grpe_ssl_session_reuse | on 或 off | on | 是否启用与 gRPC 服务器 HTTPS 连接的 SSL 会话重用功能 |
grpc_ssl_ciphers | ciphers | DEFAULT | 设置 HTTPS 建立连接时用于协商使用的加密算法组合,也称为密码套件,指令值内容为 openssl 的密码套件名称,多个套件名称由“:”分隔 |
grpc_ssl_server_name | on 或 off | off | 在与 gRPC 服务器建立 SSL 连接时,设置是否启用通过 SNI 或 RFC 6066 传递主机名 |
grpc_ssl_certificate | file | -- | 指定 gRPC 服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书文件 |
grpc_ssl_certificate_key | file | -- | 指定 gRPC 服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书私钥文件 |
grpc_ssl_password_file | file | -- | 存放 gRPC 服务器对 Nginx 服务器身份验证的 PEM 格式 SSL 证书私钥文件的密码文件,一个密码一行。有多个密码时,Nginx 会依次尝试 |
grpe_ssl_verify | on 或 off | off | 设置是否启用对 gRPC 服务器的 SSL 证书验证机制 |
grpc_ssl_name | name | proxy_pass 指令指定的主机名 |
指定对 gRPC 服务器 SSL 证书验证的主机名 |
grpc_ssl_crl | file | -- | 证书吊销列表文件,用以验证被代理服务器 SSL 证书有效性的 PEM 格式文件 |
grpc_ssl_trusted_certificate | file | -- | 指定一个 PEM 格式的 CA 证书(根或中间证书)文件,该证书用作 gRPC 服务器的证书链验证 |
grpc_ssl_verify_depth | number | 1 | 设置 gRPC 服务器的证书链的验证深度 |
3.gRPC反向代理
gRPC 是基于 HTTP/2 协议的,所以 Nginx 的 gRPC 代理需要启用 HTTP/2,然后 gRPC 客户端将请求发送到 Nginx。Nginx 为 gRPC 服务提供了一个稳定的网关。其部署方式如下图所示。
图:gRPC 代理
配置样例如下:
server { listen 8080 http2; # 设置监听端口为8080并启用http/2协议支持 access_log /var/log/nginx/grpc_access.log main; location / { grpc_pass grpc://192.168.2.145:50051; # 设置gRPC服务器 } }
gRPC 模块同样提供对后端 SSL gRPC 服务器的反向代理,配置样例如下:
server { listen 80 http2; # 设置监听端口为80并启用http/2协议支持 access_log /var/log/nginx/grpcs_access.log main; grpc_ssl_verify off; # 关闭对gRPC服务器的SSL证书验证 grpc_ssl_session_reuse on; # 设置gRPC服务器 location / { grpc_pass grpcs://192.168.2.145:50051; # 设置SSL gRPC服务器 } }
Nginx 可以通过 HTTP 协议的 SSL 证书,对外提供安全的 gRPC 代理转发,部署方式为客户端 → Nginx 服务器(HTTPS)→ 被代理服务器(SSL gRPC)。配置样例如下:
server { listen 443 ssl http2 default_server; # 设置监听端口为443并启用SSL及HTTP/2协议支持 access_log /var/log/nginx/grpcs_access.log main; ssl_certificate ssl/www_nginxbar_org.pem; # 网站证书文件 ssl_certificate_key ssl/www_nginxbar_org.key;# 网站证书密钥文件 grpc_ssl_verify off; grpc_ssl_session_reuse on; location / { grpc_pass grpcs://192.168.2.145:50051; } }