nginx 域名路由转发最稳:基于 $host 精确匹配 server_name,proxy_pass 明确后端,proxy_set_header host $host 和 x-forwarded-host $host 必设;应用层校验白名单内 x-forwarded-host;数据库按域名独立实例或用户隔离;https 需 sni 与多域名证书对齐。
用 nginx 做域名路由转发最直接
不需要改应用代码,也不用在数据库层做映射,把路由逻辑压到反向代理层是最稳的方案。核心是让 nginx 根据 $host 变量把请求分发到不同后端服务,每个后端连自己的数据库实例。
- 配置里必须用
server_name明确声明每个域名,不能靠通配符模糊匹配(否则 HTTPS SNI 或日志排查会出问题) - 每个
location块里用proxy_pass指向对应服务器的 IP+端口,别漏写斜杠(http://10.0.1.5:8000/和http://10.0.1.5:8000转发路径行为不同) - 务必加
proxy_set_header Host $host;,否则某些框架(如 Django、Flask)生成绝对 URL 时会错用代理地址
Node.js / Python 后端里读取原始 Host 头做数据库切换
如果必须由应用层控制数据库连接(比如共用一套代码部署多个租户),就得在启动时或请求中动态选库。关键不是“识别域名”,而是“信任且只信任 X-Forwarded-Host 或 Host”——前提是 Nginx 已设好可信来源。
- Node.js 用
req.headers['x-forwarded-host'] || req.headers.host,但得先在 Nginx 里加proxy_set_header X-Forwarded-Host $host; - Python Flask 中避免直接用
request.host,它可能被伪造;应校验request.headers.get('X-Forwarded-Host')是否在白名单里(如['a.example.com', 'b.example.com']) - 数据库连接池不能全局复用:每个域名对应的
db_config必须独立初始化,否则连接混用会导致数据错乱
MySQL 不支持按域名自动路由,别碰 init_connect 或触发器
有人想在 MySQL 层做“根据客户端 IP 或用户变量切库”,这条路走不通。MySQL 没有请求级上下文感知能力,init_connect 是会话级的,且无法读取 HTTP 头;触发器和存储过程更没法接触网络层信息。
-
init_connect只能执行固定 SQL,不能做条件判断,也不能访问外部变量 - 试图用
USER()或CURRENT_USER()区分租户?它们返回的是认证账号,不是访问域名 - 如果硬要 DB 层隔离,唯一可行的是为每个域名配独立 MySQL 用户 + 独立数据库名,并在应用里严格绑定,而不是指望 MySQL 自动识别
HTTPS 下 SNI 和证书配置容易漏掉多域名支持
一个 IP 绑多个域名,HTTPS 必须靠 SNI,而 Nginx 默认支持,但证书配置稍不注意就会 502 或证书警告。
- 每个
server块必须单独配ssl_certificate和ssl_certificate_key,不能共用同一组文件(除非是泛域名证书且覆盖所有域名) - 用 Let’s Encrypt 的
certbot申请多域名证书时,命令要带多个-d:certbot certonly --nginx -d a.example.com -d b.example.com - 测试时用
curl -v https://a.example.com看* Server certificate:部分是否匹配预期域名,别只看页面能不能打开
真正麻烦的从来不是怎么写路由规则,而是所有环节都得对齐“这个请求到底属于谁”——Nginx 要传、后端要验、数据库要隔离、证书要覆盖,漏一环,就变成看似正常实则数据串了。










