Nginx端口转发的坑

最近在配置Nginx转发端口的时候踩了个大坑,记录一下

需求是这样的,我们游戏服务器使用的wss协议,需要用nginx进行大量的端口转发,如wss://xxx.com/10000 转发到 ws://xxx.com:10000,后面的端口范围是10000到11000,我不想写1000条这样的规则,于是我在网上找了这样一段代码:

location ~* ^/(?<port>\d+)$ {
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}

咋一看,好像确实能用,就是把/port替换成:port。之后被同事发现了,惊呼我艹,这特么相当于在公网裸奔。服务器的安全组虽然设置了只对外开放10000到11000端口,但是这段代码,相当于在用户可以通过nginx的80或者443端口,间接访问到任意端口!当服务器的规模还小的时候,一切都正常,但是当用户量上去了,一定会被扫,一旦被扫到一些敏感端口,后果不堪设想。

如何解决这个问题,首先想到的是用if语句,但在Nginx社区中有一个说法”If Is Evil”(if是邪恶的),因为在某些复杂情况下if语句可能导致意外行为。所以我最终采取匹配数字的方式:

location ~* ^/(?<port>(20[0-9]\{3\}))$ {
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}

意思是0到9这一区段数值重复3个,也就是10000-10999的端口能匹配上,这样子其它端口就匹配不上,或者:

location ~* ^/(?<port>2[0-1]\d\d\d)$ {
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}