经常会碰到一些项目,其服务虽然在线上是通过同一个域名公开访问的,但是开发时,却是由多个不同的子项目组成的。在本地可以单独启动单独测试,一般是通过端口区分。在本地联调时,不想单独做很复杂的配置的话,就需要模拟线上环境,在同一个端口下把多个项目跑起来。这就需要用到反向代理。
假设有两个项目,单独启动时,分别运行在 5001 和 5003 端口,但是现在希望在本地能够通过 https://local.dev.example.com:5000 来访问,其中 /client/* 指向 5003 项目,而其他路由指向 5001 端口。
域名
在本地,可以配置一个 hosts (/etc/hosts)来模拟线上环境:
csharp 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost
127.0.0.1 local.dev.example.com
用 docker compose nginx 做反向代理
当然也可以用 nginx,如果不想安装和配置,建议使用 Docker compose 方案:
yaml version: 3.4
services: localproxy: build: context: ./LocalProxy dockerfile: Dockerfile ports: - 5000:80 networks: default: aliases: - local.dev.example.com
client:
build:
context: .
dockerfile: client/Dockerfile
ports:
- 5003:80
server: build: context: . dockerfile: server/Dockerfile ports: - 5001:80
networks: default: name: example_network
以上,通过 docker compose up 启动后,将 server 项目的 5001 映射到 80 端口,而 client 项目的 5003 也映射到 80 端口。而反向代理服务将 5000 映射到 80 端口。这样就可以通过 https://local.dev.example.com:5000 的方式访问到 client 和 server 了。
client 和 server 的 Dockerfile 根据具体的项目来写,而 localproxy 的 Dockerfile 是基于 nginx 的,内容如下:
dockerfile FROM nginx:alpine COPY nginx.conf /etc/nginx/nginx.conf RUN apk add --update openssl && rm -rf /var/cache/apk/* RUN mkdir -p /etc/nginx/ssl/certs RUN mkdir -p /etc/ssl/private/ RUN openssl req -x509 -nodes -days 365 -subj /C=CA/ST=QC/O=Example, Inc./CN=local.dev.example.com -addext subjectAltName=DNS:local.dev.example.com -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt; EXPOSE 80 EXPOSE 443 EXPOSE 5000
虽然完全可行,但是比较麻烦。如果不想用 Docker compose 也不想用 nginx,就可以使用 Caddy 来完成同样的事情:
用 caddy 来做反向代理
同样也需要在 hosts 里增加域名。
安装 caddy
如果没有安装,可以通过 brew install caddy(Mac)或者 choco install caddy(Windows)安装 caddy。
添加 Caddyfile
在项目的根目录下新建 Caddyfile 文件,内容如下:
dockerfile https://local.dev.example.com:5000 {
tls internal
reverse_proxy /client/* http://local.dev.example.com:5003
reverse_proxy http://local.dev.example.com:5001
}
运行 caddy
shell caddy run
分别启动项目后,同样可以使用 https://local.dev.example.com:5000 来访问 server 和 client 了,效果和 nginx 方案完全一样!