一般来说,子目录反向代理只需要以下配置就足够了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location ^~ /test/ {
proxy_pass https://example.com;
proxy_set_header Host example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
add_header X-Cache $upstream_cache_status;
add_header Cache-Control no-cache;
proxy_ssl_server_name off;
proxy_ssl_name $proxy_host;
}

每条配置解释:

  • location ^~ /test/: 匹配以 /test/ 开头的 URL 请求。^~ 表示优先匹配。
  • proxy_pass https://example.com;: 将请求转发到 https://example.com
  • proxy_set_header: 设置请求头,将一些客户端信息传递给后端服务器。
    • Host example.com;: 将请求头中的 Host 字段设置为 example.com,这是必须的,否则后端服务器可能无法正确处理请求。
    • X-Real-IP $remote_addr;: 传递客户端的真实 IP 地址。
    • X-Forwarded-For $proxy_add_x_forwarded_for;: 追加客户端的 IP 地址到 X-Forwarded-For 头部,用于记录完整的请求链路。
    • REMOTE-HOST $remote_addr;: 传递客户端的主机名(通常是 IP 地址)。
    • Upgrade $http_upgrade;Connection $http_connection;: 用于支持 WebSocket 代理。
    • X-Forwarded-Proto $scheme;: 传递请求的协议 (http 或 https)。
  • proxy_http_version 1.1;: 设置 HTTP 协议版本为 1.1。
  • add_header X-Cache $upstream_cache_status;: 添加一个响应头,显示缓存状态 (HIT, MISS, EXPIRED 等)。
  • add_header Cache-Control no-cache;: 设置响应头,指示客户端不要缓存响应。
  • proxy_ssl_server_name off;: 关闭 SNI (Server Name Indication)。
  • proxy_ssl_name $proxy_host;: 设置用于验证后端服务器证书的域名。

但实际使用会发现,如果反向代理的是一些有绝对路径的网站,就会出现 404 错误。

举个例子:

假设我们使用上述配置将 /test/ 映射到 https://example.com。当访问 http://your_server/test/ 时,Nginx 会将其代理到 https://example.com/。这通常没有问题。

但是,如果 https://example.com 的网页中有一个资源的链接是绝对路径,例如:

1
<img src="/images/logo.png">

当浏览器解析到这个标签时,它会尝试请求 http://server/images/logo.png,而不是 http://server/test/images/logo.png。由于服务器上 /images/logo.png 路径并不存在,就会导致 404 错误。

问题的原因在于,当网站使用绝对路径时,浏览器会根据当前的域名来拼接完整的 URL,而忽略了反向代理的子目录 /test/

使用rewrite重写url

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
location ^~ /test/ {
rewrite ^/test/(.*)$ /$1 break; # 重写 URL
proxy_pass https://example.com;
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache off;
proxy_ssl_server_name on;
proxy_ssl_name example.com;
add_header Strict-Transport-Security "max-age=31536000";
proxy_set_header X-Accel-Buffering no;
add_header X-Proxy-Cache $upstream_cache_status;
tcp_nodelay on;
location ~* /test/.*\.(css|js)$ {
rewrite ^/test/(.*)$ /$1 break;
proxy_pass https://example.com;
proxy_set_header Host example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_key "$scheme$proxy_host$uri";
proxy_ssl_server_name on;
proxy_ssl_name example.com;
expires 7d;
add_header Cache-Control "public";
}
}

我这里反代的是某个视频网站,所以我开了缓存+视频流优化,如果不需要请自行删减

反代前:

反代后:

虽然不知道为什么反代之后资源只会一个个加载了,但起码视频流是正常的,速度比反代前高得多