Nginx 从入门到能扛事:反向代理、负载均衡与 HTTPS 实战

Nginx 从入门到能扛事:反向代理、负载均衡与 HTTPS 实战

运维学习路线系列 · 阶段三 中间件栈 · 第 3 篇(长篇)

适用环境:Ubuntu 24.04 LTS,Nginx 1.26(apt 官方源),示例 IP:192.168.1.10/11/12

阅读前提:阶段一、二全部

前言:为什么你的服务"裸奔"不过夜

Flask 应用直接监听 8080 对公网提供服务:没有 HTTPS、静态文件也要 Python 来扛、单进程崩了网站全下线、后台地址被人扫出来。生产环境的正确姿势是前面挡一层 Nginx:

  • 静态文件它扛(快到离谱),动态请求它转发;
  • 它管 HTTPS/HTTP2/压缩,应用不用管;
  • 后面挂多个应用实例,它做负载均衡;
  • 挂了拉起交给 systemd(S1-05)。

这篇从配置文件结构讲到 location 匹配、反向代理、负载均衡、HTTPS,全程给可直接抄的完整配置。


一、安装与配置文件地图

bash 复制代码
sudo apt install nginx -y
nginx -v                      # 确认版本
systemctl status nginx        # active (running)
curl -sI localhost | head -1  # 200 OK ------ 一条命令验证装好了

Ubuntu 的 Nginx 配置是"总-分-软链接"结构(S1-02 讲的软链接实战现场):

复制代码
/etc/nginx/nginx.conf             总入口:进程数、日志、events、include
/etc/nginx/conf.d/*.conf          第三方配置(自行放置)
/etc/nginx/sites-available/       可用站点(文件躺着,不生效)
/etc/nginx/sites-enabled/         已启用站点 → 指向 available 的软链接!
/etc/nginx/ssl/                   证书放这(自建)

启用/停用一个站点 = 建/删 sites-enabled 里的软链接------这是 Debian 系管理的核心动作:

bash 复制代码
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default        # 关掉默认页

两条保命命令(每次改配置必跑,S1-04 Vim 篇的老朋友):

bash 复制代码
sudo nginx -t          # 语法测试:error 才是问题,warning 是提示
sudo systemctl reload nginx    # 平滑重载,连接不断(S1-05 的 reload 知识)

二、最小内核:nginx.conf 总览

nginx 复制代码
# /etc/nginx/nginx.conf(关键段注释)
user www-data;                      # worker 进程身份(S1-03 权限呼应)
worker_processes auto;              # = CPU 核数,别手写数字
events {
    worker_connections 10240;       # 每个 worker 的连接数(×核数=总连接容量)
}

http {
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    include /etc/nginx/mime.types;          # 扩展名→Content-Type
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    gzip on;                                # 压缩下篇细讲

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;     # 站点从这进来
}

三、server 与 location:流量的分诊台

3.1 server 块:一个"虚拟主机"

nginx 复制代码
# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name www.example.com;     # 按 Host 头分流;多个域名逗号分隔

    root /var/www/myapp;             # 静态根目录
    index index.html;

    location / { try_files $uri $uri/ =404; }
}

多个 server 块共存时:精确 server_name 优先 → 通配符 → 都不中则用 default_server。"改了配置两个域名串了",九成是 server_name/监听没分对。

3.2 location 匹配顺序(必背优先级)

nginx 复制代码
location = /health { return 200 "ok"; }    # ① 精确 =(最高优先)
location ^~ /static/ { ... }               # ② ^~ 前缀匹配后不再查正则
location ~ \.(jpg|png|css|js)$ { ... }     # ③ 正则 ~(区分大小写,按声明顺序取第一个命中)
location ~* \.PHP$ { ... }                 #   正则 ~*(忽略大小写)
location /api/ { ... }                     # ④ 普通前缀(最长匹配优先)
location / { ... }                         # 兜底

一句话记忆:精确 > ^~ > 正则(声明序)> 最长前缀。90% 的"为什么走错了 location"都是正则抢了前缀的戏。

四、反向代理:把 /api 转给后端

生产最小模板(静态 + 动态分流):

nginx 复制代码
# /etc/nginx/sites-available/myapp(完整可用版)
upstream myapp_backend {
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;       # 负载均衡下文展开
}

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

    # 静态资源直接发文件
    location /static/ {
        alias /var/www/myapp/static/;
        expires 7d;                  # 浏览器缓存 7 天
        access_log off;
    }

    # 动态请求全部转给后端
    location /api/ {
        proxy_pass http://myapp_backend;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;         # 三个头是必带三件套
        proxy_set_header X-Real-IP         $remote_addr;  # 后端拿真实客户端 IP
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_connect_timeout 3s;
        proxy_read_timeout    60s;
        proxy_send_timeout    60s;
    }

    location / {
        root /var/www/myapp;
        try_files $uri $uri/ =404;
    }
}

4.1 proxy_pass 的斜杠大坑(事故率第一)

复制代码
location /api/ {
    proxy_pass http://backend;          # 不带路径:原样拼接 → /api/users
    proxy_pass http://backend/;         # 带斜杠:/api/ 被替换 → /users
    proxy_pass http://backend/v2/;      # → /v2/users
}

带不带路径,转发的 URI 截然不同 。后端路由设计成"带 /api 前缀"就用不带斜杠写法,反之带斜杠。上线前 tail -f 后端访问日志确认 URI 是预期形状。

4.2 三件套头的意义

  • X-Real-IP / X-Forwarded-For:不加它们,后端看到的客户端 IP 永远是 Nginx 机器------日志统计、风控、限频全部失真;
  • 应用侧信任链要注意:X-Forwarded-For 可被伪造,取第一个 IP 前先确认前面只有可信代理。

五、负载均衡:upstream 四种策略

nginx 复制代码
upstream backend {
    # ① 轮询(默认)
    server 192.168.1.11:8080;
    # ② 加权:机器强的多干活
    server 192.168.1.12:8080 weight=3;
    # ③ ip_hash:同一客户端固定落一台(有状态会话的偷懒方案,扩缩容不友好,慎用)
    # ip_hash;
    # ④ least_conn:转给连接最少的(长短请求混合场景表现好)
    # least_conn;

    # 被动健康检查:连不上/超时 3 次标记下线 30 秒
    server 192.168.1.13:8080 max_fails=3 fail_timeout=30s;
}

策略选择一句话:无状态服务默认轮询/加权;请求耗时差异大用 least_conn;需要会话粘滞优先在应用层做(Redis session),ip_hash 是下策。

排错高频:502 = 后端根本连不上(S2-02 的三层门:监听地址/防火墙);504 = 连上但后端处理超时------502 查部署,504 查性能。

六、HTTPS:Let's Encrypt 一条龙

bash 复制代码
# ① 放行 80/443(云安全组 + ufw,S2-03 流程)
# ② DNS 解析 A 记录指到本机公网 IP
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d www.example.com -d example.com
# certbot 自动改配置加 443/跳转/续期 systemd timer(S1-08 知识闭环)

sudo systemctl list-timers | grep certbot    # 确认自动续期任务在
sudo certbot renew --dry-run                 # 续期演练

certbot 改造后的 server 块长这样(手动部署也照这个抄):

nginx 复制代码
server {
    listen 443 ssl http2;
    server_name www.example.com;
    ssl_certificate     /etc/letsencrypt/live/www.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    # ......location 全部同前
}
server {
    listen 80;
    server_name www.example.com;
    return 301 https://$host$request_uri;   # HTTP 一律跳 HTTPS
}

🚨 自签证书排错:curl -k 能通、浏览器警告------这是正常的(缺 CA 信任);生产别用自签,内网用私有 CA 签发(Harbor 那篇 S5-06 同款问题)。


七、综合实战 + 验收

拓扑 :192.168.1.10 = Nginx;.11/.12 = 两个 Python 后端(python3 -m http.server 8080 模拟)。

bash 复制代码
# ① 后端各起一个,内容不同以区分(模拟两个实例)
# .11 上: cd /tmp/a && python3 -m http.server 8080
# .12 上: cd /tmp/b && python3 -m http.server 8080

# ② Nginx 配 upstream + location /api/(上文模板),nginx -t && reload

# ③ 验证负载均衡:连续请求,应看到两个后端轮流响应
for i in $(seq 6); do curl -s http://192.168.1.10/api/ | head -1; done

# ④ 验证健康摘除:停掉 .11 的服务,30 秒内请求全落到 .12,无 502
# ⑤ 上 HTTPS(有域名时),验证跳转与评级

验收标准:① 独立配出"静态直出 + 动态反代 + 双后端负载"的完整站点;② 能秒判 502/504 的排查方向;③ 能说清 location 四级匹配顺序和 proxy_pass 斜杠差异。


八、🚨 生产环境避坑清单

# 坑 后果 正确姿势
1 proxy_pass 斜杠随手写 后端 URI 神秘 404 想清"带不带前缀",看后端日志验证
2 不带 X-Real-IP 三件套 后端日志全是代理 IP 模板固化三行头
3 改配置不 nginx -t 直接 reload reload 失败或带病运行 t 通过再 reload
4 worker_connections 默认值上高并发 连接耗尽报 503 events 里调大 + ulimit -n 同步放开
5 后端服务监听 127.0.0.1 Nginx 反代 502(S2-01 经典) 后端监听 0.0.0.0 或内网 IP
6 静态目录权限没给 www-data 403(S1-03 权限链路) namei -l 查全链路再 chown
7 证书只配了新域名忘了旧域名跳转 老链接 404/报证书错 旧域名 301 到新域名
8 keepalive 到后端没开 每请求新建 TCP,性能砍半 proxy_http_version 1.1 + upstream keepalive(进阶)

九、一句话总结

Nginx 的本质是"流量分诊台":server 按 Host 分、location 按 URI 分、upstream 按策略分------配上 nginx -t + reload 的习惯,它就是你站点的第一道闸门。

💬 互动

你踩过 proxy_pass 斜杠的坑吗?或者 502 排查半天最后发现后端监听 127.0.0.1?评论区对个暗号。

下一篇预告:《S3-04 Nginx 进阶:限流、缓存、rewrite 与日志分析调优》------扛住流量之后,教你的 Nginx 更聪明:谁刷接口就限谁,热点内容缓存住,日志里挖出 PV/UV。

相关推荐
木头左12 小时前
【Nginx】内网服务源 IP 白名单实战:动态域名解析放行网段 + 端口接管零改造
运维·nginx·白名单·反向代理
skywalk816314 小时前
把 去也网站 从 Ubuntu 搬到 FreeBSD:一次 Service Jail + nginx 的部署实录
linux·运维·nginx·ubuntu·freebsd
没差c21 小时前
winsw将jar、nginx等注册为Windows服务
windows·nginx·jar
FungLeo1 天前
成为全栈·基础补充·域名、DNS 与 HTTPS 证书
https·网络基础·网站部署·tls证书·成为全栈·域名 dns
Lsetea3 天前
Docker更新SSL证书后容器仍读旧文件:单文件挂载与目录挂载排查
运维·nginx·docker·https·ssl证书
2501_916008894 天前
iPhone 设备信息查看,用 KeyMob 看型号、序列号、电池健康和 UDID
android·ios·小程序·https·uni-app·iphone·webview
未来之窗软件服务5 天前
WAF负载均衡+蜜罐混淆安全体系-东方仙盟
运维·安全·负载均衡·仙盟创梦ide·东方仙盟·阿雪技术观·网关开发
Linux-lucky5 天前
46-Linux学习之旅之LVS负载均衡与keepalived高可用
linux·运维·学习·ubuntu·负载均衡·lvs
枫叶轻语5 天前
【Nginx 从入门到实战 09】前后端统一入口:部署页面与接口的完整配置
nginx·全栈