LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

Nginx 实战指南:手把手带你部署反向代理

admin
2026年1月22日 17:51 本文热度 126

在部署项目时会遇到这样的问题:

  • 只有一个 80 端口可用,但公司系统有多套,这就会导致外部访问时需要域名+端口的方式,要记住各种端口是件很痛苦的事情。有没有办法让所有系统都能通过 80 端口访问呢?
  • 前后端分离时,前端调后端接口总是报 CORS 跨域错误
  • 想把内网的几台服务器隐藏起来,只暴露一个出口给公网
  • WebSocket 连接需要特殊配置才能正常工作
  • TCP 端口转发(如 MySQL、Redis)需要四层代理

这时候,你需要一位强大的"中间人"—— Nginx 反向代理

它是 Nginx 使用率最高的功能,没有之一。今天我们将彻底拆解 proxy_pass 指令,带你打通流量转发的"任督二脉"。

一、基础实战:配置你的第一个反向代理

场景:Node.js 应用代理

假设你有一个 Node.js 应用跑在 localhost:3000,现在想通过域名 api.example.com 访问它。

server {    listen 80;    server_name api.example.com;    location / {        # 核心指令:将流量转发给本地的 3000 端口        proxy_pass <http://127.0.0.1:3000>;        # ⚠️ 关键:不要让后端变成"盲人"        # 如果不传这些 Header,后端拿到的 IP 全是 127.0.0.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_set_header?

Nginx 转发请求时,默认会"丢掉"原始请求的一些头信息。如果不手动透传:

  • 后端不知道用户真实的域名是什么(Host
  • 后端拿不到用户的真实 IP(X-Real-IP),日志里全是内网 IP,做风控或限流时会失效
  • 后端不知道用户用的是 HTTP 还是 HTTPS(X-Forwarded-Proto

重载配置

# 检查配置nginx -t# 重载生效nginx -s reload

二、 经典问题:proxy_pass 后面加不加斜杠 /?

这是 Nginx 配置中最大的坑,90% 的人都踩过。

测试场景

假设请求地址是:http://api.example.com/api/user

写法 A(不带斜杠)

location /api/ {    proxy_pass <http://127.0.0.1:3000>;}



结果: 后端收到的路径是 /api/user(路径透传,原样转发)

写法 B(带斜杠)

location /api/ {    # 注意 3000 后面有个 /    proxy_pass <http://127.0.0.1:3000/>;}



结果: 后端收到的路径是 /user(路径替换,把 /api/ 切掉了)

写法 C(带路径 + 斜杠)

location /api/ {    proxy_pass <http://127.0.0.1:3000/backend/>;}

结果: 后端收到的路径是 /backend/user(路径替换并拼接)

结论

配置
请求 /api/user
后端收到
proxy_pass <http://127.0.0.1:3000>;
/api/user
/api/user
proxy_pass <http://127.0.0.1:3000/;
/api/user
/user
proxy_pass <http://127.0.0.1:3000/backend/;
/api/user
/baackend/user

记忆口诀:

  • 不带斜杠 = 原样转发
  • 带斜杠 = 替换路径

三、 生产场景 A:前后端分离部署

需求

  • 前端静态文件:www.example.com
  • 后端 API:www.example.com/api
  • 避免 CORS 跨域问题

配置

server {    listen 80;    server_name www.example.com;    # 前端静态文件    location / {        root /data/www/frontend;        index index.html;        try_files $uri $uri/ /index.html;  # SPA 应用必须加这行    }    # 后端 API 代理    location /api/ {        proxy_pass <http://127.0.0.1:8080/>;  # 注意有斜杠,去掉 /api 前缀        # 必备 Headers        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_send_timeout 60s;        proxy_read_timeout 60s;    }    # 静态资源缓存    location ~* \\.(jpg|jpeg|png|gif|ico|css|js)$ {        root /data/www/frontend;        expires 30d;        add_header Cache-Control "public, immutable";    }}




为什么能解决 CORS?

因为前端和后端 API 的域名完全一样(都是 www.example.com),浏览器认为是"同源",不会触发跨域检查。

四、 生产场景 B:多套系统统一入口

需求

  • 官网:www.example.com
  • 管理后台:www.example.com/admin
  • 用户中心:www.example.com/user
  • 订单系统:www.example.com/order

每个系统跑在不同端口,但对外只暴露 80 端口。

配置

server {    listen 80;    server_name www.example.com;    # 官网(前端静态文件)    location / {        root /data/www/website;        index index.html;        try_files $uri $uri/ /index.html;    }    # 管理后台    location /admin/ {        proxy_pass <http://127.0.0.1:8081/>;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    }    # 用户中心    location /user/ {        proxy_pass <http://127.0.0.1:8082/>;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    }    # 订单系统    location /order/ {        proxy_pass <http://127.0.0.1:8083/>;        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 太多?可以提取到 http 块或独立文件。

创建文件:/usr/local/nginx/conf/proxy_params

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_send_timeout 60s;proxy_read_timeout 60s;# 缓冲区配置(提升性能)proxy_buffering on;proxy_buffer_size 4k;proxy_buffers 8 4k;proxy_busy_buffers_size 8k;

然后在 location 中引入:

location /admin/ {    proxy_pass <http://127.0.0.1:8081/>;    include /usr/local/nginx/conf/proxy_params;}

五、 生产场景 C:WebSocket 反向代理

需求

WebSocket 应用(如在线聊天、实时推送)需要特殊配置,否则会出现连接断开或无法建立连接。

为什么 WebSocket 需要特殊处理?

WebSocket 是长连接协议,需要:

  1. 升级 HTTP 协议到 WebSocket(HTTP Upgrade)
  2. 保持连接不断开(增加超时时间)
  3. 禁用缓冲(实时传输)

配置示例

server {    listen 80;    server_name ws.example.com;    # WebSocket 代理    location / {        proxy_pass <http://127.0.0.1:3000>;        # 核心配置:协议升级        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "upgrade";        # 基础 Headers        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        # 超时配置(WebSocket 长连接)        proxy_connect_timeout 7d;    # 连接超时        proxy_send_timeout 7d;       # 发送超时        proxy_read_timeout 7d;       # 读取超时        # 禁用缓冲(实时传输)        proxy_buffering off;    }}

完整示例:前端 + WebSocket

server {    listen 80;    server_name chat.example.com;    # 前端页面    location / {        root /data/www/chat-frontend;        index index.html;    }    # HTTP API    location /api/ {        proxy_pass <http://127.0.0.1:3000/>;        include /usr/local/nginx/conf/proxy_params;    }    # WebSocket 连接    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";        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_connect_timeout 7d;        proxy_send_timeout 7d;        proxy_read_timeout 7d;        proxy_buffering off;    }}

WebSocket 测试

前端 JS 代码:

// 注意:生产环境用 wss://(WebSocket over TLS)const ws = new WebSocket('ws://chat.example.com/ws/');ws.onopen = () => {    console.log('WebSocket 连接成功');    ws.send('Hello Server!');};ws.onmessage = (event) => {    console.log('收到消息:', event.data);};ws.onerror = (error) => {    console.error('WebSocket 错误:', error);};ws.onclose = () => {    console.log('WebSocket 连接关闭');};

六、 生产场景 D:TCP/UDP 端口转发(四层代理)

需求

有些服务需要直接转发 TCP 端口,比如:

  • MySQL(3306)
  • Redis(6379)
  • PostgreSQL(5432)
  • MongoDB(27017)

前置条件

确认编译时开启了 stream 模块:

nginx -V 2>&1 | grep -o with-stream# 如果没有输出,需要重新编译./configure --with-stream --with-stream_ssl_modulemake && make install

配置示例:MySQL 代理

注意: stream 块和 http 块是并列关系,不能写在 http 里面。

编辑 nginx.conf

# 在文件最外层(和 http 块并列)stream {    # MySQL 代理    upstream mysql_backend {        server 192.168.1.10:3306;  # 内网 MySQL 服务器    }    server {        listen 3306;  # Nginx 监听 3306        proxy_pass mysql_backend;        # 超时配置        proxy_connect_timeout 10s;        proxy_timeout 300s;  # 5 分钟无数据传输则断开    }}http {    # ... 原有的 HTTP 配置 ...}

完整示例:多服务端口转发

user nginx nginx;worker_processes auto;events {    worker_connections 1024;}# TCP/UDP 代理(四层)stream {    # MySQL 代理    upstream mysql_backend {        server 192.168.1.10:3306 max_fails=3 fail_timeout=30s;    }    server {        listen 3306;        proxy_pass mysql_backend;        proxy_connect_timeout 10s;        proxy_timeout 300s;    }    # Redis 代理    upstream redis_backend {        server 192.168.1.11:6379;    }    server {        listen 6379;        proxy_pass redis_backend;        proxy_connect_timeout 10s;        proxy_timeout 600s;    }    # PostgreSQL 代理    upstream postgres_backend {        server 192.168.1.12:5432;    }    server {        listen 5432;        proxy_pass postgres_backend;        proxy_connect_timeout 10s;        proxy_timeout 300s;    }}# HTTP/HTTPS 代理(七层)http {    # ... 你的 HTTP 配置 ...}

TCP 代理日志配置

stream {    # 日志格式    log_format proxy '$remote_addr [$time_local] '                     '$protocol $status $bytes_sent $bytes_received '                     '$session_time "$upstream_addr" '                     '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';    access_log /usr/local/nginx/logs/tcp_access.log proxy;    error_log /usr/local/nginx/logs/tcp_error.log warn;    # ... 其他配置 ...}

使用场景
  1. 数据库隐藏
    :不直接暴露数据库 IP,统一通过 Nginx 入口
  2. 端口统一
    :多个内网数据库,通过 Nginx 统一对外端口
  3. 访问控制
    :配合防火墙,只允许 Nginx 访问内网数据库
  4. 负载均衡
    :后面会讲如何对 TCP 做负载均衡

七、 超时参数详解

不同场景需要不同的超时配置:

HTTP 代理超时

location /api/ {    proxy_pass <http://127.0.0.1:8080/>;    # 连接超时(Nginx 到后端建立连接的时间)    proxy_connect_timeout 60s;    # 发送超时(Nginx 向后端发送数据的超时)    proxy_send_timeout 60s;    # 读取超时(Nginx 等待后端响应的超时)    proxy_read_timeout 60s;}

WebSocket 超时

location /ws/ {    # WebSocket 需要长时间保持连接    proxy_connect_timeout 7d;    proxy_send_timeout 7d;    proxy_read_timeout 7d;}

TCP 代理超时

stream {    server {        listen 3306;        proxy_pass mysql_backend;        # 连接超时        proxy_connect_timeout 10s;        # 数据传输超时(双向无数据传输时断开)        proxy_timeout 300s;    }}

推荐配置
场景
connect
send/read
说明
普通 API
60s
60s
适合大部分场景
文件上传
60s
300s
大文件需要更长时间
长时间计算
60s
600s
如报表生成、AI 推理
WebSocket
60s
7d
长连接保持
MySQL/Redis
10s
300s
数据库连接

八、 缓冲区优化

默认配置(适合大部分场景)

location /api/ {    proxy_pass <http://127.0.0.1:8080/>;    # 开启缓冲(提升性能)    proxy_buffering on;    # 缓冲区大小(响应头)    proxy_buffer_size 4k;    # 缓冲区数量和大小(响应体)    proxy_buffers 8 4k;    # 繁忙缓冲区大小    proxy_busy_buffers_size 8k;}

实时流式传输(禁用缓冲)

适用于:SSE(Server-Sent Events)、视频流、实时日志

location /stream/ {    proxy_pass <http://127.0.0.1:8080/>;    # 禁用缓冲(实时传输)    proxy_buffering off;    # 禁用缓存    proxy_cache off;}

九、 常见问题排查

问题 1:502 Bad Gateway

原因:

  1. 后端服务未启动
  2. 后端服务端口错误
  3. 防火墙阻止连接
  4. 后端响应超时

排查步骤:

# 1. 检查后端服务是否运行ps -ef | grep your_servicesystemctl status your_service# 2. 检查端口是否监听netstat -tunlp | grep 8080# 3. 测试能否直接访问后端curl <http://127.0.0.1:8080/># 4. 查看 Nginx 错误日志tail -f /usr/local/nginx/logs/error.log# 5. 检查 SELinux(CentOS 常见问题)getenforce# 如果是 Enforcing,临时关闭测试setenforce 0

问题 2:504 Gateway Timeout

原因: 后端处理时间过长,超过了 Nginx 的超时设置。

解决方案:

location /slow-api/ {    proxy_pass <http://127.0.0.1:8080/>;    # 增加超时时间    proxy_connect_timeout 120s;    proxy_send_timeout 120s;    proxy_read_timeout 120s;}

问题 3:WebSocket 连接断开

原因: 超时时间太短或缺少协议升级配置。

解决方案:

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";    # 增加超时    proxy_read_timeout 3600s;}

问题 4:后端拿不到真实 IP

原因: 缺少 X-Real-IP 或 X-Forwarded-For 头。

解决方案:

location / {    proxy_pass <http://127.0.0.1:8080>;    # 必须传递这些头    proxy_set_header X-Real-IP $remote_addr;    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}

后端获取真实 IP(以 Node.js 为例):

// 优先从 X-Real-IP 获取,其次 X-Forwarded-Forconst realIP = req.headers['x-real-ip'] ||               req.headers['x-forwarded-for']?.split(',')[0] ||               req.connection.remoteAddress;

问题 5:TCP 代理连接失败

排查步骤:

# 1. 检查 stream 模块是否编译nginx -V 2>&1 | grep with-stream# 2. 检查 Nginx 是否监听目标端口netstat -tunlp | grep 3306# 3. 测试后端数据库连接mysql -h 192.168.1.10 -P 3306 -u root -p# 4. 查看 stream 日志tail -f /usr/local/nginx/logs/tcp_error.log# 5. 防火墙放行端口firewall-cmd --permanent --add-port=3306/tcpfirewall-cmd --reload

10、 安全加固

限制上传大小

server {    # 限制请求体大小(防止恶意上传)    client_max_body_size 10m;    location /upload/ {        # 单独配置上传接口        client_max_body_size 100m;        proxy_pass <http://127.0.0.1:8080/>;    }}

限制访问来源

location /admin/ {    # 只允许内网访问    allow 192.168.1.0/24;    allow 10.0.0.0/8;    deny all;    proxy_pass <http://127.0.0.1:8081/>;}

防止 Host 头攻击

server {    listen 80 default_server;    server_name _;    # 非法域名直接关闭连接    return 444;}server {    listen 80;    server_name www.example.com;    # 你的正常配置}

隐藏敏感信息

http {    # 隐藏 Nginx 版本号    server_tokens off;    # 隐藏后端服务器信息    proxy_hide_header X-Powered-By;    proxy_hide_header Server;}

11、 完整生产配置模板

文件结构

/usr/local/nginx/conf/├── nginx.conf                 # 主配置├── proxy_params               # 代理通用参数└── conf.d/    ├── www.example.com.conf   # 官网    ├── api.example.com.conf   # API    └── ws.example.com.conf    # WebSocket

nginx.conf

user nginx nginx;worker_processes auto;error_log logs/error.log warn;pid logs/nginx.pid;events {    worker_connections 2048;    use epoll;}# TCP/UDP 代理stream {    log_format proxy '$remote_addr [$time_local$protocol $status';    access_log logs/tcp_access.log proxy;    error_log logs/tcp_error.log warn;    # MySQL    upstream mysql_backend {        server 192.168.1.10:3306 max_fails=3 fail_timeout=30s;    }    server {        listen 3306;        proxy_pass mysql_backend;        proxy_connect_timeout 10s;        proxy_timeout 300s;    }}# HTTP/HTTPS 代理http {    include mime.types;    default_type application/octet-stream;    log_format main '$remote_addr - $remote_user [$time_local] "$request" '                    '$status $body_bytes_sent "$http_referer" '                    '"$http_user_agent" "$http_x_forwarded_for"';    access_log logs/access.log main;    sendfile on;    tcp_nopush on;    tcp_nodelay on;    keepalive_timeout 65;    server_tokens off;    gzip on;    gzip_min_length 1k;    gzip_comp_level 6;    gzip_types text/plain text/css text/javascript application/json application/javascript application/xml;    client_max_body_size 10m;    # 引入站点配置    include /usr/local/nginx/conf/conf.d/*.conf;}

proxy_params

# 通用代理参数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_send_timeout 60s;proxy_read_timeout 60s;proxy_buffering on;proxy_buffer_size 4k;proxy_buffers 8 4k;proxy_busy_buffers_size 8k;

conf.d/api.example.com.conf

# API 服务server {    listen 80;    server_name api.example.com;    access_log logs/api.example.com.access.log main;    error_log logs/api.example.com.error.log warn;    # 普通 API    location /v1/ {        proxy_pass <http://127.0.0.1:8080/>;        include /usr/local/nginx/conf/proxy_params;    }    # WebSocket API    location /ws/ {        proxy_pass <http://127.0.0.1:8080/>;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "upgrade";        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_connect_timeout 7d;        proxy_send_timeout 7d;        proxy_read_timeout 7d;        proxy_buffering off;    }    # 健康检查    location /health {        access_log off;        return 200 "ok\\n";        add_header Content-Type text/plain;    }}


该文章在 2026/1/22 17:51:47 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved