
最近有好几个朋友在折腾 Linux 服务器的时候都卡在反向代理这一步。尤其是用了宝塔面板之后明明图形界面里点几下就能配好可一旦出了问题反而不知道从哪下手去排查。今天我把宝塔 Linux 面板下 Nginx 反向代理的完整配置方法、原理和踩坑记录整理出来给同样在配置 Nginx 反向代理的朋友做个参考。这篇内容适合两类人一是刚接触宝塔面板、想把某个端口上的服务用域名或公网 IP 访问的二是已经有基础但希望搞清楚 Nginx 配置里每个参数在干什么、遇到 502/504 时怎么定位问题的。如果你只是想抄一个能用的配置直接看第 3 节和第 4 节如果你想弄明白为什么要这么配那从第 1 节开始读会更顺。1. 先说清楚反向代理到底解决了什么问题1.1 反向代理是什么和正向代理有什么区别很多人第一次接触反向代理这个词会觉得抽象。我用大白话拆一下。正向代理是你作为客户端主动去借助一台服务器访问外部资源比如你请求某台服务器帮你把资料取回来你在外侧它在中间目的是隐藏你的身份。反向代理则完全反过来它站在真实服务器前面外部访客访问的是反代服务器反代服务器再决定把请求转给后面的哪台后端机器后端机器不直接暴露给访客。用生活里的场景来类比你去一家公司拜访前台先接待你问清你找谁之后再带你到对应的部门。这个前台干的事就是反向代理。访客只需要知道公司的入口地址不需要知道每个部门在哪个房间、哪条走廊甚至不需要知道这家公司有多少个部门。1.2 在宝塔里配置反向代理能解决什么问题宝塔面板里配反向代理本质上就是让 Nginx 前面接收 80/443 端口的请求再按规则转发到本机或内网其他机器上的某个端口。我实际项目里最常用到它的几个场景前后端分离项目前端 Vue 打包后的静态文件用 Nginx 托管接口请求以 /api 开头代理到本机 8080 端口的 Spring Boot 或 Node.js 服务。通过域名访问内网服务比如家里有群晖、路由器管理页或者某些只监听内网端口的服务用公网服务器做中转再代理出去。一个域名挂多个服务主站、博客、接口、文件存储分别用不同路径或不同子域名转发到对应端口互不干扰。隐藏后端端口后端服务不直接开在公网只允许本机或内网访问外部流量统一走 Nginx减少被扫描爆破的概率。2. 动手前的准备工作2.1 宝塔面板与 Nginx 的安装确认我碰到过不少朋友下载了安装命令直接跑结果系统软件源没更新导致 Nginx 编译的时候缺依赖。所以我的习惯是在安装面板之前先把系统更新一遍。CentOS 用 yum updateUbuntu/Debian 用 apt update apt upgrade这一步能避免大量后续问题。宝塔面板安装完成后终端会输出面板地址、默认用户名和密码。这里有一个我每次都要强调的细节登录后第一件事就是改掉默认密码然后把 8888 这个默认面板端口改掉。公网服务器上每天都有大量扫描器在试探常见端口和管理面板默认账号不改等同把自己家大门钥匙挂在门口。2.2 确认 Nginx 已安装并运行登录宝塔面板后左侧菜单找到网站。如果是全新安装它会提示你还没有创建站点同时会引导你到软件商店安装 Nginx。我一般会直接在软件商店搜Nginx并安装稳定版不建议一上来就装编译版或者带特殊模块的版本稳定优先。装完之后怎么确认它在运行我习惯直接开 SSH 执行systemctl status nginx看到 active (running) 字样说明正常。顺便还可以执行 nginx -v 看一下版本号后面排查某些兼容性问题时有用。2.3 准备一个测试用的后端服务配置反向代理之前最好先准备一个能返回内容的后端服务否则代理配好了一访问就 502你都不知道是 Nginx 的问题还是后端的问题。我测试时最常用的命令是python3 -m http.server 8080这条命令会在当前目录启动一个监听 8080 端口的静态文件服务器浏览器访问本机 IP 的 8080 端口能看到目录列表。此时再执行 curl 验证一次curl http://127.0.0.1:8080只要能看到 HTML 输出就说明这个后端服务是可用的。后面所有测试都以它为标准排错就清晰多了。3. 用宝塔图形界面完成一次反向代理配置3.1 添加站点在宝塔面板左侧点击网站然后添加站点。这里填写的域名就是访客将来要使用的地址。测试阶段可以直接填服务器公网 IP也可以填一个已解析到这台服务器的域名。需要注意一个问题如果你有多个服务要挂到同一个 Nginx 上就分别添加站点每个站点绑定不同域名或不同端口这样后面管理起来才不混乱。添加站点的时候会弹出一堆选项数据库类型、PHP 版本、FTP。如果你只是为了做反向代理数据库那一项直接选不创建就行PHP 版本也没什么用选纯静态即可。因为真正干活的不是 PHP而是 Nginx 的转发逻辑。3.2 添加反向代理规则站点创建完成后进入网站设置找到反向代理选项卡。开启反向代理功能然后点添加反向代理。这里只需要关心两个字段代理名称随便写但建议按实际用途命名比如 api-server、blog-backend方便多规则时区分。目标 URL后端服务的完整地址比如 http://127.0.0.1:8080。填好并保存之后宝塔会帮你在该站点的 Nginx 配置文件里自动加入一个 location 块。这时候打开浏览器访问你刚才绑定的域名或 IP如果能看到测试服务返回的目录列表就说明反向代理已经生效了。3.3 宝塔默认生成的参数含义很多人点完保存就开始用却不知道宝塔到底往配置文件里写了什么。我实际打开过生成的配置核心其实是这几行location / { proxy_pass http://127.0.0.1:8080; 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; }逐个解释一下proxy_pass这是反向代理的核心指令指定转发到哪个后端地址。Host $host把客户端原始请求里的 Host 头传给后端很多框架会依赖它做路由。X-Real-IP / X-Forwarded-For保存客户端真实 IP后端做日志和封禁时用到。X-Forwarded-Proto告诉后端客户端原本用的是 http 还是 https。这些是基础配置能覆盖大部分常规场景。但如果你要做 WebSocket 转发、调大上传限制、或者调整超时时间光靠图形界面是不够的必须手动改配置文件。4. 手写 Nginx 配置文件的进阶玩法4.1 配置文件在哪怎么改宝塔环境下的 Nginx 主配置在 /www/server/nginx/conf/nginx.conf一般不动它。站点级的配置在 /www/server/panel/vhost/nginx/ 目录下每个站点对应一个 .conf 文件。反向代理规则也差不多运行时会被 include 进站点配置。我习惯直接在 SSH 里用 vim 改文件改完先做一次语法检查再重载nginx -t nginx -s reload这个检查动作不能省。有人改配置时少写了一个分号直接重载结果 Nginx 起不来面板都跟着失联最后只能靠命令行一点点排查非常折腾。4.2 location 匹配与 proxy_pass 的斜杠陷阱这是反向代理里最容易踩的坑。同一个 location /api后面 proxy_pass 写不写斜杠效果截然不同。第一种写法不带斜杠location /api { proxy_pass http://127.0.0.1:8080; }访问 /api/user 时Nginx 会把完整路径转发给后端后端收到的是 /api/user。如果后端接口本身就带 /api 前缀用这种写法。第二种写法带斜杠location /api { proxy_pass http://127.0.0.1:8080/; }访问 /api/user 时Nginx 会把 location 匹配到的 /api 前缀替换掉转发给后端的是 /user。如果后端接口不带 /api而你希望通过 Nginx 做一层路径改写用这种写法。记忆方法就一条proxy_pass 后面带 URI哪怕只是个 /location 匹配部分就会被替换不带 URI就原样转发。4.3 一个完整的前后端分离部署示例假设前端 Vue 项目打包后放在了 /www/wwwroot/mysite/dist后端接口跑在 8080 端口完整的 Nginx 反向代理配置可以写成这样server { listen 80; server_name example.com; location / { root /www/wwwroot/mysite/dist; index index.html; try_files $uri $uri/ /index.html; } location ^~ /api/ { proxy_pass http://127.0.0.1:8080; 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; proxy_http_version 1.1; } }这个配置的关键点在于静态资源由 Nginx 直接托管不交给后端/api 开头的请求才转发给后端服务。Vue Router 如果开了 history 模式try_files 必须配好否则刷新子页面会返回 404。^~ 表示普通前缀匹配匹配到 /api/ 之后就不会再去看其他正则 location。4.4 WebSocket 与长连接场景配置如果后端服务是 WebSocket 协议比如你做了一个在线聊天、协同编辑、实时推送之类的功能反向代理配置必须多加两个头proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_read_timeout 3600s;很多人在实际项目中遇到 WebSocket 连接打开不到一分钟就自动断开八成就是少了 Upgrade 头或者 proxy_read_timeout 还是默认的 60 秒。WebSocket 是长连接模型60 秒内没有新消息就会被掐断所以必须把读取超时调大。还有大文件上传的场景。Nginx 默认对请求体大小有限制常见的报错是 413 Request Entity Too Large。解决办法是在 server 或 location 中加入client_max_body_size 50m;这个限制是 Nginx 在读取请求体时做的不加的话就算后端把限制调到很大请求也到不了后端。4.5 多个后端服务如何用 upstream 做负载均衡当一个服务部署了多个实例可以用 upstream 定义一组后端节点upstream backend { server 127.0.0.1:8080 weight1; server 127.0.0.1:8081 weight2; } server { listen 80; server_name api.example.com; location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }upstream 是 Nginx 原生的负载均衡方案默认轮询weight 参数可以控制流量权重。新增或下线后端节点时只需要改 upstream 列表然后重载不用动下层的 proxy_pass 逻辑扩展性很好。5. 常见问题排查实录5.1 反向代理最常见的 4 类错误速查表我把反向代理部署过程中最常见的问题整理成了表格方便你直接对照排查报错表现典型原因排查方向502 Bad Gateway后端服务没启动、端口错误或监听地址不对检查后端进程和监听端口确认代理目标地址正确504 Gateway Timeout后端处理超过 Nginx 默认超时时间调大 proxy_read_timeout / proxy_send_timeout413 Request Entity Too LargeNginx 请求体大小限制配置 client_max_body_size页面反复重定向Host 头或 X-Forwarded-Proto 没传对确认后端依赖哪些请求头补充 proxy_set_header5.2 502 Bad Gateway 的详细排查思路502 是反向代理里最常见的报错背后原因通常有两种。第一种后端服务确实没起来或者刚启动就崩了。先看进程还在不在ps aux | grep 你的服务名第二种端口或者监听地址不对。后端服务可能监听在 127.0.0.1:8080但你在代理里写的是 localhost:8080。在某些 Linux 发行版上localhost 会解析成 IPv6 的 ::1而后端服务只监听了 IPv4连接自然失败。所以我的建议是配置里统一写 127.0.0.1别写 localhost。排查 502 最直接的工具是看 Nginx 错误日志。日志位置一般在 /var/log/nginx/error.log宝塔环境下站点错误日志在 /www/wwwlogs/ 目录下。日志里如果出现 connect() failed (111: Connection refused)基本就是端口不通出现 upstream timed out 则是后端无响应。5.3 504 Gateway Timeout 的调整方法504 的意思是Nginx 已经把请求转发给后端但后端在规定时间内没有返回响应。默认的读取超时是 60 秒遇到一些耗时接口——报表导出、批量数据导入、调用第三方接口——非常容易触发。我的处理方案是在需要慢处理的 location 块里单独调大超时而不是改全局配置location /api/export { proxy_pass http://127.0.0.1:8080; proxy_connect_timeout 75s; proxy_read_timeout 300s; proxy_send_timeout 300s; }三个超时分别对应建立连接、读取响应、发送请求三个阶段。connect 75 秒基本够用read 和 send 按业务耗时调整。不过我也要提醒一句如果接口动不动就超过一两分钟与其无限调大超时不如考虑改成异步任务处理前端轮询或走 WebSocket 推送结果这才是更合理的架构方案。5.4 静态资源 404 或页面样式丢失代理配置完成后页面能打开但 CSS、JS、图片全部加载失败这是很多前端项目部署时都会遇到的。常见原因有两个方向。第一个方向是静态资源路径问题。前端打包后的资源引用如果用的是绝对路径 /assets/xxx而 Nginx 的 root 指令指向的目录不对资源自然找不到。同样一个 vue 项目dist 目录必须跟 location 里的 root 对应上。第二个方向是代理把静态资源请求也转发给了后端。这种情况只要单独加一个 location 处理静态资源就行不要让静态资源走 proxy_pass。我通常把静态资源和接口分开处理而不是一股脑全部代理到后端。5.5 配置 HTTPS 和自签名证书的注意事项现在的项目基本都要走 HTTPS。宝塔面板在网站设置里直接提供 SSL 证书配置界面可以申请免费的 Lets Encrypt 证书也可以自己上传证书文件。如果只是临时测试可以用 openssl 生成一个自签名证书openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/nginx/ssl/test.key \ -out /etc/nginx/ssl/test.crt然后在 Nginx 配置里加载listen 443 ssl; ssl_certificate /etc/nginx/ssl/test.crt; ssl_certificate_key /etc/nginx/ssl/test.key;需要注意用自签名证书访问时浏览器会提示不安全这是正常现象因为证书没有经过权威机构签发。正式环境一定要用受信任的证书否则用户一打开就弹警告信任度直接掉一半。5.6 WebSocket 连不上的补充排查除了上一条提到的 Upgrade 头缺失WebSocket 连不上还有一个容易被忽略的原因前端代码里使用的协议。如果你的站点是 HTTPS那 WebSocket 地址必须写 wss:// 而不能是 ws://否则浏览器会直接拦截。反过来在 Nginx 层必须开启 SSL 并正确加载证书。这一层层的协议一致性就像水管接口的型号一样每一段都得对齐有一处不对就通不了水。6. 配置文件里的几个实战心得6.1 推荐一个小而全的标准反向代理配置模板在多个项目里反复试过之后我把自己常用的一套反向代理配置整理成了模板。如果后端是常规 HTTP 服务我会用这样一套location /api/ { proxy_pass http://127.0.0.1:8080; 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; proxy_connect_timeout 75s; proxy_read_timeout 120s; proxy_send_timeout 120s; }这套配置我基本是复制粘贴用的。如果你要代理的是 WebSocket 服务在同一个 location 里加上 Upgrade 头和 Connection upgrade并把 read_timeout 调大到 3600s 就行。如果不需要额外的路径改写proxy_pass 里不要加末尾斜杠这是最容易踩又最容易忽略的细节。6.2 该用宝塔图形界面还是手写配置我的建议是功能简单的单地点转发用宝塔图形界面完全够用便捷且不容易写错但只要涉及路径改写、WebSocket、多级代理、复杂负载均衡就一定要手写配置。图形界面帮不了你解决为什么路径多了个前缀这样的问题它只会按照默认规则生成最小可用的内容。而手写配置的好处在于你亲手写下的每一行都有明确意图出了问题也能顺着自己写的逻辑一步步排查。很多运维高手并不是记性多好只是他们知道自己写的每个配置在干什么。6.3 关于 Host 头和 X-Forwarded-Proto 的实际体会我在实际项目中遇到过的登录状态反复失效问题最后定位到原因其实就是 Host 头不对。后端框架在生成认证 Cookie 时会根据请求的 Host 判断作用域。如果 Nginx 没有把正确的 Host 传下去后端生成 Cookie 的 domain 跟浏览器地址栏里的域名不一致Cookie 就会一直被浏览器丢弃。同样的道理X-Forwarded-Proto 如果没配好后端拿到请求后无法判断客户端用的是 http 还是 https生成的重定向地址就可能从 https 跳到 http导致页面又陷入循环重定向。这两个头看似不起眼却是很多诡异问题的根源。最后提醒一下所有刚上手宝塔面板的朋友每次改完配置先在命令行执行 nginx -t 确认语法再执行 nginx -s reload 重载不要直接重启 Nginx。Nginx 重载是平滑的不会中断现有连接而重启可能造成短暂的请求失败。养成先检查、再重载的习惯能让你在服务器运维这条路上少踩很多坑。