ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Nginx反向代理配置详解:从宝塔面板到服务器部署避坑指南

Nginx反向代理配置详解:从宝塔面板到服务器部署避坑指南 很多人第一次接触服务器部署都是从“一个网站一个端口”开始的。等到服务多起来就发现一台Linux服务器上可能同时跑着博客、接口服务、管理后台每个服务各占一个端口访问地址又长又难记证书也得一个个配。其实只要在Nginx这一层做好反向代理这些零散的服务就能统一收到80和443端口上按域名和路径分发给后端不同的进程。用宝塔Linux面板来操作很多步骤可以不碰命令行但如果只会在界面里点保存不懂背后生成的是什么出了问题照样两眼一抹黑。我这两年维护服务器的习惯是所有外部流量都从Nginx进后端服务只监听内网地址对外只开必要的端口。这套玩法稳定省心而且无论你是用宝塔还是纯命令行原理都一样。下面我从方案选型、核心参数、实际操作到故障排查把Nginx反向代理的配置方法完整过一遍。1. 为什么要做反向代理场景、原理与选型1.1 一个前台接待员就说清了反向代理和正向代理的区别反向代理听起来很玄用公司前台来类比就特别清楚。访客到公司不用知道技术部张工坐在哪个工位、分机是多少只需要告诉前台“我要找技术部张工”前台负责联系并把人带到对应位置。对访客来说公司就是你面对的唯一入口内部怎么分工和你无关。Nginx反向代理就是这个前台它接收所有外部请求再根据域名、路径、端口等条件把请求转发给后面的具体服务。与之对应的正向代理角色相反它代表客户端去访问目标服务。客户端告诉代理“我要访问某某地址”代理帮你发起请求再把结果带回来目标服务并不知道真正访问的是谁。所以两者的核心区别在于正向代理隐藏的是客户端反向代理隐藏的是服务端。从部署位置看正向代理通常部署在客户端一侧反向代理部署在服务端一侧。对比项正向代理反向代理使用方客户端服务端隐藏对象隐藏客户端身份隐藏后端服务典型角色客户端的出口服务端的统一入口部署位置客户端侧服务端侧对于一台服务器上跑着多个服务的情况反向代理解决的不是“能不能访问”的问题而是“如何统一、安全、规范地暴露服务”的问题。具体体现在这几点第一统一入口无论后面是Java、Node还是Python进程对外都走同一个域名第二统一证书HTTPS证书只需要在Nginx这一层维护不需要每个后端服务单独配置第三隐藏结构外部访问者看到的只有Nginx后端端口、地址、技术栈都不暴露第四顺便可以做负载均衡同一个后端服务起多个实例时用upstream就能按权重分发。1.2 哪些场景要用反向代理方案怎么选我实际遇到需要使用反向代理的场景基本就这几类服务器上部署了多个Web服务比如一个博客、一个Python应用、一个监控面板每个都想用独立域名访问。前后端分离项目前端是Vue/React打包出来的纯静态文件后端是Spring Boot、Node或Flask接口需要让两者同源、避免跨域。后端服务没有独立域名只想通过主站下的某个路径转发比如 example.com/api/ 转到 127.0.0.1:8080。对内网服务做统一HTTPS入口或者多个后端实例需要负载均衡。也有不需要反向代理的情况。比如你只有一个纯静态站点那Nginx直接托管文件就行没必要在上面再套一层转发。再比如服务本身对延迟和带宽极其敏感虽然Nginx转发开销非常小但多一跳总归多一层这种场景就要慎重。方案选型上主流的无非Nginx、Apache、Caddy。宝塔Linux面板默认支持的就是Nginx这也是我用得最顺手的方案。Nginx的优点在于稳定、并发能力强、配置成熟社区资料多Apache规则也丰富但同样的场景配置起来更啰嗦Caddy最大的亮点是自动申请和续期HTTPS证书配置非常简洁适合小项目只是生态里很多老教程和插件都围绕Nginx出了问题不好找参考。所以我的建议是老老实实把Nginx搞明白一劳永逸。宝塔面板的价值在于把Nginx安装、配置、证书、防火墙这些杂事可视化但你看这里有个前提即使界面生成了配置你仍然要知道它生成的是什么否则一旦碰到复杂的location规则界面那点功能是不够用的。2. 配置前的必修课端口规划、proxy_pass和请求头2.1 多服务端口如何规划内网端口为什么只监听127.0.0.1动手配置之前先把服务器上的服务梳理清楚。我一般按这个思路规划对外统一只暴露80和443端口所有外部流量从这两个端口进来Nginx再根据域名分发给内网不同端口。后端服务本身不直接对外监听地址只写127.0.0.1这样即使云服务器安全组或防火墙误放开了一些端口外部也无法直接访问你的后端。举个例子一台服务器上可能有这样一个端口规划服务监听地址外部访问方式Nginx0.0.0.0:80 / 443统一入口Vue前端静态资源Nginx托管文件example.comSpring Boot后端127.0.0.1:8080example.com/api/内部工具面板127.0.0.1:9090tools.example.com端口规划的核心原则是“不冲突、易辨认、不裸奔”。项目多了之后8080、9090这类端口一眼就能认出是哪个服务省得每次都要查配置。而只监听127.0.0.1这个习惯是我强烈推荐的它从根上减少了后端被直接攻击的风险也避免了多个服务抢端口的问题。宝塔面板的防火墙上通常只需要放行80和443以及你管理面板用的那个端口。2.2 Nginx反向代理最核心的细节proxy_pass 带不带斜杠如果你翻过Nginx配置文件一定见过这条指令proxy_pass。它是反向代理的灵魂把匹配到的请求原样或改写后转发给后端。这里有一个全网都在踩的坑就是proxy_pass后面带不带斜杠、带不带路径转发结果完全不同。先看location匹配规则。比如location /api/ { proxy_pass http://127.0.0.1:8080; }配置里proxy_pass后面只写了协议和地址没有带任何URI路径那么请求 /api/users 会被原样转发给后端后端收到的是 /api/users。再比如location /api/ { proxy_pass http://127.0.0.1:8080/; }proxy_pass后面带了根路径斜杠这种情况下Nginx会用proxy_pass的URI部分替换掉location匹配到的部分请求 /api/users 转发到后端后变成 /users。这个差异可以整理成一张对照表客户端请求location定义proxy_pass配置后端实际收到/api/users/api/http://127.0.0.1:8080/api/users/api/users/api/http://127.0.0.1:8080//users/api/users/api/http://127.0.0.1:8080/api/users我见过太多人在这上面栽跟头后端说404前端怎么看路径都对实际就是proxy_pass里多了一个斜杠把接口前缀吃掉了。因此配置前先想清楚后端接口本身的路径是什么样的要不要保留 /api 前缀需要保留就不带斜杠不需要就去掉。如果用了宝塔的可视化反向代理填目标URL时同样要注意这一点它生成配置时不会帮你判断业务路径只会按你填的内容去套。另外location也有匹配优先级常见的几种修饰符是 精确匹配^~ 前缀匹配~ 和 ~* 正则匹配不带修饰则是普通前缀匹配。Nginx会先找前缀匹配中匹配最长的那个如果是^~就用它不再看正则如果不是^~则继续看正则有没匹配的有就用正则。这个规律在你配置多个location时会直接决定请求落到哪里建议理解把自己绕晕的概率会小很多。2.3 请求头设置把真实客户端IP传给后端反代之后后端收到的连接来自Nginx所以默认情况下Nginx传给后端的Host头、客户端IP等都会变成代理自身的。很多应用依赖真实客户端IP做日志、风控、限流必须显式把头传过去。下面这套配置是反代的标准动作无论什么场景都建议加上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;逐行解释一下。Host $host 把浏览器请求的原始域名传给后端后端生成跳转链接、做多域名判断时不会乱。$remote_addr是直接连Nginx的客户端地址X-Real-IP就用来装它。更复杂的网络环境里请求可能经过多层代理$proxy_add_x_forwarded_for会在原有X-Forwarded-For后面追加一层地址这样后端能拿到完整链路。X-Forwarded-Proto告诉后端客户端用的是http还是https否则有些框架看到内部是http会强制跳转或生成错误链接。还有一个容易忽略的参数是代理超时。默认的proxy_connect_timeout、proxy_read_timeout、proxy_send_timeout通常都可以用但如果你有一个接口要跑很久比如导出报表、调用第三方服务默认的60秒很容易被掐断。这种情况要么把proxy_read_timeout调大要么在业务上改成异步任务不要光指望靠反代硬扛。3. 实操在宝塔面板中从零配置Nginx反向代理3.1 5分钟快速配置宝塔内置“反向代理”功能全流程假设你已经装好了宝塔Linux面板并且在软件商店里把Nginx装好了。这一套我在CentOS、Ubuntu以及一些国产Linux发行版上都跑过宝塔的界面和配置文件位置基本一致。现在要给 example.com 配置反向代理把请求转发到本机 8080 端口的后端服务。第一步在“网站”菜单里添加一个站点域名填 example.comPHP版本选“纯静态”就可以数据库、FTP看情况创建。这里有个细节如果域名还没做DNS解析面板会提示创建成功但解析失败没关系你可以在自己的电脑上临时改hosts把 example.com 指向服务器IP先完成测试。第二步进入网站设置点“反向代理”再点“添加反向代理”。面板会让你填三样东西代理名称、目标URL、发送域名。代理名称随便起我习惯用后端服务的名字目标URL填 http://127.0.0.1:8080发送域名默认是 $host意思是转发时保留客户端访问的原始域名一般保持默认即可。第三步提交保存。宝塔会马上在网站的Nginx配置里生成一个 location / 的反向代理块配置内容大致长这样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_connect_timeout 60s; proxy_read_timeout 60s; proxy_send_timeout 60s; }到这里一个最基础的反向代理就配好了。你可以直接在浏览器访问 example.com如果后端服务正常页面就能出来。这套步骤确实快但要注意它生成的是 location / 的转发也就是说所有路径都会转发给后端。如果你的站点还有静态文件、图片等资源就还得手动加location规则或者把静态资源交给Nginx直接处理否则这些请求也会打到后端去白白浪费后端性能。3.2 手动编辑Nginx配置一份可直接复用的标准模板当你的需求超过“一个域名反代一个服务”时纯靠宝塔的可视化界面就不太够了。这时候建议直接编辑网站的Nginx配置文件。需要知道宝塔网站的配置目录是 /www/server/panel/vhost/nginx/你的站点配置文件就在这个目录下以 example.com.conf 命名。Nginx主程序的配置目录一般是 /www/server/nginx/conf/nginx.conf。我维护过一条比较完整、适合多场景的配置直接放出来供你参考server { listen 80; server_name example.com www.example.com; # 静态资源优先由Nginx直接处理 location /static/ { alias /www/wwwroot/example.com/static/; expires 7d; access_log off; } # 后端接口走反向代理 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_connect_timeout 60s; proxy_read_timeout 120s; proxy_send_timeout 60s; } # 其余所有请求都转发给前端应用 location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这段配置的逻辑是静态文件直接由Nginx服务接口 /api/ 转到Java后端其余请求转到Node前端。实际修改时建议先备份原文件再改改完保存后执行/www/server/nginx/sbin/nginx -t /www/server/nginx/sbin/nginx -s reload如果系统里nginx命令已经加入PATH直接 nginx -t 和 nginx -s reload 也行。nginx -t 是用来检测配置语法是否正确的重要安全网我每次改动后必执行出现syntax is ok再reload否则宁可先不改也绝不让一个半截配置上线把整站搞挂。3.3 典型案例宝塔部署Spring Boot Vue前后端分离项目这个场景几乎每个做web开发的人都会碰到我把它单独拿出来讲。前端用Vue或React打包后是纯静态文件需要Nginx托管后端用Spring Boot监听8080。两者通过Nginx反向代理保持同源避免跨域。具体操作分三部分。第一部分前端静态文件。把 build 或者 dist 目录里的内容上传到网站根目录比如 /www/wwwroot/example.com/dist。在Nginx配置里设置 root 指向这个目录server { listen 80; server_name example.com; root /www/wwwroot/example.com/dist; index index.html; location / { 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; } }第二部分注意 try_files。Vue Router如果用history模式访问 /about 这类前端路由时后端并没有这个文件必须让它回退到 index.html由前端路由接管。try_files $uri $uri/ /index.html 做的就是这件事。如果用的是hash模式这行可以省略但我建议直接上history因为URL更干净。第三部分接口转发。前端请求 /api/loginNginx把它转发到 127.0.0.1:8080/api/login。这里关键是proxy_pass后面不要加斜杠因为Spring Boot的Controller本身定义了 /api 前缀需要原样保留。如果你的后端接口不带 /api 前缀那就把proxy_pass改成 http://127.0.0.1:8080/同时注意后端路径会成为 /login。还有个细节帮不少人避过坑Spring Boot通过Nginx反代后如果它内部用了 X-Forwarded-Proto 来判断协议记得在配置里保留这行请求头否则有些安全框架会把请求识别成非HTTPS导致重定向死循环或者Cookie标志异常。宝塔面板自带的代理生成模板已经包含了这些头但如果你手动精简过配置很容易把这行弄丢。4. 进阶HTTPS证书、性能优化与安全加固4.1 SSL配置申请免费证书、强制HTTPS与自签名方案后端是HTTP前端用HTTPS这是反向代理最常见的组合。原因很简单证书只需要在Nginx这一层配置后端服务不用改任何代码Nginx把HTTPS流量解密后再以HTTP转发给内网端口这就省掉了给每个服务单独做TLS的麻烦。宝塔里申请证书极方便。在网站设置里找到SSL选择Lets Encrypt域名能正常解析到这台服务器的话一般一两分钟就能签发并自动部署。部署完成后开一下“强制HTTPS”访问http://example.com时会301跳转到https://example.com。我建议再把HTTP/2也打开多路复用和头部压缩对页面加载速度提升明显。如果没有域名或者只是内网测试环境也可以先用自签名证书让反代链路完整跑通。用openssl一行命令生成自签名证书openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /www/wwwroot/example.com/server.key \ -out /www/wwwroot/example.com/server.crt \ -subj /CNexample.com然后配置到server块server { listen 443 ssl; server_name example.com; ssl_certificate /www/wwwroot/example.com/server.crt; ssl_certificate_key /www/wwwroot/example.com/server.key; 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; } }自签名证书的局限是浏览器会弹不安全提示需要手动信任所以只建议用于开发、内网验收这类环境。正式环境老老实实申请可信证书宝塔里免费证书足够用。4.2 性能优化gzip、静态资源直出与代理缓存反向代理本身不会拖慢多少速度但配置方式不同对后端压力的影响差距非常大。我常用的优化手段有三个。第一个是gzip压缩。Nginx默认会压缩文本类资源但宝塔的默认配置不一定会开得很激进。你可以在http块里确认以下参数gzip on; gzip_min_length 1k; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript application/xml image/svgxml;开启后HTML、JS、CSS、JSON等资源的传输体积能减少60%以上。要注意不要对图片、视频等本来压缩过的二进制格式做gzip既费CPU又没收益。第二个是静态资源直出。凡是图片、CSS、JS文件都应该让Nginx直接读磁盘返回而不是转发给后端去读。Nginx处理静态文件的能力极强后端代码就专心出动态内容。所以我在配置里遇到 /static/ 这类路径都会单独写location指向实际目录并加上expires设置浏览器缓存。第三个是代理缓存。如果你的后端有大量请求在短时间重复访问同样的数据可以用proxy_cache把响应缓存在Nginx这一层大幅减轻后端压力。一个简单配置proxy_cache_path /tmp/ngx_cache levels1:2 keys_zoneapi_cache:10m max_size1g inactive60m; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_cache api_cache; proxy_cache_key $scheme$request_method$host$request_uri; proxy_cache_valid 200 5m; proxy_cache_valid 404 1m; }这里要特别提醒不是所有接口都能缓存。涉及用户身份、购物车、后台管理等个性化数据的接口如果统一缓存就会出现用户A看到用户B的数据这种严重事故。代理缓存只适合那种幂等、公共、变化不频繁的接口比如城市列表、菜单、配置信息。拿不准的时候宁可不开。4.3 安全加固内网端口收敛、默认站点拦截与权限控制反向代理把服务暴露方式统一了安全工作也要跟上。我自己的服务器安全底线是这几条。第一后端服务一律只监听127.0.0.1。Spring Boot在application.properties里设置 server.address127.0.0.1Node服务启动时用 app.listen(3000, 127.0.0.1)Python Flask设置 host127.0.0.1。这样即使防火墙上放开了某个端口外部也无法直接访问只能通过Nginx转发。第二云服务器安全组和宝塔防火墙只放行必要端口。80和443对外开放其他端口按需放行或者干脆全关。宝塔面板本身的管理端口也不要暴露到公网我是用IP白名单限制的不然面板登录入口容易成为被爆破的对象。第三配置一个默认站点拦截未绑定域名的访问。很多服务器的默认站点会把流量全收走如果是空白页还好最怕的是泄露Nginx版本、被扫描机器人当跳板。可以在Nginx配置里加一个default_serverserver { listen 80 default_server; server_name _; return 444; }444状态是Nginx的特殊处理会直接关闭连接连响应体都不返回对扫描器来说就像是端口没开一样。如果要用SSL在443端口也配一个default_server。这个坑挺隐蔽的很多站点没有加导致IP直接访问时总是落到某个业务站点上别人随便扫一下就能看到你的服务名称。第四敏感路径加上访问控制。比如 /admin、/manager 这类后台入口可以限定来源IP或者用HTTP Basic Auth加一层密码。宝塔的“网站-目录保护”和Nginx的allow/deny指令都能实现反正多一层验证多一分安心。5. 避坑指南高频故障排查与排查流程5.1 502与504问题大概率出在后端反向代理配置完浏览器常见的第一类报错就是502 Bad Gateway和504 Gateway Time-out。遇到这两个状态码先不要怀疑Nginx本身配置有问题绝大多数情况是后端出状况了。502的意思是Nginx成功把请求转发给了后端但后端没有给出有效响应。常见原因有后端进程没有启动端口监听的不是127.0.0.1防火墙或SELinux拦截了Nginx到后端的连接后端崩了正在重启。排查顺序建议是先看进程在不在再端口有没有监听直接从服务器上用curl访问一下后端地址比如curl -v http://127.0.0.1:8080/api/health curl -I http://127.0.0.1:8080/如果curl能通但浏览器502那就是Nginx到后端的链路有问题检查proxy_pass地址、端口、后端监听地址。如果curl也不通问题就在后端本身去看后端应用日志。504则代表Nginx和后端连上了但后端在超时时间内没有完成响应。这种问题要么是接口本身特别慢要么是某个上游依赖卡住了。解决办法是先把proxy_read_timeout调大比如改成300s确认业务能正常返回后再回头优化接口性能。注意调大超时是治标接口如果持续几秒甚至几十秒才返回用户体验很差还不如做成异步任务先返回“处理中”再轮询结果。顺便说一个和“响应时间太长导致无法访问”很像的场景如果只是某个页面偶尔打不开其他页面正常多半是后端在处理那个请求时卡住了比如查询了一个大表没有加索引、调用了外部服务没设超时。光调Nginx的timeout解决不了根本问题还是要从后端SQL、日志、链路耗时去查。5.2 404、路径错误、资源加载失败第二类常见报错是404。页面能打开但接口404或者页面样式、图片全挂了路径问题占了大头。接口404先回忆一下proxy_pass斜杠问题。我前面提过proxy_pass带不带路径会把请求的一部分替换掉。如果你发现前端请求 /api/users后端却收到 /users或者反过来后端收到 /api/api/users十有八九就是这里的斜杠搞错了。改配置后记得reload再打开Network面板看实际请求路径一对比就清楚了。页面能打开但样式和图片全丢失通常是静态资源路径没处理对。Vue或React项目如果配置了base路径打包后的资源URL会带上前缀比如 /app/assets/xxx.js而你的Nginx静态目录指向的是站点根目录资源自然加载不到。解决办法是让构建配置里的资源路径和Nginx目录结构保持一致或者在Nginx里再配一条location把资源路径映射过去location /app/ { alias /www/wwwroot/example.com/dist/; }还有一种路径坑是后端返回了重定向。后端看到请求路径不对自动补了斜杠或者带了别的路径301/302之后浏览器就跑到别的地方去了表现就是“明明配好了访问却到了一个奇怪的地址”。这类问题排查时看浏览器Network里的跳转链一般能一眼看出问题出在哪一层。5.3 配置不生效、语法错误、端口与日志排查最后一类问题是改动配置后“没效果”或者Nginx直接坏了。配置文件改了没生效最常见的原因是忘记reload。Nginx只有重启或reload后新配置才生效宝塔界面里的“重载配置”和命令行的nginx -s reload效果一样操作完记得做这一步。保存配置后Nginx起不来基本都是语法错误。用nginx -t检查是最快的它会明确告诉你哪个文件哪一行出了问题。常见错误包括每行指令结尾忘加分号大括号不匹配引号没闭合重复定义了同一个location。这种时候不要慌按提示逐行检查改回正确语法再reload。端口被占用也会让Nginx启动失败。比如80端口被其他服务占了我们可以用ss -lntp | grep :80 lsof -i:80找到占用进程把冲突解决掉再把端口释放出来。这里的教训是在一台机器上部署多个服务前先规划好端口不要贪方便随手用一个端口后面查起来非常痛苦。日志是反代排障的最后一根稻草。Nginx错误日志默认在 /www/wwwlogs/nginx_error.logJava、Node等其他后端应用各有各的日志位置但所有问题都会在某个日志里留下痕迹。我排查问题的固定套路是先看Nginx错误日志再看后端应用日志最后结合浏览器开发者工具判断是哪一层出的问题。这个顺序能过滤掉很多干扰信息比瞎猜快得多。这里把高频问题整理成速查表方便你直接对号入座现象大概率原因处理思路502 Bad Gateway后端没启动/端口不对ps、ss、curl查后端状态504 Gateway Time-out后端响应慢调大proxy_read_timeout优化后端接口404proxy_pass斜杠问题检查代理地址是否带URI资源加载失败前端base路径/目录结构不一致检查静态文件location和alias改了配置没生效没有reload或语法错误nginx -tnginx -s reload端口被占用8080等被其他进程占用ss或lsof查占用进程访问IP显示的是代理不是用户请求头没传检查X-Real-IP和X-Forwarded-For这套东西用熟了之后你会发现反向代理的配置就三板斧location怎么匹配、proxy_pass怎么转发、请求头怎么传。剩下的是经验和细心。我自己的体会是宝塔面板把流程简化了不少但它只是减轻了重复劳动真正值钱的是你对原理的理解和排障时的耐心。每次改配置先备份每次上线先nginx -t每次出问题先看日志这三个习惯能帮你避开绝大多数坑。
返回列表