You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NGINX反向代理location重写异常:后端重定向未按预期改写

问题

我正在配置NGINX反向代理,允许客户端通过代理的特定URL(如https://ip/service1、https://ip/service2)访问对应后端服务,但代理的location块URL与后端服务的基础URL不一致,且无法修改后端服务的基础URL。当前使用nginx/1.18.0(Debian 11环境),配置如下:

server {
        listen 443 ssl http2;
        server_name 192.168.1.4;
        #
        ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
        ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
        #
        ssl_protocols TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AE>
        ssl_ecdh_curve secp384r1;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        #
        location / {
            index index.html;
            root /var/www/;
        }
        #
        location /service1 {
                rewrite /service1/(.*) /$1 break;
                proxy_redirect   off;
                proxy_ssl_protocols TLSv1.3;
                proxy_pass https://192.168.3.2/;
                proxy_set_header Host "192.168.3.2";
                proxy_set_header X-Real-IP $remote_addr;
        }
        location /service2 {
                rewrite /service2/(.*) /$1 break;
                proxy_redirect   off;
                proxy_ssl_protocols TLSv1.3;
                proxy_pass https://192.168.3.2:8443/;
                proxy_set_header Host "192.168.3.2";
                proxy_set_header X-Real-IP $remote_addr;
        }
}

location /块用于提供各服务的快捷访问页面。我理解location块中的rewrite规则会将客户端含/service1的请求改写为/加后续路径,但访问https://192.168.1.4/service1时,登录页无CSS加载,登录后被后端重定向至https://192.168.1.4/index.php,而非预期的https://192.168.1.4/service1/index.php。CSS加载异常疑似与此相关。请问我的rewrite规则是否有误?能否在客户端与后端URL不同的情况下实现正确的proxy_pass?


解决方案

你的配置存在两个核心问题:

1. Rewrite规则的匹配局限性

原rewrite /service1/(.*) /$1 break;仅匹配带有/service1/(末尾斜杠)的请求,当用户访问/service1(无末尾斜杠)时,该规则不会触发,NGINX会自动重定向到/service1/,但后端返回的静态资源(如CSS、JS)使用绝对路径(例如/css/style.css),客户端会直接请求https://192.168.1.4/css/style.css,该请求被location /处理,无法获取后端的资源,导致加载失败。

2. 后端重定向未适配代理前缀

原配置proxy_redirect off;关闭了重定向URL的修改,后端返回的重定向路径(如/index.php)会直接返回给客户端,客户端跳转时不会带上/service1前缀,因此出现跳转到根路径index.php的问题。

修改后的配置示例(以service1为例)

server {
        listen 443 ssl http2;
        server_name 192.168.1.4;
        # SSL配置保持不变
        ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
        ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
        ssl_protocols TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_ecdh_curve secp384r1;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;

        location / {
            index index.html;
            root /var/www/;
        }

        # 处理不带末尾斜杠的请求,统一重定向到带斜杠的路径
        location = /service1 {
            return 302 /service1/;
        }

        location /service1/ {
            # 替换响应内容中的绝对路径,给静态资源、表单等加上代理前缀
            sub_filter 'href="/' 'href="/service1/';
            sub_filter 'src="/' 'src="/service1/';
            sub_filter 'action="/' 'action="/service1/';
            sub_filter_once off; # 替换所有匹配项

            # 修改后端返回的重定向URL,添加代理前缀
            proxy_redirect https://192.168.3.2/ https://192.168.1.4/service1/;
            proxy_redirect / /service1/;

            proxy_ssl_protocols TLSv1.3;
            proxy_pass https://192.168.3.2/;
            proxy_set_header Host "192.168.3.2";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            # 可选:如果后端支持,传递前缀信息
            proxy_set_header X-Forwarded-Prefix /service1;
        }

        # service2的配置同理修改
        location = /service2 {
            return 302 /service2/;
        }

        location /service2/ {
            sub_filter 'href="/' 'href="/service2/';
            sub_filter 'src="/' 'src="/service2/';
            sub_filter 'action="/' 'action="/service2/';
            sub_filter_once off;

            proxy_redirect https://192.168.3.2:8443/ https://192.168.1.4/service2/;
            proxy_redirect / /service2/;

            proxy_ssl_protocols TLSv1.3;
            proxy_pass https://192.168.3.2:8443/;
            proxy_set_header Host "192.168.3.2";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Prefix /service2;
        }
}

关键修改说明

  • 统一路径格式:通过location = /service1将无斜杠的请求重定向到带斜杠的路径,确保后续所有请求都包含完整前缀。
  • 替换响应内容中的绝对路径:使用sub_filter将后端返回的/css/、/js/等绝对路径替换为/service1/css/,让客户端请求正确的代理路径资源。
  • 修正重定向URL:开启proxy_redirect并配置规则,将后端返回的根路径重定向修改为带代理前缀的路径,解决登录后跳转错误的问题。
  • 移除冗余rewrite:利用NGINX原生的location与proxy_pass匹配逻辑(proxy_pass末尾带/时,会自动将location匹配的/service1/替换为后端的/),替代原rewrite规则,更稳定可靠。

内容的提问来源于stack exchange,提问作者user19019822

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 05:27:32