Nginx反向代理多个域名怎么设置

文章导读
多个域名指向同一台机器、由同一个 Nginx 接流量时,设置方式是给每个域名一个 server 块,用 server_name 精确匹配请求头里的 Host,各自 proxy_pass 到对应后端。80/443 端口只监听一次,靠域名分流,不靠端口分流。动手前先确认两件事:这些域名的 DNS 已指向这台机器,且每个 server_name 在本机配置里只出现一次。
📋 目录
  1. Ⅰ 反向代理多个域名:先把能核对的事实摆清楚
  2. Ⅱ 反向代理多个域名最容易搞错的一点
  3. Ⅲ 反向代理多个域名:一个照着就能做完的做法
  4. Ⅳ 反向代理多个域名:怎么验证结果对不对
A A

多个域名指向同一台机器、由同一个 Nginx 接流量时,设置方式是给每个域名一个 server 块,用 server_name 精确匹配请求头里的 Host,各自 proxy_pass 到对应后端。80/443 端口只监听一次,靠域名分流,不靠端口分流。动手前先确认两件事:这些域名的 DNS 已指向这台机器,且每个 server_name 在本机配置里只出现一次。

判断方向:多域名反向代理靠 server 块加 server_name 匹配,不是把多个 proxy_pass 堆进一个 server 里。适用场景是域名都解析到同一 IP、共用 80/443。操作前先 nginx -T 确认没有重复 server_name、没有意外的 default_server;改完 nginx -t 通过再 reload。验证用 curl 带 Host 头打 127.0.0.1,看落到哪个后端。风险边界:server_name 写错或漏配会静默落到 default_server,返回别的站点内容且不报错。

反向代理多个域名:先把能核对的事实摆清楚

先把手头能核对的东西列出来,再谈配置怎么写。

  • 对象:同一台 Nginx 上要接的域名(如 a.example.com、b.example.com)、每个域名对应的后端地址和端口、配置文件位置。位置不要靠猜,用 nginx -V 2>&1 | tr ' ' '\n' | grep conf-path 看 --conf-path,再看 nginx.conf 里 include 指向哪个目录,Debian/Ubuntu 常见 sites-enabled,RHEL 系和容器镜像常见 conf.d。
  • 前提:域名解析已指向本机地址,80 或 443 端口在防火墙与安全组放通,后端服务在本机或内网可达并正在监听。
  • 可核对的现象:nginx -T 打印合并后的完整配置;nginx -t 给出语法检查结果;/var/log/nginx/access.log 与 /var/log/nginx/error.log 记录请求和错误;curl 带 Host 头请求 127.0.0.1 能看到实际由哪个后端响应。默认 combined 日志格式里没有 $host,想按域名分日志得自己定义 log_format,这一条很容易被忽略。

这几项都在手上再往下走:能打印当前配置、能改文件、能 reload、能看到日志。少一样就先补,不要靠试。

反向代理多个域名最容易搞错的一点

最常见的误解是把多个域名的 proxy_pass 写进同一个 server 块,或者以为 listen 80 后面并列写几个 server_name 就能自动分流。Nginx 的分流依据是请求头 Host 与 server_name 的匹配结果,一个 server 块只有一组 location 和 proxy_pass,装不下两套互不相同的后端。

判断分界在这里:Host 精确匹配到哪个 server_name,就走哪个 server 块;一个都没匹配上,就走标了 default_server 的那个 listen(没标则走该端口上第一个 server 块),而且整个过程不报错、日志里也看不出异常。

能把两种情况区分开的检查动作:

Nginx反向代理多个域名怎么设置
curl -I -H "Host: b.example.com" http://127.0.0.1/
nginx -T | grep -n "server_name\|listen"

返回的是 a 站点页面或 a 后端特有的响应头,说明 b.example.com 没匹配上、落到了 default_server;返回 b 后端的内容,说明 server_name 生效。这个动作比盯着配置文件一行行看更快得出判断。

反向代理多个域名:一个照着就能做完的做法

按下面顺序做,每步都写了该看到什么。

  1. 确认配置入口并备份:
    nginx -V 2>&1 | tr ' ' '\n' | grep conf-path
    ls /etc/nginx/conf.d/ /etc/nginx/sites-enabled/ 2>/dev/null
    cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
    该看到 --conf-path 指向的 nginx.conf,以及 include 引入的目录。
  2. 新建一个独立文件,两个域名写两份 server 块:
    # /etc/nginx/conf.d/multi-domain.conf
    log_format by_host '$host $remote_addr [$time_local] "$request" $status';
    
    upstream app_a { server 127.0.0.1:8081; }
    upstream app_b { server 127.0.0.1:8082; }
    
    server {
        listen 80;
        server_name a.example.com;
        access_log /var/log/nginx/a.access.log by_host;
    
        location / {
            proxy_pass http://app_a;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            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;
        }
    }
    
    server {
        listen 80;
        server_name b.example.com;
        access_log /var/log/nginx/b.access.log by_host;
    
        location / {
            proxy_pass http://app_b;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            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;
        }
    }
    替换项只有域名、后端地址端口、日志路径。log_format 只能定义在 http 块,conf.d 里的文件通常已被 include 进 http 块;若报 duplicate log_format,说明已有同名定义,换个名字即可。除非确实想要一个兜底站点,否则不要在别的 server 块里补 listen 80 default_server。
  3. 检查再生效:
    nginx -t
    nginx -s reload
    nginx -t 该看到 syntax is ok 和 test is successful;reload 没有输出一般就是接受了。有报错就别 reload,按提示的文件行号改。
  4. 要走 HTTPS 的域名各自配证书:443 的 server 块同样按域名分开写,每个 server 块里的 ssl_certificate 和 ssl_certificate_key 指向该域名自己的证书,不要一份证书套所有域名。HTTP/2 的写法随版本不同,先用 nginx -v 确认版本,再决定是 listen 443 ssl; 加 http2 on; 还是旧写法 listen 443 ssl http2;。

反向代理多个域名:怎么验证结果对不对

分三层验,别只看浏览器能不能打开。

  • 配置层:nginx -T | grep -n "server_name",每个域名应只出现一次,且没有两个 server 块抢同一个 server_name。
  • 路由层:
    curl -I -H "Host: a.example.com" http://127.0.0.1/
    curl -I -H "Host: b.example.com" http://127.0.0.1/
    curl -s -o /dev/null -w '%{http_code}\n' -H "Host: b.example.com" http://127.0.0.1/some-path
    正常结果:两次响应能看出不同后端的特征,比如不同的自定义响应头、不同页面标题或不同的跳转地址,状态码是后端真实返回的,不是 502 或 504。出现 502 说明 server_name 匹配对了但后端连不上,去 error.log 找 connect() failed 那行。
  • 日志层:tail -f /var/log/nginx/a.access.log,另一台机器正常访问 a.example.com,该看到首列 $host 是 a.example.com;访问 b.example.com 时只应写进 b.access.log。两个域名的请求混进同一个文件,就是没匹配上,或日志指令写在了被继承的层级。

最后从外部再验一次:curl -I http://a.example.com 与 curl -I http://b.example.com,结果应与本机带 Host 头一致。不一致时先 dig +short a.example.com 看解析是否已生效,DNS 没切换时请求根本到不了这台机器,此时改配置是白费功夫。