资讯动态

Nginx双端口代理配置实战:一台服务器同时运行两个独立网站

发布时间:2026/10/15 2:24:32 来源:尧图企业网站定制
1. 从一个真实需求说起为什么要在同一台机器上跑两个网站很多人第一次接触 Nginx都是从装完、改个配置、能访问开始的。但真正到了实际场景里最常撞上的问题不是怎么装而是我手上有两个完全不同的站点但只有一台服务器、一个公网入口怎么让它们互不打架。这个需求听起来简单实际拆开来看涉及的东西一点都不少端口怎么分配、请求怎么区分、静态资源和后端服务怎么各自独立、日志怎么分开排查、配置写在哪一层才不会互相污染。我见过太多人一开始图省事把两个站点的配置全塞进一个server块里用if判断路径来分流结果上线没两天就出现资源串台、缓存互相覆盖、日志混在一起根本没法定位问题。所以这篇内容我想用一个最朴素的实验场景把双端口代理不同网站这件事从头到尾讲透。所谓双端口就是让 Nginx 同时监听两个不同的端口比如 8081 和 8082访问 8081 走 A 站点访问 8082 走 B 站点两个站点在配置层面完全隔离互不干扰。这个实验麻雀虽小但把 Nginx 里最核心的几个概念——server块、listen指令、location匹配、root与proxy_pass的区别、日志分离——全都串了一遍。适合谁来读如果你是刚学 Nginx、只会改默认配置的新手这篇能帮你建立一个 server 块就是一个独立站点的正确心智模型如果你已经用过 Nginx 但总是靠复制粘贴配置这篇能帮你搞清楚每一行到底在干什么出问题该往哪查。下面我按实际动手的顺序一步步拆。2. 实验整体设计与思路拆解2.1 为什么选双端口而不是双域名分流两个网站常见做法有三种一是用不同域名靠server_name区分二是用不同路径前缀靠location区分三是用不同端口靠listen区分。这三种没有绝对优劣关键看场景。用域名区分最正规但前提是你得有域名解析权限本地实验还得改 hosts 文件多一层心智负担。用路径区分最省事但两个站点的资源路径会互相干扰比如 A 站的/static和 B 站的/static会撞车而且很多前端项目默认从根路径加载资源改路径前缀要动构建配置很麻烦。双端口的优势在于隔离最彻底配置最直观实验成本最低。每个端口对应一个独立的server块两个站点在 Nginx 眼里就是两个毫不相干的虚拟主机root目录、日志文件、代理目标全都可以各管各的。本地做实验时浏览器直接输localhost:8081和localhost:8082就能切换不需要动任何系统配置。这也是我推荐新手从这个方式入手的原因——先把一个 server 块 一个站点这个模型刻进脑子里后面再学域名分流就是水到渠成。2.2 两个站点的角色设计为了让实验覆盖更全我特意让两个站点走不同的技术路线而不是两个都做静态页。这样能顺带把 Nginx 两种最典型的用法都练到站点 A端口 8081纯静态站点用root指令直接指向一个本地目录Nginx 自己把文件读出来返回。这对应的是官网、文档站、前端打包产物这类场景。站点 B端口 8082反向代理站点用proxy_pass把请求转发给一个跑在本地其他端口的后端服务。这对应的是 API 服务、动态应用这类场景。这么设计的好处是你能在同一份配置里同时看到root和proxy_pass的写法差异理解Nginx 自己处理和Nginx 只做转发这两种模式的本质区别。很多人分不清这两个指令其实一句话root是 Nginx 亲自去磁盘找文件proxy_pass是 Nginx 把请求原样丢给后面的服务自己只当中间人。2.3 端口选择的讲究端口不是随便挑的。1024 以下是系统保留端口普通用户没权限监听所以实验一律用 1024 以上。8081、8082 这类 8 字头端口是社区约定俗成的备用 HTTP 端口不容易和系统服务冲突。要避开的是 3306数据库、6379缓存、27017 这类常见服务的默认端口免得以后装东西时打架。另外提醒一句选端口前最好确认一下没被占用。Linux 下用ss -tlnp | grep 8081macOS 下用lsof -i :8081Windows 下用netstat -ano | findstr 8081。这个习惯能帮你省掉后面启动报错 address already in use的排查时间。3. 环境准备与基础配置落地3.1 安装与目录规划Nginx 的安装各平台差异不大包管理器一把梭就行。Ubuntu/Debian 系用apt install nginxCentOS/RHEL 系用yum install nginxmacOS 用brew install nginx。装完之后先别急着改配置跑一下nginx -v确认版本再跑nginx -t确认默认配置没语法错误这是排查问题的基线。目录规划这块我强烈建议不要把所有站点文件都堆在默认的/usr/share/nginx/html里。默认目录是给欢迎页用的你往里塞业务文件时间一长自己都分不清哪个是哪个。我的习惯是单独建一个实验根目录比如/data/www/下面按站点分子目录sudo mkdir -p /data/www/site-a sudo mkdir -p /data/www/site-b站点 A 是静态站直接往/data/www/site-a里放一个index.html就行。站点 B 是代理站本身不需要放文件但为了实验完整我会在本地起一个简单的后端服务来当被代理对象。3.2 配置文件该放哪sites-available 还是 conf.d这是新手最容易迷糊的地方。Nginx 主配置nginx.conf里通常有一行include把某个目录下的所有.conf文件都加载进来。不同发行版这个目录不一样Debian/Ubuntu 系习惯用/etc/nginx/sites-available/存配置、sites-enabled/放软链接CentOS 系习惯直接用/etc/nginx/conf.d/。我的建议是实验阶段直接用conf.d目录一个站点一个文件。比如建site-a.conf和site-b.conf各自独立。这样做的好处是改 A 站不会误伤 B 站删掉某个文件就等于下线某个站点管理起来清清爽爽。Debian 系如果默认没有conf.d可以在nginx.conf的http块里手动加一行include /etc/nginx/conf.d/*.conf;。注意改配置前先备份原文件cp nginx.conf nginx.conf.bak。我踩过的坑是改错了include路径导致整个 Nginx 起不来有备份能秒回滚。3.3 站点 A 的静态配置站点 A 的配置非常短但每一行都值得说清楚server { listen 8081; server_name localhost; root /data/www/site-a; index index.html; access_log /var/log/nginx/site-a.access.log; error_log /var/log/nginx/site-a.error.log; location / { try_files $uri $uri/ 404; } }listen 8081是核心它决定了这个 server 块只响应 8081 端口的请求。root指定文件根目录index指定默认首页。try_files $uri $uri/ 404这行是精髓它按顺序尝试请求的原始路径 → 当作目录再找一次 → 都没有就返回 404比单纯用root更严谨能避免一些路径穿越的意外行为。日志分离是我特别想强调的一点。默认情况下所有站点日志都写进同一个access.log两个站点的请求混在一起排查问题时根本分不清哪条是哪个站的。给每个站点单独指定日志文件是专业配置的基本素养。3.4 站点 B 的代理配置与后端准备站点 B 需要一个后端服务。为了不引入额外依赖我用 Python 自带的 HTTP 服务来模拟一条命令就能起cd /data/www/site-b python3 -m http.server 9001这条命令会在 9001 端口起一个静态文件服务我们就把它当作后端应用。然后 Nginx 这边配置成代理server { listen 8082; server_name localhost; access_log /var/log/nginx/site-b.access.log; error_log /var/log/nginx/site-b.error.log; location / { proxy_pass http://127.0.0.1:9001; 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_pass指向后端地址后面三行proxy_set_header是把客户端的真实信息透传给后端。很多人代理配完发现后端拿到的 IP 全是127.0.0.1就是因为漏了这几行。X-Real-IP传真实客户端 IPX-Forwarded-For传代理链路上的 IP 列表Host传原始请求的域名。这三件套几乎是反向代理的标配。4. 核心细节解析与实操要点4.1 listen 指令背后的匹配逻辑listen不只是监听哪个端口这么简单它其实定义了 Nginx 的请求分发规则。当请求进来时Nginx 先按IP 端口找到对应的监听套接字再在这个套接字下按server_name匹配具体的 server 块。如果两个 server 块监听了同一个端口但server_name不同Nginx 会按名字精确匹配如果名字都匹配不上就落到该端口下的默认 server第一个定义的或者显式标了default_server的那个。我们这个实验里两个 server 监听不同端口所以匹配逻辑退化成最简单的端口对端口不存在歧义。但理解上面这套机制很重要因为一旦你以后要在一个端口上挂多个域名靠的就是server_name的匹配顺序。有个细节listen 8081等价于listen *:8081也就是监听所有网卡的 8081。如果你只想监听本机可以写listen 127.0.0.1:8081这样外部访问不进来安全性更高。实验环境无所谓生产环境要按需收紧。4.2 root 与 alias 的区别别用错讲静态站点就绕不开root和alias这对容易混淆的指令。它们的区别在于路径拼接方式root /data/www/site-a;配合location /img/访问/img/a.png时Nginx 找的是/data/www/site-a/img/a.png也就是root 路径 完整请求路径。alias /data/www/images/;配合location /img/访问/img/a.png时Nginx 找的是/data/www/images/a.png也就是alias 路径替换掉 location 匹配的部分。一句话记忆root是在根目录后面接上请求路径alias是用别名目录替换掉匹配前缀。用错了的典型症状就是 404而且路径看起来就差一层目录。我建议新手实验阶段统一用root等真正需要把某个 URL 前缀映射到完全不同的目录时再上alias。4.3 proxy_pass 结尾带不带斜杠差别巨大这是反向代理里最经典的坑没有之一。proxy_pass的 URL 结尾有没有/行为完全不同配置写法location请求路径转发到后端的路径proxy_pass http://127.0.0.1:9001;/api//api/user/api/userproxy_pass http://127.0.0.1:9001/;/api//api/user/user规律是结尾不带斜杠原始路径原样透传结尾带斜杠location 匹配到的前缀会被替换掉。这个差异导致过无数本地好好的一上代理就 404的事故。我的经验是如果后端服务的路由和前端请求路径一致就不带斜杠如果后端服务是独立部署、路由里没有那个前缀就带斜杠把它剥掉。实验里我用的location /匹配根路径带不带斜杠效果一样但你必须知道这个区别否则换个 location 就翻车。4.4 日志格式与排查字段默认的combined日志格式包含客户端 IP、时间、请求行、状态码、响应大小、Referer、User-Agent够用但不够细。做代理实验时我建议自定义一个格式把上游响应时间和上游地址也带上log_format proxy_debug $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent upstream$upstream_addr upstream_time$upstream_response_time request_time$request_time;$upstream_addr告诉你请求最终打到了哪个后端$upstream_response_time是后端处理耗时$request_time是 Nginx 视角的总耗时。这两个时间一对比就能判断慢是慢在后端还是慢在 Nginx 本身。这个技巧在排查性能问题时特别有用属于配一次受益很久的投入。5. 完整实操流程与验证5.1 从零到跑通的完整步骤把前面的碎片拼起来完整流程是这样的确认环境nginx -v看版本nginx -t看默认配置是否正常。建目录放文件mkdir -p /data/www/site-a /data/www/site-b往 site-a 放一个index.html内容随便写点能区分的东西比如标题写我是站点 A。起后端服务cd /data/www/site-b python3 -m http.server 9001 同样放个index.html写我是站点 B 的后端。写两个配置文件按前面的模板把site-a.conf和site-b.conf放进conf.d目录。检查语法nginx -t这一步必须过报错会直接告诉你哪个文件哪一行有问题。重载配置nginx -s reload注意是 reload 不是 restartreload 是平滑重载不断连接。验证浏览器开localhost:8081和localhost:8082应该分别看到两个不同的页面。5.2 用命令行验证别只信浏览器浏览器有缓存有时候你改了配置它还是显示旧的容易误判。我习惯用curl做验证干净利落curl -I http://localhost:8081 curl -I http://localhost:8082-I只取响应头看HTTP/1.1 200 OK和Server: nginx就够了。想看得更细加-v看完整交互。如果 8081 返回 200 而 8082 返回 502那基本就是后端服务没起来或者proxy_pass地址写错了502 是 Nginx 连不上后端的典型信号。再进一步可以验证两个站点的隔离性故意把 site-a 的index.html删掉访问 8081 应该 404而 8082 完全不受影响。这个测试能直观证明两个 server 块互不干扰比看配置文档印象深得多。5.3 参数计算连接数与超时怎么定实验阶段用默认值就行但既然讲到了顺手把两个关键参数的算法说清楚以后上生产心里有数。worker_connections单个 worker 进程能同时处理的最大连接数。理论最大并发 worker_processes × worker_connections。但注意反向代理场景下Nginx 既要接客户端连接又要连后端一个请求占两条连接所以实际能扛的并发要除以 2。比如worker_processes 4、worker_connections 1024理论 4096 条连接代理场景下大约能扛 2000 个并发请求。proxy_read_timeoutNginx 等待后端响应的超时时间默认 60 秒。如果后端处理慢比如跑报表要 2 分钟就得把这个值调大否则 Nginx 会提前断开报 504。设置原则是略大于后端 P99 响应时间别盲目调成很大否则后端真挂了Nginx 会一直傻等白白占着连接。6. 常见问题与排查技巧实录6.1 高频问题速查表现象最可能的原因排查方向8081 访问 404root 路径写错或文件不存在检查root指向的目录和文件权限8082 返回 502后端没起或地址端口错curl直连后端端口验证8082 返回 504后端响应超时看proxy_read_timeout和后端日志改了配置没生效忘了 reload 或改错文件nginx -t确认nginx -s reload启动报端口占用端口被别的进程占了ss -tlnp找到占用进程后端拿不到真实 IP漏了 proxy_set_header补上 X-Real-IP 等头静态资源 403目录权限不足检查 Nginx 运行用户对目录的读权限6.2 三个我踩过的坑坑一reload 之后配置没变。有次我改完配置nginx -s reload刷新页面还是老样子。折腾半天才发现我改的是sites-available里的文件但sites-enabled里的软链接指向的是另一个同名文件。教训是改配置前先确认nginx -T大写 T输出的到底是哪份配置它会打印所有生效的配置和来源文件路径一目了然。坑二代理后静态资源全 404。前端页面能打开但 CSS、JS 全挂。原因是页面里写的是绝对路径/static/xxx.js而我的location /api/只代理了 API 前缀静态资源请求打到了 Nginx 本地本地又没有这些文件。解决办法要么给静态资源也配代理要么让前端用相对路径。这个坑的本质是没搞清楚哪些请求该走代理、哪些该走本地。坑三日志文件权限报错。自定义日志路径后 Nginx 起不来报Permission denied。原因是 Nginx 的 worker 进程以www-data或nginx用户运行而我建的日志目录属主是 root。解决方法是把日志目录属主改成 Nginx 运行用户或者干脆把日志放在 Nginx 有权限的默认目录下。查 Nginx 运行用户看nginx.conf里的user指令。6.3 一个实用的排查顺序遇到问题别乱试按这个顺序走90% 的情况能定位nginx -t看语法配置都过不了就别谈别的。nginx -T看生效配置确认你改的和你以为的一致。curl -I看状态码200/404/502/504 各自指向不同方向。看对应站点的error.logNginx 的报错信息其实很直白。代理问题再curl直连后端确认后端本身是好的。这个顺序的核心逻辑是从外到内、从配置到服务先排除配置层的问题再往服务层查能避免在错误的方向上浪费时间。7. 配置优化与后续扩展方向7.1 让配置更健壮的两个小改动实验跑通之后可以加两个小优化让配置更专业。一是给静态资源加缓存头减少重复请求location ~* \.(css|js|png|jpg|jpeg|gif|ico)$ { expires 7d; add_header Cache-Control public; }二是给代理加一个健康检查的兜底后端挂了返回一个友好的错误页而不是干巴巴的 502error_page 502 503 504 /50x.html; location /50x.html { root /data/www/errors; }这两个改动都不大但体现的是配置不只是能跑还要跑得稳的思路。7.2 从双端口到多站点管理双端口实验的真正价值是帮你建立起一个 server 块就是一个独立站点的模型。等你以后站点多了这套思路可以直接扩展每个站点一个.conf文件统一放在conf.d下用include批量加载。想下线某个站删文件 reload 即可想加新站复制模板改端口和路径即可。这种配置即站点的组织方式比把所有东西塞进一个大文件里可维护性高太多。再往后你可以把端口分流升级成域名分流把listen 8081换成server_name a.example.com其余结构几乎不用动。也可以引入 upstream 做后端负载均衡把单个proxy_pass地址换成一个后端组。这些进阶玩法的地基都是今天这个双端口实验打下的。我个人在实际操作中的体会是Nginx 这东西看着配置项多但核心就那么几个概念server 块管站点、location 管路径、root 管静态、proxy_pass 管转发、log 管排查。把这五个吃透剩下的一大堆指令都是在这五个基础上的微调。双端口代理这个实验之所以值得反复做就是因为它用最小的场景把这五个概念全串了一遍做完一遍你对 Nginx 的理解会比看十篇教程都扎实。最后再分享一个小习惯每次改完配置别急着关终端先nginx -t再reload然后curl验证一遍这三步养成肌肉记忆能帮你挡掉绝大多数低级失误。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑