Nginx 反向代理实战:从 502、跨域到 HTTPS,一次打通

Nginx 反向代理实战:从 502、跨域到 HTTPS,一次打通

502 不是玄学,是 Nginx 在告诉你:上游服务它连不上。

前后端分离之后,前端跑在 80 端口,后端在 3000,浏览器跨域、微信回调写死域名、HTTPS 还得配证书------这些问题我全用 Nginx 反向代理一把梭解决了。这篇从"它到底在干嘛"讲起,把 502/504/413、跨域、HTTPS 和那些反直觉的坑一次讲清。

什么时候你真的需要它?三种典型场景:一是单台服务器上同时跑前端和多个后端服务,靠不同路径分发;二是微信、支付宝等回调只认 80/443 端口,必须做一层转发;三是想统一收口 HTTPS 和静态资源缓存。如果你只是本地 npm run dev 调试,那用不到,但只要你把项目部署到公网,基本都绕不开这一层。下面所有配置我都标了中文注释,复制改域名即可用。

一、反向代理到底在干什么

一句话:反向代理是站在服务端的,把用户请求悄悄转发给后端真实服务,再把结果回传给用户,用户全程不知道背后有几台机器。

维度 正向代理 反向代理
代理对象 客户端(帮内网用户访问外网) 服务器(帮后端隐藏真实地址)
谁配置 客户端自己配 服务端运维配
典型场景 内网出口、访问控制 负载均衡、统一入口、SSL 卸载
用户感知 知道自己用了代理 以为就在访问这一台机器

我们说的"反向代理"就是后者:用户只访问 Nginx 的 80/443,Nginx 把 /api 转给后端 3000 端口。


二、最小可用的 proxy_pass

先装好:sudo apt install nginx(CentOS 用 yum install nginx)。配置文件放在 /etc/nginx/conf.d/,默认 nginx.confinclude 这个目录。最小能跑的反代:

nginx 复制代码
server {
    listen 80;
    server_name example.com;   # 改成你的域名,没域名先用服务器 IP

    location / {
        proxy_pass http://127.0.0.1:3000;   # 转发到本机后端
    }
}

改完务必先校验再生效:

bash 复制代码
sudo nginx -t            # 检查语法,看到 successful 再继续
sudo nginx -s reload     # 平滑重载,不影响已有连接

三、四个关键 header 为什么必须传

只写 proxy_pass 会埋坑:后端拿到的 Host127.0.0.1:3000,拿不到用户真实 IP,生成绝对链接、限流、日志全错。所以标准写法一定要带这四个头:

nginx 复制代码
location / {
    proxy_pass http://127.0.0.1:3000;

    # 把原始域名传给后端,后端生成链接才不会写成 localhost
    proxy_set_header Host $host;
    # 用户真实 IP,后端日志、风控要用
    proxy_set_header X-Real-IP $remote_addr;
    # 多层代理时累加的 IP 链,比 X-Real-IP 更完整
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 原始协议,后端判断是不是 HTTPS 靠它(否则死循环跳转)
    proxy_set_header X-Forwarded-Proto $scheme;
}

后端框架(如 Express、Spring)开启 trust proxy 后就能正确读取这些头。


四、502/504/413 各自怎么查

502 Bad Gateway :Nginx 连上了 socket 但上游返回了无效响应,最常见是后端根本没启动或端口写错。

bash 复制代码
# 先看后端进程在不在、端口是否监听
sudo lsof -i :3000
curl http://127.0.0.1:3000   # 直接在服务器本地打,排除 Nginx 干扰
tail -f /var/log/nginx/error.log   # 502 会把 "connect() failed" 写这里

504 Gateway Timeout :连接成功了,但后端处理太久没回。调大超时:

nginx 复制代码
proxy_connect_timeout 60s;
proxy_send_timeout    60s;
proxy_read_timeout    60s;   # 长任务 / 大查询重点调这项

413 Request Entity Too Large :上传文件超过默认 1MB 限制。改 client_max_body_size

nginx 复制代码
client_max_body_size 50m;   # 放在 http / server / location 都行

定位通用套路:先 sudo nginx -t 确认配置没错,再 tail -f /var/log/nginx/error.log 看具体行号报错,最后在服务器本地 curl 后端端口验证"到底是 Nginx 的锅还是后端的锅"。


五、用 Nginx 解决跨域

前端和后端不同源时浏览器会拦跨域。与其改后端代码,不如让 Nginx 在响应里加上 CORS 头,并正确处理预检请求(OPTIONS):

nginx 复制代码
location /api/ {
    # 预检请求直接返回 204,不带 body
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
        return 204;
    }

    # 正常响应也带上头
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';

    proxy_pass http://127.0.0.1:3000;
}

生产环境建议把 * 换成具体前端域名,更安全。


六、Certbot 一键上 HTTPS

免费证书用 Let's Encrypt + Certbot,自动申请还能自动续期:

bash 复制代码
# 安装(Ubuntu/Debian 示例)
sudo apt install certbot python3-certbot-nginx

# 一条命令:申请证书 + 自动改写 Nginx 配置 + 加上 HTTP 跳转 HTTPS
sudo certbot --nginx -d example.com -d www.example.com

# 验证自动续期任务(certbot 默认会注册 systemd timer)
sudo certbot renew --dry-run

执行后 Nginx 配置里会自动多出 listen 443 ssl; 和证书路径,并新增一段 80 端口的 return 301 https://$host$request_uri;。证书 90 天一换,renew 只在快过期时才真正更新,放心挂着。


七、gzip 压缩与静态资源缓存

开启 gzip,文本类资源体积能砍掉 70%:

nginx 复制代码
gzip on;
gzip_min_length 1024;             # 小于 1KB 不压缩,省 CPU
gzip_comp_level 6;                # 压缩级别 1-9,6 是性价比甜点
gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;

静态资源(图片、打包后的 JS 与样式表)设长缓存,文件名带 hash 就不怕更新不生效:

nginx 复制代码
location /static/ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

八、单机多域名多站点

一台机器挂多个域名,写多个 server 块即可,Nginx 按 server_name 路由:

nginx 复制代码
server {
    listen 80;
    server_name a.com;
    location / { proxy_pass http://127.0.0.1:3000; }
}

server {
    listen 80;
    server_name b.com;
    location / { proxy_pass http://127.0.0.1:4000; }
}

每个站点放一个独立 .conf 文件在 conf.d/ 下,互不干扰,删站点就是删文件再 reload


九、常见坑逐个排

坑 1:proxy_pass 结尾斜杠的差别

proxy_pass http://127.0.0.1:3000;proxy_pass http://127.0.0.1:3000/; 不一样!带斜杠会把 location /api/ 里的 /api/ 部分剥掉 再转发;不带则连同 /api/ 一起转。路径对不上大多源于此,按后端实际路由选。

坑 2:上传大文件 413

忘了 client_max_body_size,加在 serverlocation 里并 reload

坑 3:SSE / WebSocket 被缓冲

实时推送、聊天室连上却收不到消息,是 Nginx 缓冲了响应。关缓冲并升级协议:

nginx 复制代码
location /ws/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";   # WebSocket 必备
    proxy_buffering off;                      # SSE 必备,别等满了才发
}

坑 4:改了配置却没生效

你改的是 conf.d/ 下的文件却忘了 nginx -s reload,或改错了文件(确认 nginx -t 指向的配置路径)。

坑 5:SELinux 挡转发(CentOS/RHEL 特有)

配置全对但就是 502,且 error.log 报 Permission denied。放行网络转发:

bash 复制代码
sudo setsebool -P httpd_can_network_connect on

收个尾:反向代理本质就是"转发 + 补头 + 兜底超时",502 先本地 curl 后端、413 改最大体积、跨域加头、HTTPS 交给 Certbot。今晚就把你那个还在裸跑 3000 端口的项目用上面的最小配置接一层 Nginx,再跑一次 certbot --nginx,体验一次输入 http:// 自动跳 https:// 的爽感。

相关推荐
迷茫的大专生2 小时前
服务器部署与 MySQL 运维学习笔记:从 Ansible 到高可用与性能优化
mysql·nginx·ansible·mysql优化·keepalive
一技安身3 小时前
【信创】docker-26.0.2.tgz 原理 + 完整安装
linux·运维·服务器
Dachui_11223 小时前
内网穿透 Webhook 告警实战:客户端离线、应用探测、资源删除全覆盖
运维·远程工作·内网穿透·devops·webhook·服务器监控·应用探测
数据智研3 小时前
【数据分享】300个城市-5G试点城市DID数据(2014-2025)
大数据·运维·人工智能·信息可视化·数据分析
honsor3 小时前
工业级网口温湿度变送器 ModbusTCP 机房动环环境监测终端
运维·网络·人工智能·物联网·安全·云计算·智能温湿度监测系统
2501_915918413 小时前
怎么把 Python 写的 Flet 应用打包成 iOS App 并上架 App Store?
android·ios·小程序·https·uni-app·iphone·webview
fengkai45453 小时前
八、Docker详解1-3
运维·docker·容器
流浪0014 小时前
Linux系统篇34——信号(六):信号处理期间又来了怎么办?——sigaction、sa_mask、可重入函数与 volatile
linux·运维·面试·操作系统·信号处理·信号
学烹饪的小胡桃4 小时前
资产设备管理系统 WGFIX 怎么设置https访问
linux·运维·服务器·网络·安全