文章目录
如果想了解更多与Nginx相关的内容,可以查看Nginx专栏: Nginx
视频教程:15-Nginx代理概述及环境准备
1. 反向代理
1.1 正向代理和反向代理的区别
正向代理更多的是为客户端服务,目标服务器看到的是正向代理服务器的IP地址,而不是客户端的真实IP地址

魔法使用的就是正向代理技术,魔法的使用教程可以参考我的另一篇博文:GitHub的使用技巧(加速访问GitHub、查看GitHub的热门项目、查看GitHub推荐的项目、Fork、Issue、快速找到项目的安装包、GitHub的各种快捷键)
反向代理更多的是为服务器端服务,真实服务器看到的是反向代理服务器的请求,而不是直接来自客户端的请求

1.2 正向代理案例
视频教程:16-Nginx正向代理实现
猫咪软件(也就是魔法)正是基于正向代理实现的,在猫咪软件中开启代理之后,按下Win + i快捷键打开设置界面,点击网络和Internet

接着点击代理,可以发现猫咪软件开启了使用代理服务器选项,地址是127.0.0.1,端口是7890,而7890正是猫咪软件占用的端口

1.3 反向代理的配置语法
Nginx反向代理模块的指令是由ngx_http_proxy_module模块进行解析的,ngx_http_proxy_module模块在安装Nginx的时候已经加装到Nginx中了,接下来我们介绍一下反向代理中的常用指令
1.3.1 proxy_pass
proxy_pass指令用来设置被代理服务器地址,可以是主机名称 + 端口号的形式,也可以是IP地址 + 端口号的形式
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_pass URL; | location |
其中URL为要设置的被代理服务器地址,包含传输协议(http,https://)、主机名称或IP地址、端口号、URI等要素
1.3.2 prox_pass中URL最后是否要加/
在编写proxy_pass的时候,URL最后是否要加/呢,我们通过两个例子来说明这个问题
1.3.2.1 第一个例子
首先我们来看匹配到的server块中路径上只有一个/的情况
# 匹配到的server块中路径上只有一个/
server {
listen 80;
server_name localhost;
location / {
# proxy_pass http://192.168.200.146; # 第一个proxy_pass
proxy_pass http://192.168.200.146/; # 第二个proxy_pass
}
}
当客户端访问http://localhost/index.html时,第一个proxy_pass和第二个proxy_pass效果是一样的
接着我们来看匹配到的server块中有额外路径的情况
# 匹配到的server块中有额外路径
server {
listen 80;
server_name localhost;
location /server {
# proxy_pass http://192.168.200.146; # 第一个proxy_pass
proxy_pass http://192.168.200.146/; # 第二个proxy_pass
}
}
当客户端访问http://localhost/server时,两个proxy_pass的效果就不一样了
- 第一个proxy_pass相当于访问http://192.168.200.146/server/index.html
- 第二个proxy_pass相当于访问http://192.168.200.146/index.html
当proxy_pass的端口号(如果不指定端口,默认会使用80端口)后面存在URL(即使只有一个/)时,匹配到的location块中的路径会被proxy_pass中端口号后面存在的URL替换
1.3.2.2 第二个例子
server {
listen 80;
server_name your-nginx-domain.com;
location /api/ {
# proxy_pass http://192.168.100.200;
proxy_pass http://192.168.100.200/;
proxy_set_header Host $host;
}
}
在 Nginx 反向代理中,proxy_pass 的路径拼接规则取决于其是否以斜杠 / 结尾
以上述代理规则为例,两种情况的详细分析如下:
1. proxy_pass 配置为 192.168.100.200(无斜杠结尾)
- 规则:Nginx 直接拼接
location匹配的路径到proxy_pass的 URL 后 - 示例:
- 原始请求:
http://your-nginx-domain/api/user/findById - 代理后的请求:
http://192.168.100.200/api/user/findById
- 原始请求:
- 关键点:
proxy_pass的 URL 不 以/结尾时,location匹配的路径会被完整保留并追加到proxy_pass的 URL 后
2. proxy_pass 配置为 192.168.100.200/(有斜杠结尾)
- 规则:Nginx 替换
location匹配的路径,仅保留proxy_pass的路径部分(即/),然后拼接原始请求的 URI。 - 示例
- 原始请求:
http://your-nginx-domain/api/user/findById - 代理后请求:
http://192.168.100.200/user/findById
- 原始请求:
- 关键点:
proxy_pass的 URL 以/结尾时,location匹配的路径会被完全剔除,仅保留proxy_pass的路径部分,然后拼接原始请求的 URI(已剔除location匹配的路径)
1.3.2.3 总结对比
server {
listen 80;
server_name your-nginx-domain.com;
location /api/ {
# proxy_pass http://192.168.100.200;
proxy_pass http://192.168.100.200/;
proxy_set_header Host $host;
}
}
| 配置方式 | 原始请求路径 | 代理后的请求路径 |
|---|---|---|
proxy_pass 192.168.100.200 | /api/user/findById | http://192.168.100.200/api/user/findById |
proxy_pass 192.168.100.200/ | /api/user/findById | http://192.168.100.200/user/findById |
1.3.3 proxy_set_header指令
proxy_set_header指令可以更改Nginx服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给被代理的服务器
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_set_header field value; | proxy_set_header Host $proxy_host; proxy_set_header Connection close; | http、server、location |
代理服务器[192.168.200.133]
server {
listen 8080;
server_name localhost;
location /server {
proxy_pass http://192.168.200.146:8080/;
proxy_set_header username TOM;
}
}
被代理的服务器(真正处理请求的服务端)[192.168.200.146]
server {
listen 8080;
server_name localhost;
default_type text/plain;
return 200 $http_username;
}
1.3.4 proxy_redirect
视频教程:19-Nginx反向代理之proxy_redirect指令
proxy_redirect指令用于重置头信息中的"Location"和"Refresh"的值
| 语法 | 默认值 | 位置 |
|---|---|---|
proxyredirect redirect replacement;proxyredirect default;proxyredirect off; | proxyredirect default; | http, server, location |
| 语法 | 说明 |
|---|---|
| proxy_redirect redirect replacement; | 将响应头中的 Location 值从 redirect 替换为 replacement |
| proxy_redirect default; | 使用匹配到的 location 块中的 uri 变量作为 replacement,将 proxy_pass 变量作为 redirect 进行替换 |
| proxy_redirect off; | 关闭 proxy_redirect 的功能 |
如果使用默认规则(default),假设location块的配置如下
location /api/ {
proxy_pass http://backend.example.com:8080/backend/;
proxy_redirect default;
}
Nginx 会自动将 Location 中的 http://backend.example.com:8080/backend/ 替换为 /api/
例如,如果后端服务器返回的 Location 头是 http://backend.example.com:8080/backend/user/profile,Nginx 会将其替换为 /api/user/profile
为什么要用proxy_redirect指令呢,主要是为了隐藏真正的服务端的IP地址
观察以下信息中的Location属性可以发现,第一个Location暴露了服务端的IP地址,而第二个Location没有暴露服务端的IP地址

代理服务器[192.168.200.133]
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://192.168.200.146:8081/;
proxy_redirect http://192.168.200.146 http://192.168.200.133;
}
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://192.168.200.146/;
}
}
服务端[192.168.200.146]
server {
listen 8081;
server_name localhost;
if (!-f $request_filename) {
return 302 http://192.168.200.146;
}
}
1.4 反向代理实战案例
视频教程:20-Nginx反向代理的实战案例

服务器1、2、3存在两种情况
- 第一种情况:三台服务器的内容不一样
- 第二种情况:三台服务器的内容是一样的
1.4.1 各个服务器的内容不一样
如果各个服务器的内容不一样,可以根据用户请求来分发到不同的服务器
代理服务器的配置
server {
listen 8082;
server_name localhost;
location /server1 {
proxy_pass http://192.168.200.146:9001/;
}
location /server2 {
proxy_pass http://192.168.200.146:9002/;
}
location /server3 {
proxy_pass http://192.168.200.146:9003/;
}
}
服务端的配置
# server1
server {
listen 9001;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.200.146:9001</h1>';
}
# server2
server {
listen 9002;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.200.146:9002</h1>';
}
# server3
server {
listen 9003;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.200.146:9003</h1>';
}
1.4.2 各个服务器的内容相同
如果各个服务器的内容是一样的,该如何处理呢?我们在后面的 负载均衡 章节进行讲解
2. 安全控制
Web服务器的安全是比较大的一个话题,里面所涉及的内容很多,我们主要讨论Nginx反向代理如何提升Web服务器的安全
在反向代理服务器之前设置防火墙,并仅留一个入口供代理服务器访问,可以实现以下安全措施:
- 限制访问:防火墙可以限制对应用程序服务器的直接访问,只允许通过代理服务器的流量
- 隐藏内部网络结构:外部客户端无法直接访问内部的应用程序服务器,从而隐藏了内部网络结构,减少了攻击面
- 集中监控和管理:所有进入内部网络的流量都通过代理服务器,这使得监控和管理变得更加集中和高效
- 增强安全性:代理服务器可以作为第一道防线,对进入的流量进行过滤和检查,阻止潜在的恶意攻击
- 负载均衡:代理服务器还可以实现负载均衡,将流量分配到多个应用程序服务器上,提高系统的可用性和性能

2.1 使用SSL对流量进行加密
使用SSL对流量进行加密,翻译成大家熟悉的说法就是将我们常用的http请求转变成https请求
简单来说,http请求和https请求都是基于HTTP协议的,只不过https是身披SSL外壳的http
HTTPS是一种通过计算机网络进行安全通信的传输协议,由HTTP进行通信,利用SSL/TLS建立全通信,加密数据包,确保数据的安全性
2.1.1 SSL协议&TLS协议
-
SSL(Secure Sockets Layer):安全套接字层协议
-
TLS(Transport Layer Security):传输层安全性协议
SSL协议&TSL协议都是为网络通信提供安全及数据完整性的安全协议,TLS和SSL都是在传输层和应用层对网络连接进行加密
2.1.2 为什么要使用https
使用HTTPS(超文本传输安全协议)有很多重要的原因,主要包括以下几个方面:
- 数据加密:HTTPS通过TLS(传输层安全性协议)或SSL(安全套接字层协议)对传输的数据进行加密,防止数据在传输过程中被窃听或篡改。这对于保护敏感信息(如登录凭据、信用卡号、个人信息等)至关重要
- 数据完整性:HTTPS确保数据在传输过程中未被篡改。通过使用消息认证码(MAC)来验证数据的完整性,任何对数据的篡改都会被发现
- 身份验证:HTTPS通过数字证书验证服务器的身份,确保用户正在与真实的网站进行通信,而不是一个伪装的网站。这有助于防止中间人攻击(MITM)
- 信任和信誉:使用HTTPS可以增强用户对网站的信任。现代浏览器会显示HTTPS网站的安全状态,用户更倾向于信任显示为“安全”的网站。此外,搜索引擎(如Google)会优先索引HTTPS网站,这有助于提高网站的搜索引擎排名(SEO)
- 防止劫持:在一些网络环境中(如公共Wi-Fi),未加密的HTTP流量容易被劫持和篡改。HTTPS可以防止这种情况发生
2.2 Nginx添加SSL支持
Nginx要想使用SSL,需要添加--with-http_ssl_module模块
运行nginx -V 2>&1 | grep -o -- '--with-http_ssl_module'指令,如果显示--with-http_ssl_module,说明--with-http_ssl_module模块已成功添加
nginx -V 2>&1 | grep -o -- '--with-http_ssl_module'

2.3 Nginx中与SSL相关指令
2.3.1 ssl指令
ssl指令用来在指定的服务器开启HTTPS
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl on | off; | ssl off; | http、server |
实际开发中用的更多的是以下配置
server {
listen 443 ssl;
}
2.3.2 ssl_certificate指令
PEM(Privacy-Enhanced Mail)是一种证书格式,用于存储安全套接字层(SSL)证书、私钥和其他加密密钥
ssl_certificate指令用于为当前虚拟主机指定一个带有PEM格式证书的证书
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl_certificate file; | http、server |
2.3.3 ssl_certificate_key指令
ssl_certificate_key指令用于指定 SSL 私钥文件的路径
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl_certificate_key file; | http、server |
2.3.4 ssl_session_cache指令
ssl_session_cache指令用与配置用于SSL会话的缓存
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl_sesion_cache off|none|[builtin[:size]] [shared:name:size] | ssl_session_cache none; | http、server |
| 选项 | 描述 |
|---|---|
| off | 禁用会话缓存,客户端不得重复使用会话 |
| none | 禁止使用会话缓存,客户端可以重复使用,但是并没有在缓存中存储会话参数 |
| builtin | 内置OpenSSL缓存,仅在一个工作进程中使用 |
| shared | 所有工作进程之间共享缓存,缓存的相关信息用name和size来指定 |
2.3.5 ssl_session_timeout指令
开启SSL会话功能后,ssl_session_timeout指令用于设置 SSL/TLS 会话缓存中存储的会话参数(Session ID 或 Session Ticket)的有效期
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl_session_timeout time; | ssl_session_timeout 5m; | http、server |
2.3.6 ssl_ciphers指令
ssl_ciphers指令可以指出允许的密码,密码指定为OpenSSL支持的格式
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl_ciphers ciphers; | ssl_ciphers HIGH:!aNULL:!MD5; | http、server |
可以使用openssl ciphers指令查看OpenSSL支持的格式(前提是当前服务器已成功安装OpenSSL)
openssl version

openssl ciphers

2.3.7 ssl_prefer_server_ciphers指令
ssl_prefer_server_ciphers指令用于指定是否服务器密码优先客户端密码
| 语法 | 默认值 | 位置 |
|---|---|---|
| ssl_perfer_server_ciphers on|off; | ssl_perfer_server_ciphers off; | http、server |
2.4 如何获取SSL证书
2.4.1 通过阿里云、腾讯云等云服务商购买
SSL证书需要绑定一个域名,购买域名需要支付一定的费用,而且域名需要备案,比较麻烦
我们以阿里云为例,演示购买SSL证书的步骤
首先,在阿里云的官网上找到数字证书管理服务(原SSL证书),点击登录控制台
https://www.aliyun.com/product/cas

接着点击立即购买


2.4.2 使用openssl生成证书文件
先确认当前服务器是否已经成功安装openssl
openssl version
整体步骤如图所示

我们先创建一个目录,用于管理证书文件
mkdir /home/ssl && cd /home/ssl
接着运行以下指令生成相关文件
openssl genrsa -des3 -out server.key 1024
生成server.key文件的过程中需要设置一个密码

openssl req -new -key server.key -out server.csr
生成server.csr文件的过程中需要输入刚才生成server.key文件时设置的密码

生成server.csr文件的过程中需要填写一些信息(可以随意填写,不会验证,但如果是通过云服务商购买的,输入过程中会有实时验证
| 字段名称 | 说明 |
|---|---|
| Country Name (2 letter code) | 国家代码,使用两位字母缩写。CN 代表中国。这是证书的基本信息之一,用于标识组织所在的国家 |
| State or Province Name (full name) | 省份或州的全名 |
| Locality Name (eg, city) | 城市名称 |
| Organization Name (eg, company) | 组织(公司、机构)的全名。这是证书颁发机构(CA)用来验证证书申请者身份的重要信息 |
| Organizational Unit Name (eg, section) | 组织单位名称,例如部门、团队或子机构。这有助于在大型组织中进一步区分不同的部门或业务单元 |
| Common Name (e.g. server FQDN or YOUR name) | 常用名称,通常是您希望通过 SSL/TLS 证书保护的域名(Fully Qualified Domain Name, FQDN),或者是服务器的主机名(如果用于内部) 如果证书用于服务器身份验证,则填写服务器的主机名。这个字段对于证书的验证至关重要,浏览器会将其与您访问的域名进行比对 |
| Email Address | 联系电子邮件地址。这个字段是可选的,但提供它可以方便 CA 在需要时与您联系。如果您不想提供,可以直接按回车键跳过(留空) |
| A challenge password | 挑战密码。这是一个可选的密码,用于保护您的证书签名请求(CSR)文件。如果您设置了此密码,之后在处理 CSR 文件生成证书时需要提供此密码 |
| An optional company name | 可选的公司名称。这是一个可选字段,如果您在 “Organization Name” 中没有提供完整信息,或者想提供另一个名称,可以在此填写 |
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
中途需要输入刚才生成server.key文件时设置的密码

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

最终会生成四个文件

2.5 开启SSL支持
2.5.1 开启https支持前
假设nginx.conf文件中有如下server块
server {
listen 80;
server_name 127.0.0.1;
location / {
root /www/server/nginx/html;
index index.html index.htm index.php;
}
}
正常情况下是可以访问的

如果我们在网址前面加上https://前缀,就会发现网站打不开了,说明Nginx默认是不支持https访问的

2.5.2 开启https支持后
接下来我们通过修改nginx.conf配置文件开启Nginx对https的支持
2.5.2.1 修改nginx.conf文件
在nginx.conf文件中添加一个server块,重点修改以下三个参数
- ssl_certificate:指定 SSL 证书文件路径
- ssl_certificate_key:# 指定 SSL 私钥文件路径
- root:# 网站根目录
server {
listen 443 ssl; # 监听 443 端口,启用 SSL/TLS(HTTPS)
server_name localhost; # 服务器名称,这里设置为 "localhost"
ssl_certificate /home/ssl/server.crt; # 指定 SSL 证书文件路径
ssl_certificate_key /home/ssl/server.key; # 指定 SSL 私钥文件路径
ssl_session_cache shared:SSL:1m; # 共享 SSL 会话缓存,大小为 1MB
ssl_session_timeout 5m; # SSL 会话超时时间,5 分钟
ssl_ciphers HIGH:!aNULL:!MD5; # 指定加密套件,排除不安全的算法
ssl_prefer_server_ciphers on; # 优先使用服务器指定的加密套件
location / { # 匹配所有以 "/" 开头的请求
root /www/server/nginx/html; # 网站根目录
index index.html index.htm; # 默认索引文件
}
}
2.5.2.2 开放防火墙的443端口
- 如果你使用的是云服务器,请在安全组中放行 443 端口
- 如果安装了宝塔,除了在安全组中放行 443 端口,可能还要在宝塔中放行 443 端口
2.5.2.3 验证
再次访问带https前缀的网址,发现已经可以成功访问了,但是浏览器弹出了你的连接不是专用连接的提示,主要是因为我们使用openssl生成的证书并没有经过第三方机构的认证,浏览器任务这不是一个安全的连接

如果我们想要继续访问的话,可以点击高级,再点击继续访问,就可以看到Nginx的欢迎页面了


2.5.2.4 输入baidu.com时为什么不需要输入https://前缀也能够跳转到https://www.baidu.com
大家可能会有一个疑问,上面我们在验证时https前缀都是手动输入的,但我们在访问baidu.com时并没有加https://前缀,为什么会自动跳转到https://www.baidu.com页面呢
如何实现像百度一样的跳转效果呢,我们可以使用rewrite指令来实现
我们修改监听80端口的server块,在server块中添加rewrite指令(将rewrite指令中的127.0.0.1改成服务器的IP地址或具体的域名)
server {
listen 80;
server_name 127.0.0.1;
location / {
rewrite ^(.*) https://127.0.0.1$1;
}
}
重载nginx.conf配置文件后直接访问没有https://前缀的网址,也能跳转到https对应的页面了
3. 反向代理的系统优化
3.1 Buffer&Cache
在反向代理系统中,Buffer(缓冲区)和Cache(缓存)是两个重要的概念,它们在提高系统性能和效率方面发挥着关键作用
- Buffer是一个临时存储区域,用于在数据传输过程中暂存数据。在反向代理系统中,缓冲区通常用于处理客户端请求和服务器响应之间的数据流
- Cache是一个用于存储频繁访问数据的临时存储区域。在反向代理系统中,缓存通常用于存储静态内容(如HTML、CSS、JavaScript、图片等)和动态内容的缓存版本
3.2 Buffer相关指令
3.2.1 proxy_buffering指令
proxy_buffering指令用于开启或者关闭代理服务器的缓冲区
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_buffering on|off; | proxy_buffering on; | http、server、location |
3.2.2 proxy_buffers指令
proxy_buffers指令用于指定单个连接从代理服务器读取响应的缓存区的个数和大小
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_buffers number size; | proxy_buffers 8 4K | 8K;(与系统平台有关) | http、server、location |
缓冲区的总大小为number * size
- number:缓冲区的个数
- size:每个缓冲区的大小
3.2.3 proxy_buffer_size指令
proxy_buffer_size指令用于设置从被代理服务器获取的第一部分响应数据的大小(保持与proxy_buffers中的size一致即可)
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_buffer_size size; | proxy_buffer_size 4k | 8k;(与系统平台有关) | http、server、location |
3.2.4 proxy_busy_buffers_size指令
proxy_busy_buffers_size指令用于限制同时处于BUSY状态的缓冲总大小
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_busy_buffers_size size; | proxy_busy_buffers_size 8k|16K; | http、server、location |
3.2.5 proxy_temp_path指令
注意path最多设置三层
当缓冲区存满后,仍未被Nginx服务器完全接受,响应数据就会被临时存放在磁盘文件上,proxy_temp_path指令用于设置文件路径
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_temp_path path; | proxy_temp_path proxy_temp; | http、server、location |
3.2.6 proxy_temp_file_write_size指令
proxy_temp_file_write_size指令用于设置磁盘上缓冲文件的大小
| 语法 | 默认值 | 位置 |
|---|---|---|
| proxy_temp_file_write_size size; | proxy_temp_file_write_size 8K | 16K; | http、server、location |
3.2.7 通用网站与Buffer有关的配置
proxy_buffering on;
proxy_buffer_size 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
&spm=1001.2101.3001.5002&articleId=149666367&d=1&t=3&u=eaabe522606040ec8c03b1f6fe51800f)
359

被折叠的 条评论
为什么被折叠?



