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。