Nginx 反向代理实战:从入门配置到 HTTPS 与负载均衡

一台服务器上跑着好几个服务:博客、API、监控面板……每个都监听一个端口(3000、8080、9090),用户记不住端口号,浏览器地址栏还老是弹「不安全」。反代(反向代理)就是来解决这件事的:所有流量先到 Nginx,Nginx 按域名/路径转发给背后的服务,端口、证书、负载均衡全部在这一层集中处理。

本文用一套「从零到生产」的实战路径讲清 Nginx 反向代理:最小配置 → HTTPS → 负载均衡 → WebSocket → 多应用部署 → 常见坑。

反向代理原理:一句话

用户访问 https://example.com → Nginx 收到请求 → 根据 server_namelocation 规则 → 转发给内网/本机的后端服务 → 拿回响应再返回给用户。对用户来说只看到 Nginx 这一个入口,后端服务的真实地址被藏了起来。

最小可用配置

假设你有个应用跑在 127.0.0.1:3000,想让用户通过 app.example.com 访问:

server {
    listen 80;
    server_name app.example.com;

    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;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

配置放好后验证并重载(每次改配置必做):

sudo nginx -t                    # 语法检查
sudo systemctl reload nginx      # 平滑重载, 不中断连接

四个请求头,一个都不能少

这四行是生产环境标配,缺了会出各种诡异问题:

请求头 作用 缺失后果
Host $host 把原始域名传给后端 后端按域名路由时会 404
X-Real-IP $remote_addr 传递真实客户端 IP 后端日志里全是 127.0.0.1
X-Forwarded-For 完整代理链 IP 列表 多级代理时拿不到真实 IP
X-Forwarded-Proto $scheme 告知后端是 http 还是 https 应用生成错误的跳转(http→http 死循环)

HTTPS:交给 Certbot,别手写证书配置

申请 Let’s Encrypt 证书用 Certbot 的 Nginx 插件一键完成,不要手动生成证书和写 SSL 配置块(容易踩加密套件配置的坑):

# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx -y

# 一条命令: 验证域名 → 签发证书 → 自动改 nginx 配置 → 自动配 80→443 跳转
sudo certbot --nginx -d app.example.com

Certbot 会自动:把 listen 80 改成 listen 443 ssl http2、插入证书路径、加 301 跳转、配置安全套件。你只需要管一件事——自动续期

sudo systemctl status certbot.timer     # 证书 90 天有效, 定时器会提前 30 天自动续期
sudo certbot renew --dry-run            # 手动演练一次续期, 确认没毛病

证书文件在 /etc/letsencrypt/live/域名/ 下:fullchain.pem(证书链)和 privkey.pem(私钥),注意别泄露私钥。

负载均衡:一个入口,多个后端

后端服务部署了多份(多实例/多机器),用 upstream 定义服务器池,proxy_pass 指向池子:

upstream app_cluster {
    least_conn;                       # 算法: 见下方说明
    server 192.168.1.101:9090 weight=3;   # 权重 3, 分到更多流量
    server 192.168.1.102:9090 weight=2;
    server 192.168.1.103:9090 max_fails=3 fail_timeout=30s;  # 30 秒内失败 3 次则摘除
    server 192.168.1.104:9090 backup;     # 备用机, 主服务器全挂才启用
}

server {
    listen 443 ssl;
    server_name api.example.com;
    location / {
        proxy_pass http://app_cluster;
        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;
    }
}

四种负载均衡算法:

算法 说明 适用场景
轮询(默认) 依次分发,可配 weight 权重 后端性能均衡
least_conn 转发给连接数最少的后端 请求处理时间差异大
ip_hash 同一 IP 永远打到同一后端 需要会话保持(WebSocket/登录态)
random two least_conn 随机挑两个取连接少的 后端数量多

WebSocket:缺两行就静默失败

WebSocket 需要 HTTP/1.1 升级握手,proxy_pass 默认按 HTTP/1.0 转发,少了下面两行连接会莫名断开

location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;               # 升级协议必需
    proxy_set_header Upgrade $http_upgrade;   # 传递升级请求
    proxy_set_header Connection "upgrade";    # 声明连接升级
    proxy_set_header Host $host;
    proxy_read_timeout 3600s;             # 关键! 默认 60s 会掐断长连接
}

proxy_read_timeout 不调大,WebSocket 长连接 60 秒后就会被 Nginx 断开——这是最常见的「连接一会儿就断」原因。多实例部署 WebSocket 建议配 ip_hash,保证同一客户端的连接始终落在同一后端。

多应用同机部署:按域名路由

一台服务器多个应用,各写各的 server 块,Nginx 按 server_name 分发,互不干扰:

# /etc/nginx/sites-available/blog.conf
server {
    listen 443 ssl;
    server_name blog.example.com;
    root /var/www/blog;
    # WordPress 伪静态: 非真实文件交给 index.php 处理
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }
}

# /etc/nginx/sites-available/api.conf
server {
    listen 443 ssl;
    server_name api.example.com;
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

启用站点:sudo ln -s /etc/nginx/sites-available/blog.conf /etc/nginx/sites-enabled/ 然后 nginx -t + reload

实战提醒:面板类工具(宝塔等)生成的伪静态规则偶尔会「好心办坏事」——比如把 /category/xxx/ 这类路径拦截掉导致 404。遇到这种问题,先看面板的伪静态/重写规则,再看 nginx 的 location 匹配优先级,别急着怀疑应用本身。

常见坑与排查

502 Bad Gateway 三大原因:

systemctl status 你的服务        # 1. 后端根本没启动
ss -tlnp | grep 3000             # 2. proxy_pass 端口写错/没监听
tail -f /var/log/nginx/error.log # 3. 看真实报错(连接拒绝/超时)

HTTPS 证书没生效 / 跳转异常:先 curl -v https://域名 看证书链,sudo certbot certificates 查证书状态,nginx -t 确认配置没被改坏。

前端路由刷新 404(SPA)location / { try_files $uri $uri/ /index.html; },把不存在的路径回退到入口页。

安全与性能小优化

http {
    server_tokens off;   # 隐藏 Nginx 版本号

    # 限流: 每个 IP 每秒 5 个请求, 超出返回 503
    limit_req_zone $binary_remote_addr zone=api:10m rate=5r/s;
}

server {
    # 安全响应头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=31536000" always;  # 强制 HTTPS

    # 屏蔽敏感文件
    location ~ \.(env|git|log|sql)$ { deny all; }

    # 静态资源直接由 Nginx 出, 不代理给后端
    location /static/ {
        alias /var/www/app/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

多个 server 块共享的代理头可以抽到 /etc/nginx/proxy_params 文件里,用 include proxy_params; 复用,少写重复代码。

总结

反向代理的核心心智模型就一句话:Nginx 是唯一的门,门背后是各种服务。按这个路径走:

  1. 最小 server 块 + 四个请求头起步
  2. HTTPS 直接 certbot --nginx,续期交给定时器
  3. 多实例上 upstream,按场景选算法
  4. WebSocket 记得 proxy_http_version 1.1 + Upgrade/Connection + 长超时
  5. 每次改配置 nginx -t + reload,出问题先看 error.log

配置本身不难,难的是知道「哪些头不能省、哪些超时要调大」。把本文这几条记牢,反代基本不会翻车。

参考资料

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇