在实际部署中,服务器的公网IP往往只开放了80和443端口,但业务上可能需要同时运行官网、管理后台、API服务等多个站点。这时候最经济高效的做法,就是让nginx在同一个端口上监听,通过域名来区分不同的请求,再分发到各自的后端。这篇文章会从配置原理、具体写法、常见坑点三个方面,把nginx多域名共用端口的方案一次讲清楚。

一、核心原理:server_name如何区分同一端口的请求
nginx之所以能在同一个端口上服务多个域名,靠的是HTTP请求头中的Host字段。当一个请求到达nginx时,nginx会先根据监听的IP和端口找到对应的server块,然后拿请求中的Host头去匹配各个server块的server_name,匹配成功的server块负责处理这个请求。
如果所有server块都没有匹配上,nginx会使用一个默认server。默认server的规则是:同一组listen的IP端口组合中,第一个出现的server块就是默认server,除非某个server块显式声明了default_server参数。理解这一点非常重要,很多线上出现的奇怪跳转问题,根源都在默认server的处理上。
匹配优先级从高到低依次是:精确名称匹配、以星号开头的最长通配符、以星号结尾的最长通配符、正则表达式(按配置文件中的顺序)。例如ippipp.com会优先于*.ippipp.com被匹配,而*.ippipp.com又会优先于正则。配置多个域名时如果不清楚这个顺序,很容易出现请求进了错误的server块的诡异现象。
二、具体配置示例:三种常见写法
最基础的场景是两个域名指向同一个80端口,各自代理不同的后端服务。配置如下:
server {
listen 80;
server_name www.ipipp.com;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 80;
server_name api.ipipp.com;
location / {
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}注意每个server块的server_name可以写多个名称,用空格分隔,也可以指定别名。例如server_name ipipp.com www.ipipp.com;表示这两个域名都由这个server块处理。此外还可以用下划线_作为server_name来做一个兜底的默认server,把不认识的域名请求统一拦截或者返回403。
第二种写法是通配符和正则匹配,适合子域名较多的场景:
server {
listen 80;
server_name *.ipipp.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
# 正则匹配,以 ~ 开头
server {
listen 80;
server_name ~^(?<sub>[a-z0-9]+)\.ipipp\.com$;
location / {
# 可以用捕获的变量做动态转发
proxy_pass http://127.0.0.1:8090;
}
}第三种是https场景,多个域名共用443端口,每个域名挂各自的证书。nginx支持在同一个端口上配置多张证书,根据请求的SNI(Server Name Indication)自动选择对应的证书文件,只需要保证证书和server_name对应即可:
server {
listen 443 ssl;
server_name www.ipipp.com;
ssl_certificate /etc/nginx/ssl/www.pem;
ssl_certificate_key /etc/nginx/ssl/www.key;
location / {
proxy_pass http://127.0.0.1:8081;
}
}
server {
listen 443 ssl;
server_name api.ipipp.com;
ssl_certificate /etc/nginx/ssl/api.pem;
ssl_certificate_key /etc/nginx/ssl/api.key;
location / {
proxy_pass http://127.0.0.1:8082;
}
}三、注意事项与常见坑点排查
第一个坑是Host头丢失。使用proxy_pass转发到后端时,如果不加proxy_set_header Host $host;,后端拿到的Host可能是proxy_pass中写的地址,导致后端应用做域名校验或者生成跳转链接时出错。建议在模板里就固定写上这一行,同时加上X-Real-IP和X-Forwarded-For,方便后端获取真实客户端IP。
第二个坑是默认server被意外命中。有人会用IP直接访问服务器,或者别人把自己的域名解析到你的IP上,如果第一个server块恰好是官网,这些垃圾请求就会全部打到官网后端。推荐的做法是单独定义一个返回444或403的默认server,显式声明default_server,把无效请求直接断开:
server {
listen 80 default_server;
server_name _;
return 444; # 直接关闭连接,不返回任何内容
}第三个坑是证书配置问题。多域名共用443端口时,如果某个域名没有配置证书,握手阶段就会失败,浏览器报SSL错误。另外要注意,泛域名证书只能覆盖一级子域名,a.b.ipipp.com这类二级子域名不在*.ipipp.com的覆盖范围内。如果希望一个server块覆盖所有子域名,可以考虑把多个域名合并到一张多域名证书或者使用ACME自动签发。
第四个坑是配置生效和排查方法。修改配置后先执行nginx -t检查语法,再用nginx -s reload平滑加载。排查请求到底进了哪个server块,最直接的办法是查看/var/log/nginx/access.log,确认日志中的Host记录;也可以用curl -H "Host: api.ipipp.com" http://服务器IP/来模拟不同域名的请求,验证分发逻辑是否正确。最后别忘了DNS解析,所有域名都要添加A记录指向这台服务器的IP,否则配置写得再对也访问不到。
四、方案选择建议
如果域名数量少且后端各不相同,直接用多个server块加精确server_name,结构清晰、互不干扰,是最推荐的方案。如果子域名大量且后端逻辑一致,用通配符server_name配合变量做动态转发能减少配置重复。如果前后端分离且多个站点共用一套前端,也可以在一个server块内用不同的location路径区分,但要注意路径冲突和前端路由的base配置。
总体来说,多域名指向同一端口是nginx最经典的虚拟主机能力,只要理解了server_name的匹配规则、默认server的行为和Host头的传递机制,配置起来并不复杂。把上面提到的坑点提前规避,基本可以做到一次配置、长期稳定运行。
nginx多域名配置server_name反向代理修改时间:2026-09-02 02:16:32