如何在Docker中为同一Vue.js应用实现多子域名托管(多租户)
一、本地环境配置(Docker + 反向代理)
1. 用Nginx实现通配符子域名转发
本地localhost的子域名默认不会自动指向127.0.0.1,手动修改hosts无法满足动态添加需求,通过Nginx反向代理统一处理所有子域名请求:
Docker Compose配置
在docker-compose.yml中添加Nginx服务:
services: # 保留原有的backend、database、frontend、app服务配置 nginx: image: nginx:alpine ports: - "3001:80" # 对外暴露3001端口,对应原app的访问端口 volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf depends_on: - app
Nginx配置文件(nginx.conf)
配置通配符虚拟主机,将所有子域名请求转发到Vue app容器:
server { listen 80; server_name *.localhost; location / { proxy_pass http://app:3000; # 指向app容器的内部端口(根据实际端口调整) proxy_set_header Host $host; # 保留原始请求的Host头,确保Vue能获取子域名 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
启动容器后,tenant1.localhost:3001、tenant2.localhost:3001等地址都会指向同一个Vue app服务。
2. Vue.js提取子域名
在Vue应用中添加工具函数,从当前域名提取租户子域名,用于登录时传给后端:
// utils/tenant.js export function getTenantSubdomain() { const hostname = window.location.hostname; const parts = hostname.split('.'); // 处理本地环境:tenant1.localhost -> 返回tenant1 if (parts.length >= 2 && parts.at(-1) === 'localhost') { return parts[0]; } // 处理生产环境:tenant1.mybusiness.com -> 返回tenant1 if (parts.length >= 3) { return parts[0]; } return null; // 默认子域名或无租户场景 }
登录时将子域名作为参数传给后端API:
// 登录请求示例 async function login(credentials) { const subdomain = getTenantSubdomain(); const response = await axios.post('/api/login', { ...credentials, tenant_subdomain: subdomain }); // 处理令牌存储等逻辑 }
二、生产环境配置
1. Heroku部署
步骤1:配置通配符DNS
在域名服务商后台添加通配符CNAME记录:
- 类型:CNAME
- 主机记录:
* - 记录值:你的Heroku应用域名(如
yourapp.herokuapp.com)
步骤2:绑定通配符域名到Heroku
在Heroku应用设置的「Domains and certificates」中,添加通配符域名:*.mybusiness.com。
步骤3:配置Vue静态服务路由
使用serve包处理静态文件,确保所有子域名的路由请求都返回Vue入口文件:
- 安装依赖:
npm install -g serve - 修改
package.json启动脚本:"scripts": { "start": "serve -s dist -l $PORT" }
serve -s参数会让所有路径请求返回index.html,保障Vue路由和子域名识别逻辑正常运行。
2. Vercel部署
步骤1:配置通配符域名
在Vercel项目设置的「Domains」中添加通配符域名:*.mybusiness.com,并完成域名验证。
步骤2:配置路由规则
在项目根目录创建vercel.json,确保所有子域名请求都返回Vue入口文件:
{ "routes": [ { "handle": "filesystem" }, // 优先处理静态资源 { "src": "/.*", "dest": "/index.html" } // 所有其他请求返回index.html ] }
三、后端配合要点
CORS配置:在Laravel的
config/cors.php中允许所有子域名的跨域请求:'allowed_origins' => ['*.mybusiness.com', '*.localhost'],或动态判断请求来源,确保子域名请求能正常访问API。
租户识别:后端从请求的
Host头或前端传入的tenant_subdomain参数提取子域名,通过tenancy包完成租户切换和令牌发放。
内容的提问来源于stack exchange,提问作者peterxz

