解决Nginx监听非80端口反向代理80端口出现跳转错误

最近遇到一个Nginx反向代理的问题,举例来说:
有一个example.com域名,在web服务器(简称web-server,假定服务器的ip为8.8.8.8)上使用nginx反向代理本地的tomcat服务(8080端口),配置信息如下:

http {
  upstream tdt_tomcat_server {
    server 127.0.0.1:8080 weight=1 max_fails=3 fail_timeout=30s;
  }

  server {
    listen 80;
    server_name example.com *.example.com;

    location / {
      proxy_next_upstream http_502 http_504 error timeout invalid_header;

      proxy_set_header Host  $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://tdt_tomcat_server;
      proxy_redirect off;
    }
  }
}

又有一台反向代理服务器(proxy-server),因为特殊原因这台服务器对外只能使用非80端口,通过这台服务器反向代理上面的web-server,配置信息如下:

http {
  upstream tdt_web_server {
    server 8.8.8.8:80 weight=1 max_fails=3 fail_timeout=30s;
  }

  server {
    listen 9000;
    server_name example.com *.example.com;

    location / {
      proxy_next_upstream http_502 http_504 error timeout invalid_header;

      proxy_set_header Host  $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://tdt_web_server;
      proxy_redirect off;
    }
  }
}

首先将example.com域名通过hosts文件绑定ip到proxy-server上面,然后访问http://example.com:9000的时候会调整到80端口上面:

[root@proxy-server ~]# curl -I http://example.com:9000/
HTTP/1.1 302 Found
Server: nginx/1.12.0
Location: http://example.com/

Google了一下查到需要将proxy_set_header Host 设置成主机+端口的形式,即将 proxy_set_header Host $host; 修改成 proxy_set_header Host $host:$server_port;
这个时候再次访问http://example.com:9000的时候就正常了,不过还有一个问题,就是当访问 http://example.com:9000/userinfo 的时候需要用户登录才能访问,这个时候系统应该自动跳转到 http://example.com:9000/login 才对,但是确是跳转到了 http://example.com/login :

[root@proxy-server ~]# curl -I http://example.com:9000/userinfo
HTTP/1.1 302 Found
Server: nginx/1.12.0
Location: http://example.com/login

但是直接访问 http://example.com:9000/login 也是正常的。一开始想到是tomcat服务器的问题,但是如果反向代理服务器直接设置成web-server上的8080端口的话则是正常的,因此断定问题出在了nginx反向代理的设置上面,后来查阅到nginx和Tomcat集成后发生的重定向问题分析和解决这篇文章,可以通过proxy_redirect进行设置,修改后的proxy-server配置信息如下:

http {
  upstream tdt_web_server {
    server 8.8.8.8:80 weight=1 max_fails=3 fail_timeout=30s;
  }

  server {
    listen 9000;
    server_name example.com *.example.com;

    location / {
      proxy_next_upstream http_502 http_504 error timeout invalid_header;

      proxy_set_header Host  $host:$server_port;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_redirect http://$host http://$host:$server_port;
      proxy_redirect off;
    }
  }
}

这个时候再访问 http://example.com:9000/userinfo 就自动跳转到 http://example.com:9000/login 了:

[root@proxy-server ~]# curl -I http://example.com:9000/userinfo
HTTP/1.1 302 Found
Server: nginx/1.12.0
Location: http://example.com:9000/login

最后还有一个问题需要特别注意,就是web-server中nginx的配置信息中一定不要这样设置:proxy_set_header Host $host:$server_port;,而是要设置成 proxy_set_header Host $host;,即不加端口号,否则自动跳转会失败。

参考资料:
nginx和Tomcat集成后发生的重定向问题分析和解决
Nginx + Apache trailing slash redirect
Nginx reverse proxy - requests still return port 80
解决nginx反向代理监听非80端口造成的端口丢失问题
Nginx代理非80端口

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注