背景

某项目有两个外网的站点a.site1.comb.site2.com需要通过definesys.com进行代理,代理后的地址

  • a.definesys.com => a.site1.com
  • b.definesys.com => b.site2.com

a和b都是托管在vps站点上。

CNAME

接到这个任务时,以为很简单,到definesys.com域名后台增加两个域名,并且将CNAME指向代理的站点即可,但还是想简单了,这里简单介绍下vps托管站点的原理,vps就是大家所说的虚拟主机,相比云服务器,vps具有价格低,部署简单,监控方便等特点,所以很多站点都会托管到vps上,但我们都知道vps供应商不可能一台服务器只部署一个站点,肯定想法设法压榨服务器资源,一台服务器可能部署了上千个站点,那么是如何实现几千个站点都可以通过80端口进行访问,我在之前的这篇文章中有介绍过方法,就是根据访问的host进行路由达到访问不同站点的目的。

所以如果将a.definesys.com => a.site1.com,那么本质上是带着a.definesys.com这个host去访问a.site1.com的ip,vps是根据host来识别站点,当然识别不了a.definesys.com,所以一般这种情况下会报站点不存在之类的。

Nginx代理

既然CNAME走不通就考虑用definesys.com上的nginx进行反向代理

  • nginx.conf增加两个upstream
upstream a.definesys.com{
             server a.site1.com:80;
    }
    
upstream b.definesys.com{
             server a.site2.com:80;
    }

上面提到,vps是根据host来识别站点,所以要在http请求中配置http header Host,以下是当前nginx配置

location / {
        proxy_set_header X-forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header   REALIP   $remote_addr;
        proxy_pass http://$host;
        index  index.html index.htm;
    }

修改为

location / {
        if ( $host = "a.definesys.com" ) {
            proxy_set_header Host "a.site1.com";
        }
        
        if ( $host = "purchase.srmdemo.definesys.com" ) {
            proxy_set_header Host "b.site2.com";
        }
        proxy_set_header X-forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header   REALIP   $remote_addr;
        proxy_pass http://$host;
        index  index.html index.htm;
    }

根据host进行判断,并通过指令proxy_set_header设置Host头,但是报错

Reloading nginx configuration: nginx: [emerg] "proxy_set_header" directive is not allowed here

proxy_set_header指令不允许包含在if代码块中(不明白这么设计的目的),于是改了下配置

location / {
        set $remoteHost $host
        if ( $host = "a.definesys.com" ) {
            set $remoteHost "a.site1.com";
        }
        
        if ( $host = "purchase.srmdemo.definesys.com" ) {
            set $remoteHost "b.site2.com";
        }
        proxy_set_header Host $remoteHost
        proxy_set_header X-forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header   REALIP   $remote_addr;
        proxy_pass http://$host;
        index  index.html index.htm;
    }

通过一个变量解决了问题,重启nginx后访问正常,但是问题又来了,definesys.com上的有些站点访问不正常,测试过只要加上Host的设置就异常,虽然是代码问题,但是要去改代码也不现实,也试过将$remoteHost默认为空,但还是会带上Host的头。

换一个nginx?

既然在definesys.com上没法配置,就找其他服务器的nginx进行代理,尴尬的是definesys.com这个主机是带宽最高的机器用来做代理最适合,其他机器带宽非常低,配置后基本无法访问。所以这条路也行不通。

双重代理

既然definesys.com的nginx配置不能动,那么可以再创建一个nginx专门用来代理a和b站点,让definesys.com代理刚创建的nginx不就行了,于是新开了一个nginx的server,监听非80端口,配置如下

location / {
       set $remoteHost "portal.definesys.com";
       if ( $host = "a.definesys.com" ) {
           set $remoteHost "a.site1.com";
        }
       if ( $host = "b.definesys.com" ) {
           set $remoteHost "b.site2.com";
        }
       proxy_set_header Host $remoteHost;
       proxy_set_header X-forwarded-for $proxy_add_x_forwarded_for;
       proxy_set_header   REALIP   $remote_addr;
       index  index.html index.htm;
       proxy_pass http://$host;
  }

在definesys.com 80的nginx上将upstream指向本地nginx

upstream a.definesys.com{
             server 172.16.81.91:7009;
    }
    
upstream b.definesys.com{
             server 172.16.81.91:7009;
    }

这就不需要更改原配置,保持原配置不变。问题解决。

Trackback

no comment untill now

Add your comment now