Nginx配置通用反向代理指定域名到指定服务
前言
首先我们先看一下要达到的效果,我们希望访问某一个域名自动指向本地启动的某一个端口的服务(我们就以域名 <number>.localapp.com
为例),效果如下:
8080.localapp.com => 127.0.0.1:8080
8081.localapp.com => 127.0.0.1:8081
接下来大家可能会说为什么要这么做呢,直接访问 http://127.0.0.1:8080 不好吗,非得转一层呢?下面就是好处:
1、解决 cookie 共享的问题
我们直接访问 http://127.0.0.1:8080 是拿不到 localapp.com 下面的 cookie 的,有部分网站的授权是通过 cookie 实现的,当然这个也可以通过 本地配置 host + webpack proxy
实现,但是需要在每个项目中都这样配置。
2、解决跨域的问题
在前后端分离的开发模式中,一般情况前端和服务端一般会使用不同域名。假如 http://localapp-api.com 这个是接口服务器域名,这个服务只允许 *.localapp.com
域名访问时,我们就只能通过 本地配置 host + webpack proxy
中的方式去配置,同样在每个项目都需要修改。如果项目中使用到了 OSS 并且开启了防盗链,OSS 也会去校验域名,导致 OSS 中的资源会加载失败。
3、配置本地 https 证书
如果使用 http://127.0.0.1:8080 访问,是不好配置 https 证书的,访问的时候也就会出现证书错误警告,首先是对开发不友好,如果我们想在手机端有些 app 的 webview 调试页面,那必须要用 https,如果配置了证书,就可以方便的调试。还有一点大家可能发现了,http 服务是拿不到 https 服务下面的 cookie 的。
4、同时启动多个项目
如果我们通过 本地配置 host + webpack proxy
来解决上面的问题,那我们必须要将服务在80或者443上启动,所以无法同时调试多个项目。
实施方案
下面内容主要包含如下:
- 搭建本地的 DNS 服务器,进行域名解析,将
<number>.localapp.com
指向127.0.0.1
- 配置配置 nginx 反向代理实现域名指向指定端口
运行流程如下
搭建DNS服务器
首先我们要知道为什么要搭建 DNS 服务器呢,而不是直接将域名指向 hosts 呢?是因为 hosts 文件不支持通配符,那么每个端口就需要写一条记录,添加了新的端口就需要添加新的记录,如下:
127.0.0.1 8080.localapp.com
127.0.0.1 8081.localapp.com
127.0.0.1 8082.localapp.com
127.0.0.1 8083.localapp.com
这里我们使用 dnsmasq 来搭建 DNS 服务器,该软件可以运行在 linux/macOS 等操作系统上,以 macOS 为例,我们可以直接使用 brew 进行安装(linux 可以使用内置的 apt 或者 yum 工具进行安装)。
brew install dnsmasq
安装完成修改配置添加 DNS 解析规则,配置文件位置在 $HOMEBREW_PREFIX/etc/dnsmasq.conf
,我们可以使用 VSCode 或者 vim 进行修改。
要添加上面的解析,需要在配置文件中追加下面的内容,这条内容表示 .localapp.com
都解析到 127.0.0.1
,当然这里也可以指向局域网的其他 IP 实现解析。
# 如果仅仅给自己使用的话,就用 127.0.0.1,否则的话可以加上局域网的IP地址,使用逗号分开
listen-address=127.0.0.1,192.168.1.6
# 注意下面的规则仅匹配 abc.localapp.com 不能匹配,abc.def.localapp.com
address=/.localapp.com/127.0.0.1
修改完成之后,重新启动一下 DNS 服务器即可;
# 这里要使用sudo,否则可能会不生效,不加sudo执行时,控制台也会给出警告
sudo brew services restart dnsmasq
配置DNS解析
DNS 服务器搭建完成之后,我们还需要修改下本地网络 DNS 解析,以 macOS 为例:
需要将 127.0.0.1 这个 DNS 放到第一位,保存网络后,在本地终端 ping 的时候就会发现下面的域名都指向了 127.0.0.1。
ping 123.localapp.com
ping 456.localapp.com
ping abc.localapp.com
配置反向代理
1、首先我们在 nginx 中创建一个配置文件如 proxy.localapp.conf
,然后将 server_name 设置为正则表达式,具体内容如下所示:
server {
listen 80;
server_name ~^(?<port>\d+)\.localapp\.com$;
location / {
# 代理到本地的端口上
# 8000.local.com => 127.0.0.1:8000
# 9000.local.com => 127.0.0.1:9000
proxy_pass http://127.0.0.1:$port;
proxy_set_header Host $host;
client_max_body_size 50m;
proxy_redirect off;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass_header Sec-Websocket-Extensions;
index index.html index.htm;
}
}
配置说明:
- server_name: 该域名匹配 1~n 个数字开头的域名,并且将这段数字提取后存储在变量 port 中,例如 8080.localapp.com 中 port=8080。
- proxy_pass: 直接转发到本地127.0.0.1监听的某一个端口号上。
- proxy_set_header: 设置代理请求的头信息,用于真实的目标服务器一些 header。例如设置了 Host 为 $host,在 http://127.0.0.1:8080 这台服务器中得到的 Host 就是 8080.localapp.com 而不是 127.0.0.1:8080。
2、重新加载 Nginx 配置以使更改生效
nginx -s reload
测试
现在在 8080 端口上启动一个 webpack devServer,然后使用 8080.localapp.com
去访问发现就可以正常使用了。
常见问题
1、要是发现配置的 dns 无效,可以检查是否开启了 clash,需要把域名规则在 clash 中排除