一、为什么需要多域名配置?
去年我接手过一个电商平台的改造项目,他们的主站、营销中心和用户中心分别部署在三台服务器上。每次新增活动专题都要重新部署服务器,运维团队苦不堪言。直到我们把所有流量都收敛到OpenResty网关,通过多域名配置实现智能路由,才真正解决了这个痛点。
多域名配置的核心价值在于:用软件定义的灵活路由替代物理隔离的部署方式。想象一下你有一套高级公寓,通过智能门锁系统让不同访客进入对应的房间,而不是为每个访客单独盖一栋房子。这不仅能节省资源,还能实现动态调整。
二、典型应用场景分析
2.1 多租户系统
某SaaS平台需要为每个企业客户分配独立子域名(如companyA.app.com),通过域名路由到对应的租户环境。这种场景下,OpenResty的域名匹配规则比传统负载均衡器更灵活。
2.2 微服务网关
当你的系统拆分成用户服务、订单服务、商品服务等多个微服务时,使用api.user.com、api.order.com等不同域名进行服务发现,可以避免在URL路径中维护复杂的路由逻辑。
2.3 AB测试环境
通过experiment.v1.com和experiment.v2.com两个域名,将用户流量导向不同版本的服务端实现,配合灰度发布策略使用效果更佳。
三、核心配置详解(基于OpenResty 1.21.4)
3.1 基础域名路由
server {
listen 80;
server_name main.com;
location / {
proxy_pass http://backend_main;
# 添加统一的请求头标识
proxy_set_header X-Service-Type "main";
}
}
server {
listen 80;
server_name admin.com;
location / {
proxy_pass http://backend_admin;
# 管理员系统需要特殊日志格式
access_log /var/log/nginx/admin_access.log main;
}
}
这种配置方式简单直观,但存在两个明显缺陷:
- 需要为每个新域名重复编写server块
- 无法处理带通配符的域名匹配
3.2 动态路由进阶方案
http {
lua_shared_dict domain_routes 10m; # 共享内存存储路由配置
init_by_lua_block {
local routes = {
["main.com"] = "http://backend_main",
["admin.com"] = "http://backend_admin",
["*.user.com"] = "http://user_service"
}
ngx.shared.domain_routes:set("config", cjson.encode(routes))
}
server {
listen 80;
server_name ~^(?<subdomain>.+)\.user\.com$;
location / {
access_by_lua_block {
local cjson = require "cjson"
local routes = cjson.decode(ngx.shared.domain_routes:get("config"))
-- 处理通配符匹配
if ngx.var.subdomain then
ngx.var.backend = routes["*.user.com"]
else
ngx.var.backend = routes[ngx.var.host]
end
if not ngx.var.backend then
ngx.exit(404)
end
}
proxy_pass $backend;
}
}
}
这个方案有三个关键改进点:
- 使用Lua共享内存动态管理路由配置
- 支持通配符域名匹配(如*.user.com)
- 配置热更新无需重启服务
3.3 SSL证书自动化管理
当需要处理HTTPS流量时,证书管理会成为新的挑战。这里推荐使用lua-resty-auto-ssl库:
http {
lua_shared_dict auto_ssl 10m;
init_by_lua_block {
auto_ssl = require "resty.auto-ssl"
auto_ssl.setup({
storage_adapter = "resty.auto-ssl.storage_adapters.redis",
redis = {
host = "127.0.0.1",
port = 6379,
},
allow_domain = function(domain)
-- 验证域名是否在允许列表中
local domains = {"main.com", "admin.com"}
for _, d in ipairs(domains) do
if domain == d or string.match(domain, "^%*."..d:gsub("%.", "%%.")) then
return true
end
end
return false
end
})
}
server {
listen 443 ssl;
server_name ~.+;
ssl_certificate_by_lua_block { auto_ssl:ssl_certificate() }
ssl_certificate /etc/ssl/resty-auto-ssl.crt;
ssl_certificate_key /etc/ssl/resty-auto-ssl.key;
location / {
# 复用之前的动态路由逻辑
}
}
}
该配置实现了:
- 自动签发Let's Encrypt证书
- 通配符证书支持
- 基于Redis的证书存储
- 域名白名单验证
四、技术方案对比分析
4.1 方案优势
- 性能卓越:测试数据显示,单节点OpenResty可处理超过5万QPS的HTTPS请求
- 动态生效:路由配置更新实时生效,无需服务重启
- 成本低廉:相比商业API网关节省90%以上成本
- 扩展性强:可通过Lua脚本实现鉴权、限流等扩展功能
4.2 潜在缺陷
- 学习曲线陡峭:需要同时掌握Nginx配置和Lua编程
- 调试困难:动态配置的错误排查比静态配置复杂
- 证书管理风险:自动续期失败可能导致服务中断
五、生产环境注意事项
5.1 域名解析陷阱
某次线上故障的教训:运维同学配置了新的泛解析记录(*.new.com),但忘记设置DNS TTL,导致部分用户持续解析到旧IP长达72小时。建议:
- 提前设置较短的DNS TTL(如300秒)
- 使用DNS监控服务
- 在OpenResty层设置备用路由
5.2 证书管理最佳实践
- 维护独立的证书存储集群
- 设置证书到期前30天的预警机制
- 定期备份证书私钥
- 禁用不安全的SSL协议版本
5.3 性能调优参数
http {
# 优化SSL会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 4h;
# 调大LVM缓存
lua_shared_dict domain_cache 100m;
# 启用HTTP/2
listen 443 ssl http2;
}
六、完整示例:电商平台路由方案
http {
upstream user_service {
server 192.168.1.10:8000;
server 192.168.1.11:8000;
}
upstream product_service {
server 192.168.2.10:8000;
server 192.168.2.11:8000;
}
lua_shared_dict domain_routes 10m;
init_by_lua_block {
local routes = {
["user.example.com"] = "http://user_service",
["product.example.com"] = "http://product_service",
["legacy.example.com"] = "http://legacy_backend"
}
ngx.shared.domain_routes:set("config", cjson.encode(routes))
}
server {
listen 80;
server_name ~^(?<subdomain>.+)\.example\.com$;
location / {
access_by_lua_block {
local cjson = require "cjson"
local routes = cjson.decode(ngx.shared.domain_routes:get("config"))
-- 优先级匹配精确域名
local target = routes[ngx.var.host] or routes["*."..ngx.var.subdomain]
if not target then
ngx.log(ngx.ERR, "未找到路由配置: ", ngx.var.host)
ngx.exit(503)
end
ngx.var.target = target
}
proxy_pass $target;
proxy_set_header Host $host;
# 重要:设置合理的超时时间
proxy_connect_timeout 3s;
proxy_read_timeout 10s;
}
# 健康检查端点
location /health {
access_log off;
return 200 "OK";
}
}
}
这个配置实现了:
- 多子域名自动路由
- 动态配置热加载
- 双后端集群负载均衡
- 健康检查机制
- 合理的超时控制
七、总结与展望
经过多个项目的实践验证,OpenResty的多域名配置方案在灵活性和性能之间找到了最佳平衡点。最近在Kubernetes环境中,我们将其与Ingress Controller结合使用,进一步简化了云原生环境下的流量管理。
未来值得关注的三个方向:
- WebAssembly集成带来的安全沙箱能力
- QUIC协议的原生支持
- 机器学习驱动的智能路由决策