nginx+ngrok共享80端口

上一篇我们讲到 通过ngrok实现内网穿透,在运行服务器时指定了参数 -httpAddr=:30080 -httpsAddr=:30443

1
./bin/ngrokd -domain=ngrok.kyo86.com -tlsKey=./keys/device.key -tlsCrt=./keys/device.crt -httpAddr=:30080 -httpsAddr=:30443

是为了避免和nginx服务器端口占用冲突,但这会导致我们通过子域名来映射web服务时只能通过30080端口访问,而不是通常的80端口。

例如我们启动一个hexo博客

1
hexo s
1
2
3
4
daimingzhuang@ecs-windows:/mnt/d/Projects/blog$ hexo s
INFO Validating config
INFO Start processing
INFO Hexo is running at http://localhost:4000/ . Press Ctrl+C to stop.

然后将其使用的4000端口通过hexo子域名映射出去

1
./ngrok.exe -config="ngrok.cfg" -subdomain=hexo -proto=http 4000
1
2
3
4
5
6
ngrok                                                                (Ctrl+C to quit)                       Tunnel Status                 online
Version 1.7/1.7
Forwarding http://hexo.ngrok.kyo86.com:30080 -> 127.0.0.1:4000
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms

这时候任何人都可以通过 http://hexo.ngrok.kyo86.com:30080 来访问博客了但这显然不是很令人舒服,我希望能通过 http://hexo.ngrok.kyo86.com 来访问。

通常80端口会留给nginx使用,在nginx上配置反向代理,根据域名或者根据路径把请求转发到其他端口或者其他内部服务器上。

下面我们就通过nginx配置将 *.ngrok.kyo86.com 的请求转发到 30080端口

1
vim /etc/nginx/sites-enabled/default

新建一个server configuration如下

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name *.ngrok.kyo86.com;
location / {
proxy_pass http://127.0.0.1:30080;
proxy_redirect off;
proxy_set_header Host $http_host:30080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 120;
}
}

server_name来指定域名,特别注意 $http_host:30080 这里一定要指定端口,不然当我们使用 http://hexo.ngrok.kyo86.com 访问时请求确实会被转发到ngrok服务器,但是ngrok会根据 http://hexo.ngrok.kyo86.com 这个地址去寻找tunnel,而被注册的地址是 http://hexo.ngrok.kyo86.com:30080 所以会找不到tunnel,也就无法将请求转发给hexo服务器。

检测nginx配置文件合法性

1
nginx -t

重启nginx服务器

1
service nginx restart

现在就可以通过 http://hexo.ngrok.kyo86.com 来访问hexo博客了,当然仍然可以通过 http://hexo.ngrok.kyo86.com:30080 来访问。

到现在只剩下一点稍微不爽,就是在运行ngrok客户端时,其中回显

1
Forwarding                    http://hexo.ngrok.kyo86.com:30080 -> 127.0.0.1:4000

仍然带着:30080。

实际上我们可以把nginx和ngrok绑定在不同IP的80端口上,nginx绑定在公网IP:80,ngrok绑定在localhost:80,这样是没有冲突的。

修改nginx配置

1
vim /etc/nginx/sites-enabled/default
1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 172.19.XX.XXX:80;
server_name *.ngrok.kyo86.com;
location / {
proxy_pass http://127.0.0.1;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 120;
}
}

这里的 listen 在端口前面加了IP地址,我在阿里云上,虽然ECS是有公网地址的,但查看ifconfig时没有看到公网地址,我就指定了连接到公网的那块网卡的地址,这时候 $http_host就不要带上:80了,因为这时向ngrok注册tunnel的地址是不带端口的。

还要注意,其他的server配置如果是使用80端口,都要改成指定IP地址绑定,不然后面会和ngrok冲突。

重启nginx服务器

1
service nginx restart

运行ngrok服务器

1
./bin/ngrokd -domain=ngrok.kyo86.com -tlsKey=./keys/device.key -tlsCrt=./keys/device.crt -httpAddr=127.0.0.1:80 -httpsAddr=127.0.0.1:443

这里把端口绑定成了127.0.0.1的80和443。

启动ngrok客户端,回显变成了

1
Forwarding                    http://hexo.ngrok.kyo86.com -> 127.0.0.1:4000

测试访问 http://hexo.ngrok.kyo86.com ,成功,完美。

如果启动ngrokd时报错

1
panic: listen tcp 127.0.0.1:80: bind: address already in use

去检查nginx配置看是不是所有80端口前都加了IP地址,或者用

1
netstat -anp|grep :80

来查看绑定了80端口的进程。