Nginx 基础学习笔记

文章目录

  • [Nginx 基础学习笔记](#Nginx 基础学习笔记)
    • 写在前面:这份笔记怎么用
    • [一、Nginx 简介](#一、Nginx 简介)
      • [1.1 定义](#1.1 定义)
      • [1.2 常见 Web 服务器对比](#1.2 常见 Web 服务器对比)
      • [1.3 Nginx 优势](#1.3 Nginx 优势)
        • [1.3.1 master-worker 进程模型与请求处理流程](#1.3.1 master-worker 进程模型与请求处理流程)
      • [1.4 核心组成与常用功能](#1.4 核心组成与常用功能)
    • 二、源码安装与升级
      • [2.1 环境准备(Rocky/CentOS 系)](#2.1 环境准备(Rocky/CentOS 系))
      • [2.2 源码编译安装](#2.2 源码编译安装)
      • [2.3 目录结构](#2.3 目录结构)
      • [2.4 启动与排错](#2.4 启动与排错)
      • [2.5 进程模型与信号控制](#2.5 进程模型与信号控制)
      • [2.6 版本升级与新增模块](#2.6 版本升级与新增模块)
      • [2.7 核心配置文件结构](#2.7 核心配置文件结构)
    • 三、静态资源部署
      • [3.1 静态资源概念](#3.1 静态资源概念)
      • [3.2 server 配置基础](#3.2 server 配置基础)
      • [3.3 server_name 匹配](#3.3 server_name 匹配)
      • [3.4 location 匹配优先级(高频考点)](#3.4 location 匹配优先级(高频考点))
      • [3.5 root / alias(高频易混)](#3.5 root / alias(高频易混))
      • [3.6 index 与 error_page](#3.6 index 与 error_page)
      • [3.7 MIME 类型(default_type 相关)](#3.7 MIME 类型(default_type 相关))
      • [3.8 传输优化(sendfile / tcp_nopush / tcp_nodelay)](#3.8 传输优化(sendfile / tcp_nopush / tcp_nodelay))
      • [3.9 gzip 压缩](#3.9 gzip 压缩)
      • [3.10 浏览器缓存(强缓存 / 协商缓存)](#3.10 浏览器缓存(强缓存 / 协商缓存))
      • [3.11 跨域 CORS(同源策略)](#3.11 跨域 CORS(同源策略))
      • [3.12 防盗链 valid_referers](#3.12 防盗链 valid_referers)
      • [3.13 rewrite 地址重写](#3.13 rewrite 地址重写)
      • [3.14 URL 组成(请求报文里)](#3.14 URL 组成(请求报文里))
    • 四、代理
      • [4.1 正向代理 vs 反向代理](#4.1 正向代理 vs 反向代理)
      • [4.2 正向代理配置](#4.2 正向代理配置)
      • [4.3 反向代理配置](#4.3 反向代理配置)
      • [4.4 安全隔离](#4.4 安全隔离)
    • [五、HTTPS 与 SSL](#五、HTTPS 与 SSL)
      • [5.1 HTTP vs HTTPS](#5.1 HTTP vs HTTPS)
      • [5.2 自签证书(一键生成,2048 位)](#5.2 自签证书(一键生成,2048 位))
      • [5.3 HTTPS server 完整配置](#5.3 HTTPS server 完整配置)
      • [5.4 HTTP 强制跳转 HTTPS](#5.4 HTTP 强制跳转 HTTPS)
      • [5.5 HTTPS 常见报错排查表](#5.5 HTTPS 常见报错排查表)
    • 六、负载均衡
      • [6.1 为什么需要负载均衡](#6.1 为什么需要负载均衡)
      • [6.2 七层 vs 四层负载均衡](#6.2 七层 vs 四层负载均衡)
      • [6.3 upstream 配置(7 层负载均衡)](#6.3 upstream 配置(7 层负载均衡))
      • [6.4 负载均衡算法一览](#6.4 负载均衡算法一览)
      • [6.5 四层负载均衡(stream 模块,用的少)](#6.5 四层负载均衡(stream 模块,用的少))
      • [6.6 高可用(keepalived)------ 了解概念即可](#6.6 高可用(keepalived)—— 了解概念即可)
      • [6.7 动静分离](#6.7 动静分离)
      • [6.8 JMeter 压测验证负载均衡(实战)](#6.8 JMeter 压测验证负载均衡(实战))
    • 七、开发高频避坑汇总
      • [7.1 排查清单(20 条)](#7.1 排查清单(20 条))
      • [7.2 三条通用排查心法](#7.2 三条通用排查心法)

Nginx 基础学习笔记

TL;DR

  • Nginx 扛高并发的底牌是 epoll IO 多路复用 + master-worker 多进程模型:master 只管配置和信号,worker 抢连接干活。
  • 源码编译必须全量带参数,增量加模块时把旧参数原样抄上再追加,否则 ssl/gzip 等旧模块全丢。
  • location 优先级:= > ^~ > 正则(~ / ~*)> 普通前缀(取最长)。
  • root 是路径拼接 ,alias 是前缀替换,两者别混用。
  • 改完配置先 nginx -t 检查语法,再 nginx -s reload 重载,不 reload 不生效。

写在前面:这份笔记怎么用

这份笔记不是官方文档的搬运,而是把「课堂上学到的原理」和「真机上一次又一次踩坑」揉在一起整理出来的。写它的初衷很简单:Nginx 的知识点零散、配置项多、坑又隐蔽 ,如果只按官方手册的顺序读,很容易「看得懂每个指令,却配不出一套能跑的配置」。所以这里换了个组织方式------按 Nginx 实际承担的作用来分章,你遇到什么问题,就翻对应那一章。

内容组织逻辑

章节 解决的问题 你会得到什么
一、Nginx 简介 Nginx 到底是什么、凭什么比 Apache 快 建立整体认知,面试能讲清楚
二、源码安装与升级 怎么装、怎么启动、怎么平滑升级 一套可复现的安装 + 排错流程
三、静态资源部署 怎么把网页、图片、JS/CSS 正确发出去 server/location/缓存/压缩/防盗链全套配置
四、代理 正向代理和反向代理到底差在哪 两种代理的配置模板与适用场景
五、HTTPS 与 SSL 怎么让站点跑在 https 上 自签证书 + SSL 配置 + 常见报错
六、负载均衡 一台扛不住时怎么横向扩展 upstream 配置、算法选型、JMeter 验证
七、开发高频避坑汇总 前面踩过的坑集中复盘 20 条可直接对照排查的清单

阅读建议

  • 零基础读者:按章节顺序读,第一章建立概念,第二章跟着敲一遍安装命令,后面每章都动手配一次,比只看不练强十倍。
  • 有基础的读者:直接跳到你要用的那一章,比如只做静态站点就看第三章,只做反向代理就看第四章;遇到报错再回第七章对照。
  • 准备面试的读者:重点看每章的「高频考点」「高频易混」标注,以及表格里的对比项,这些是最容易被追问的地方。

关于格式约定

  • 全文尽量用表格承载对比类知识(如 root vs alias、正向 vs 反向代理),比大段文字更容易速查;
  • 命令和配置统一放在代码块里,可直接复制执行 ,路径以源码安装的默认路径 /usr/local/nginx 为准;
  • 带 > 的引用块是实战教训和踩坑记录,这些内容官方文档里通常没有,但恰恰是最容易卡住人的地方;
  • 文中出现的 IP(如 192.168.228.128)、域名(如 www.jidai.com)都是实验环境示例,实际使用时替换成你自己的即可。

一句话总结:把这份笔记当成「Nginx 使用手册 + 排错字典」,先通读建立框架,再按需查阅细节,最后一定要在虚拟机上把配置跑一遍------Nginx 这门手艺,看会不算会,配通才算会。


一、Nginx 简介

1.1 定义

概念 说明
Nginx C 语言编写、开源、高性能的 HTTP 服务器和反向代理服务器;同时可作为 POP3/SMTP/IMAP 邮件代理服务器
POP3 邮局协议版本 3(收邮件)
SMTP 简单邮件传输协议(发邮件)
IMAP 交互式邮件存取协议(收邮件,功能更强)

1.2 常见 Web 服务器对比

服务器 特点
IIS 微软出品,性能一般
Tomcat Java 专用、重量级,静态资源、高并发弱,本质是 Java Web 容器
Apache 老牌,并发模型老旧
Lighttpd 轻量高性能,国外使用多,国内资料少
Nginx 高并发、配置简洁、模块化、热部署、BSD 协议商用免费

1.3 Nginx 优势

  • 高并发、速度快,基于 IO 多路复用 epoll
  • 配置简洁,模块化,扩展性好
  • 多进程模型:Master 进程 + Worker 进程,Master 管理 Worker
  • 热部署:不停服务,直接升级 Nginx
  • 衍生版本:OpenResty(Nginx+Lua)、Tengine(淘宝)
1.3.1 master-worker 进程模型与请求处理流程

#mermaid-svg-MbDPdbdZVrebt9Cy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MbDPdbdZVrebt9Cy .error-icon{fill:#552222;}#mermaid-svg-MbDPdbdZVrebt9Cy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MbDPdbdZVrebt9Cy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MbDPdbdZVrebt9Cy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MbDPdbdZVrebt9Cy .marker.cross{stroke:#333333;}#mermaid-svg-MbDPdbdZVrebt9Cy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MbDPdbdZVrebt9Cy p{margin:0;}#mermaid-svg-MbDPdbdZVrebt9Cy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy .cluster-label text{fill:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy .cluster-label span{color:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy .cluster-label span p{background-color:transparent;}#mermaid-svg-MbDPdbdZVrebt9Cy .label text,#mermaid-svg-MbDPdbdZVrebt9Cy span{fill:#333;color:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy .node rect,#mermaid-svg-MbDPdbdZVrebt9Cy .node circle,#mermaid-svg-MbDPdbdZVrebt9Cy .node ellipse,#mermaid-svg-MbDPdbdZVrebt9Cy .node polygon,#mermaid-svg-MbDPdbdZVrebt9Cy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MbDPdbdZVrebt9Cy .rough-node .label text,#mermaid-svg-MbDPdbdZVrebt9Cy .node .label text,#mermaid-svg-MbDPdbdZVrebt9Cy .image-shape .label,#mermaid-svg-MbDPdbdZVrebt9Cy .icon-shape .label{text-anchor:middle;}#mermaid-svg-MbDPdbdZVrebt9Cy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MbDPdbdZVrebt9Cy .rough-node .label,#mermaid-svg-MbDPdbdZVrebt9Cy .node .label,#mermaid-svg-MbDPdbdZVrebt9Cy .image-shape .label,#mermaid-svg-MbDPdbdZVrebt9Cy .icon-shape .label{text-align:center;}#mermaid-svg-MbDPdbdZVrebt9Cy .node.clickable{cursor:pointer;}#mermaid-svg-MbDPdbdZVrebt9Cy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MbDPdbdZVrebt9Cy .arrowheadPath{fill:#333333;}#mermaid-svg-MbDPdbdZVrebt9Cy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MbDPdbdZVrebt9Cy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MbDPdbdZVrebt9Cy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MbDPdbdZVrebt9Cy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MbDPdbdZVrebt9Cy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MbDPdbdZVrebt9Cy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MbDPdbdZVrebt9Cy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MbDPdbdZVrebt9Cy .cluster text{fill:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy .cluster span{color:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MbDPdbdZVrebt9Cy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MbDPdbdZVrebt9Cy rect.text{fill:none;stroke-width:0;}#mermaid-svg-MbDPdbdZVrebt9Cy .icon-shape,#mermaid-svg-MbDPdbdZVrebt9Cy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MbDPdbdZVrebt9Cy .icon-shape p,#mermaid-svg-MbDPdbdZVrebt9Cy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MbDPdbdZVrebt9Cy .icon-shape .label rect,#mermaid-svg-MbDPdbdZVrebt9Cy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MbDPdbdZVrebt9Cy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MbDPdbdZVrebt9Cy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MbDPdbdZVrebt9Cy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
是
否
reload:重开 worker
启动 nginx(读取 nginx.conf)
master 进程
fork 出多个 worker 进程

数量 = worker_processes
监听信号:reload / quit / USR2
worker 通过 epoll

监听 listen socket(80/443)
有新连接到达?
accept 连接

(accept_mutex 控制争抢)
解析 HTTP 请求

匹配 server / location
处理请求

静态资源 / 反向代理 / 负载均衡
写回响应

记录 access.log
keep-alive 连接?
关闭连接

职责分工:master 进程不处理请求,只负责读取并校验配置、fork 与管理 worker、接收信号(reload / quit / USR2 平滑升级);worker 进程才是真正干活的,各自通过 epoll 多路复用监听同一个 listen socket,谁抢到连接谁处理,互不阻塞。

并发上限 :worker_processes 决定 worker 数量(一般设为 CPU 核数),worker_connections 决定单个 worker 能同时持有的连接数,两者相乘即为理论最大并发连接数(如 4 × 1024 = 4096)。注意每个反向代理请求会同时占用客户端连接和后端连接,实际可用并发约为该值的一半。

1.4 核心组成与常用功能

核心组成 作用
nginx 二进制可执行程序
nginx.conf 主配置文件
error.log 错误日志
access.log 访问日志
常用功能 对应章节
静态资源部署 第三章
反向代理 / 正向代理 第四章
HTTPS 第五章
负载均衡(7 层 + 4 层) 第六章

二、源码安装与升级

2.1 环境准备(Rocky/CentOS 系)

① 关闭 SELinux

bash 复制代码
sestatus                 # 查看状态
getenforce               # 查看当前模式(Enforcing / Permissive / Disabled)
vim /etc/selinux/config  # 修改配置,SELINUX=disabled(永久关闭)
模式 效果 建议
enforcing 强制拦截,nginx 可能被静默拒绝 生产保留
permissive 只记录警告不拦截 学习期推荐
disabled 彻底关闭 学习期可接受

临时切换:setenforce 0(permissive)/ setenforce 1(enforcing),重启失效。

② 依赖包一键安装

bash 复制代码
# gcc编译器、pcre(正则rewrite)、zlib(压缩)、openssl(https加密)
yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
rpm -qa pcre pcre-devel openssl openssl-devel   # 校验

③ 防火墙放行端口(firewalld)

bash 复制代码
firewall-cmd --list-all                       # 查看当前放行
firewall-cmd --permanent --add-port=80/tcp    # 永久放行 80
firewall-cmd --reload                         # 必须重载才生效
命令 作用
firewall-cmd --state 防火墙是否运行
firewall-cmd --list-all 查看所有放行信息
firewall-cmd --permanent --add-port=80/tcp 永久放行端口
firewall-cmd --permanent --remove-port=80/tcp 删除放行
firewall-cmd --reload 重载配置,永久改动后必做

铁律:加了 --permanent 必须 --reload;不加 permanent 是临时放行,重启失效。

实战教训:后端机曾因防火墙只放行了 22,导致负载均衡池端口全被拒,JMeter 100% 超时。

2.2 源码编译安装

安装流程:

  1. 下载官网压缩包(nginx.org/download),解压到 /root/nginx/core
  2. ./configure:环境检测 + 生成编译脚本(可追加自定义编译参数)
  3. make && make install:编译 + 安装
  4. 启动:进入 sbin 目录 ./nginx
  5. 防火墙放行 80 端口
  6. 查看信息:./nginx -V

默认安装路径:/usr/local/nginx

./configure 的作用:

职责 说明
检测系统环境 检查 gcc、PCRE、zlib、OpenSSL 是否齐全,缺了报错
收集编译选项 读取 --prefix、--with-xxx 等参数
生成 Makefile 把检测结果+选项写进 Makefile,make 照图纸编译

完整编译参数:

bash 复制代码
./configure \
--prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module \
--with-stream

三个大坑:

  1. 多行写法每行末尾 \ 后不留空格 ,最后一行不加 \,否则报 --sbin-path=... 没有那个文件或目录
  2. 增量编译必须把之前所有参数全量带上,再追加新参数 (如 --with-stream),否则新二进制会丢掉 ssl/gzip 等旧模块
  3. --with-http_ssl_module 默认不开启,想用 HTTPS 必须自己加

yum 安装 vs 源码编译安装:

对比 yum 安装 源码编译安装
速度 简单快速 较慢
编译参数 固定 可自定义
第三方模块 难扩展 灵活增加
适用 快速部署 生产定制

卸载旧源码版:./nginx -s stop → rm -rf /usr/local/nginx → make clean → 重新 configure。

2.3 目录结构

bash 复制代码
yum install -y tree
tree /usr/local/nginx
复制代码
/usr/local/nginx/
├── conf/     # 配置文件(nginx.conf 主配置、mime.types 媒体类型表;.default 是原文件副本)
├── html/     # 默认网页目录(index.html、50x.html)
├── logs/     # 日志目录(access.log、error.log、nginx.pid)
└── sbin/     # 可执行文件(nginx)
目录/文件 说明
conf/ nginx.conf 主配置;mime.types 媒体类型映射表
html/ index.html 成功默认页;50x.html 错误页
logs/ access.log 访问日志、error.log 错误日志、nginx.pid 主进程 PID
sbin/ 二进制可执行文件 nginx

常用查看命令: whereis nginx(找安装位置)、./nginx -v(版本)、./nginx -V(版本+编译参数)

2.4 启动与排错

标准启动姿势:

bash 复制代码
cd /usr/local/nginx/sbin
./nginx -t    # ① 检查配置语法(syntax is ok)
./nginx       # ② 启动

标准流程:先 ps -ef | grep nginx 看有没有在跑 → 没在跑才 ./nginx;改完配置 ./nginx -s reload,不要重复启动。

启动报错:bind() failed (98: Address already in use)

占用者 处理
就是 nginx(master+worker) 已在运行,直接访问验证,别重复启动
其他服务(httpd 等) systemctl stop httpd 再启动
不想停别人的服务 改 nginx.conf 的 listen 8080;

排查命令:ss -tlnp | grep :80、ps -ef | grep nginx

访问不通排查顺序:

排查项 命令
防火墙 firewall-cmd --list-all
SELinux getenforce
nginx 进程 `ps -ef
IP 漂移 虚拟机 DHCP 会换 IP,重启后 ip addr 确认

2.5 进程模型与信号控制

进程 作用
master 主进程:管理 worker、读取配置、处理信号
worker 工作进程:真正处理请求,数量由 worker_processes 控制
bash 复制代码
kill -信号 `cat /usr/local/nginx/logs/nginx.pid`
信号 等价命令 作用
TERM/INT ./nginx -s stop 快速停止
QUIT ./nginx -s quit 优雅停止(处理完当前请求再退)
HUP ./nginx -s reload 重载配置,会重开 worker
USR1 ./nginx -s reopen 重新打开日志文件(日志切割)
USR2 --- 平滑升级(启动新 master,新旧并存)
WINCH --- 优雅关闭旧 worker(配合 USR2)

命令行参数:

参数 作用
-v 只查看版本号
-V 版本 + 各种编译信息
-t 检查配置语法
-T 同 -t,且输出完整配置信息
-s signal stop / quit / reopen(≈USR1)/ reload(≈HUP)
-c 指定配置文件路径
-g 指定参数配置(少用)

2.6 版本升级与新增模块

平滑升级(核心命令序列):

升级原理:USR2 启动新 master,新旧并存;确认新版正常后 QUIT 旧 master。

bash 复制代码
# ① 备份旧二进制(不要直接 cp 覆盖!会报 ETXTBSY: 文本文件忙)
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old

# ② 拷贝新编译的二进制
cp /root/nginx/core/nginx-1.28.3/objs/nginx /usr/local/nginx/sbin/nginx

# ③ 语法检查 + 启动新 master
nginx -t
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
sleep 1

# ④ 确认新版正常后,关掉旧 master
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

# ⑤ 验证
nginx -V | grep ssl
两个 PID 文件 内容
nginx.pid 新 master 的 PID(USR2 后写入)
nginx.pid.oldbin 旧 master 的 PID

关键经验:

  • ETXTBSY(文本文件忙) = 旧 nginx 还在运行,文件被占用,直接 cp 覆盖会失败。解法就是 mv 改名 → cp 新文件 → USR2 → QUIT
  • QUIT 前务必确认新版正常(nginx -V 有新模块、curl 有响应);新版有问题别 QUIT,kill -HUP \cat nginx.pid.oldbin`` 可回滚
  • make upgrade 只做信号切换,不做编译和安装,跳过 make 直接 upgrade 等于没升

新增模块示例(--with-http_ssl_module / --with-stream):

bash 复制代码
cd /root/nginx/core/nginx-源码目录
make clean                       # 清旧编译产物
./configure <上面全量参数> --with-stream   # 全量参数 + 新模块!
make
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp objs/nginx /usr/local/nginx/sbin/nginx
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
sleep 1
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
nginx -V | grep stream           # 验证模块已编译

2.7 核心配置文件结构

配置位置:/usr/local/nginx/conf/nginx.conf

复制代码
nginx.conf
├── 全局块(events 和 http 以外的内容)
├── events 块(网络连接相关)
└── http 块
    └── server 块(可多个)
        └── location 块(一个 server 可多个)

全局块:

指令 作用
user user [group] 运行 worker 的用户;不指定 group 默认等于用户名,默认 nobody;与 Linux 用户有关,利于权限控制
`master_process on off`
worker_processes number 工作进程数量,用于并发处理请求
`daemon on off`
pid 路径 master 进程 PID 文件路径
error_log 路径 错误日志路径
include file 引入其他配置文件

events 块:

指令 作用
`accept_mutex on off`
`multi_accept on off`
worker_connections number 单个 worker 的最大连接数
use epoll 事件驱动模型,建议 epoll

http 块:

指令 作用
include mime.types 媒体类型映射表
default_type application/octet-stream 兜底返回格式(二进制流)。常用:text/plain、text/html、application/json
access_log path [format] 访问日志位置和名称
log_format name 格式 日志输出格式,name 与 access_log 的 format 相同
`sendfile on off`
keepalive_timeout time 长连接超时时间
keepalive_requests number 一个 keep-alive 连接可使用的请求次数

一个 http 可有多个 server,一个 server 可有多个 location。access_log 配置遵循就近原则 (location 覆盖 server)。

每次改配置:./nginx -t 检查 → ./nginx -s reload 重载。


三、静态资源部署

3.1 静态资源概念

类型 内容
静态资源 html、css、js、图片、视频等不变的文件
动态资源 需要后端程序生成(JSP、接口返回等),一般部署在 Tomcat

3.2 server 配置基础

nginx 复制代码
server {
    listen       80;
    server_name  localhost;
    location / {
        root   html;
        index  index.html index.htm;
    }
}

listen 语法:

写法 含义
listen 127.0.0.1:8000; 指定 IP+端口
listen 127.0.0.1; 指定 IP 的所有端口
listen 8000; 指定端口(所有 IP)
listen *:8000; 同 listen 8000,* 代表所有 IPv4
listen 80 default_server; 指定默认服务器(端口匹配但 server_name 都没命中时兜底)

当 IP 没匹配到任何 server_name 时,匹配到第一个 server 模块 ;可通过 default_server 显式指定。

3.3 server_name 匹配

方式 写法 说明
精确匹配 server_name www.jidai.com; 最常用,可空格隔开多个
通配符 server_name *.jidai.com; * 只能在域名首/尾部,不能放中间(www.*.com 不行)
正则匹配 server_name ~^www\.\w+\.com; 以 ~ 开头,用正则表达式

匹配顺序:

复制代码
精确匹配 → 通配符开头匹配 → 通配符结尾匹配 → 正则匹配 → default_server → 找不到则 404/第一个 server

实战:域名解析靠 /etc/hosts(Windows: C:\Windows\System32\drivers\etc)。非管理员改 hosts 会被 UAC 拒绝;1.1.1.1 是公网 Cloudflare 地址,浏览器直访到不了本机,必须 hosts 映射。

3.4 location 匹配优先级(高频考点)

复制代码
= 精确匹配  >  ^~ 前缀匹配(命中即停)  >  正则(~ 区分大小写 / ~* 不区分)  >  普通前缀(取最长)
写法 示例 规则
不带符号 location /abc 前缀匹配:/abc、/abcd、/abcdf 都能访问
= location = /abc 精确匹配,必须完全相等(/abc/ 也不行),优先级最高
~ location ~ \.png$ 正则匹配,区分大小写
~* `location ~* .(png jpg)$`
^~ location ^~ /server 普通前缀命中后不再向后匹配,可防正则块抢走

实战教训:

  • 防盗链正则块 ~*\.(html|js|css|png)$ 会抢掉前缀块的请求 → 用 ^~ /server 或调整正则
  • 正则 location 一旦匹配就覆盖普通前缀(取最长规则失效)

3.5 root / alias(高频易混)

指令 拼接规则 示例
root root 路径 + location 路径(最上层目录) root html; + location /images → html/images/...
alias 替换 location 路径(目录别名) alias /data/img; + location /images → /data/img/...

若 location 以 / 结尾,alias 也必须以 / 结尾;root 无此要求。

3.6 index 与 error_page

nginx 复制代码
location / {
    root   html;
    index  index.html index.htm;   # 可多个,从左到右匹配
}
error_page   500 502 503 504  /50x.html;
location = /50x.html {
    root   html;
}
关键点 说明
index 管目录 访问目录时自动找默认文件
error_page 管出错 状态码 → 内部重定向到具体 URI,不走 index 逻辑
为什么用 = 精确匹配优先级最高,保证内部跳转不被 location / 干扰
改状态码 error_page 500 502 503 504 =200 /50x.html; 把响应码改成 200
跳外链 error_page 404 http://www.bilibili.com; 重定向到外部地址
命名 location error_page 404 @jump_to_error; + location @jump_to_error

3.7 MIME 类型(default_type 相关)

default_type 是兜底值 :请求的文件扩展名在 mime.types 里找不到对应类型时才用它。include mime.types; 之后绝大多数常见类型已自动映射。

MIME 类型 对应文件 说明
text/html .html .htm 网页
text/plain .txt 纯文本
text/css .css 样式
text/javascript .js JS
application/json .json JSON 接口返回最常用
image/png / image/jpeg / image/gif .png .jpg .jpeg .gif 图片
video/mp4 .mp4 视频
application/pdf / application/zip .pdf .zip 文件下载
application/octet-stream 任意 默认兜底,浏览器会直接下载而不是打开
font/woff2 .woff2 字体(前端部署常踩坑)

3.8 传输优化(sendfile / tcp_nopush / tcp_nodelay)

指令 作用 前提
sendfile on 高效文件传输,减少用户态↔内核态两次拷贝和进程切换 ---
tcp_nopush on 数据先攒到缓冲区,满了再一次性发,提升网络包传输效率 必须在 sendfile on 下生效
tcp_nodelay on 有数据就发,提高实时性 必须在 keep-alive 开启下生效

tcp_nopush 是"攒够再发"(吞吐优先),tcp_nodelay 是"有就发"(实时优先),两者可同时开。

3.9 gzip 压缩

nginx 复制代码
gzip on;                     # 开启压缩
gzip_types text/html text/css application/javascript;  # 压缩哪些类型
gzip_comp_level 1;           # 1-9:1 压缩最低最快,9 最高最慢,默认 1
gzip_vary on;                # 响应头加 Vary: Accept-Encoding
gzip_min_length 1024;        # 小于该字节数不压缩(默认 20 字节)
gzip_buffers 4 16k;          # 压缩缓存数量和大小
gzip_disable "MSIE [1-6]\.(.*?)$";  # 匹配 User-Agent 的客户端不压缩
易混点 说明
gzip 与 gzip_static 不互斥;gzip_static 直接发预压缩的 .gz 文件
gzip_min_length 默认 20 字节,太小压了没意义
sendfile 与 gzip 的矛盾 sendfile 数据不进应用程序,但压缩需要进应用 → 两者同开时 nginx 自动处理

3.10 浏览器缓存(强缓存 / 协商缓存)

复制代码
用户发请求
   ↓
① 本地有缓存吗?
   ├─ 没有 → 直接请求服务器,拿新数据存缓存
   └─ 有 ↓
② 缓存过期了吗?(强缓存)
   ├─ 没过期 → 直接用本地缓存,不发请求 ← 强缓存
   └─ 过期了 ↓
③ 带 ETag / Last-Modified 问服务器(协商缓存)
   ├─ 服务器说 304(没变) → 用本地缓存
   └─ 服务器说 200(变了) → 拿新数据,更新缓存
缓存类型 相关头 机制
强缓存 Expires(过期时间)、Cache-Control: max-age(秒) 没过期直接用本地,不发请求
协商缓存 Last-Modified(最后修改时间)、ETag(实体标签) 每次带条件问服务器,304 就用本地

expires 指令:

写法 效果
expires 时间(正整数/0) Cache-Control: max-age=time
expires -1(负数) Cache-Control: no-cache(全走协商缓存)
expires epoch Expires=1970,Cache-Control: no-cache
expires max Cache-Control: max-age=10年
expires off 默认,不设置缓存头

实战教训:配置了防盗链/新规则但浏览器还显示旧图 = 浏览器缓存,强刷 Ctrl+F5 或用 expires -1 验证。

3.11 跨域 CORS(同源策略)

同源策略:协议 + IP(域名) + 端口 三者全部相同才叫同源,A 页面异步请求 B 服务器数据 = 跨域。

nginx 复制代码
location /getUser {
    default_type application/json;
    add_header Access-Control-Allow-Origin *;              # 允许来源:* 或指定 http://192.168.228.128
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
    return 200 '{"id":1,"name":"jidai","age":18}';
}
坑 说明
Access-Control-Allow-Origin http:192.168.228.128 少个斜杠 http: 应为 http://,浏览器不识别
指定来源写法 add_header Access-Control-Allow-Origin http://192.168.228.128;

3.12 防盗链 valid_referers

原理 :HTTP 头 Referer 告诉服务器"这个请求是从哪个页面链接过来的"。nginx 把 Referer 和 valid_referers 匹配,匹配不上就把 $invalid_referer 置 1。

nginx 复制代码
location ~*\.(html|js|css|png)$ {
    valid_referers none blocked www.bilibili.com;   # 白名单
    if ($invalid_referer) {
        return 403;
    }
    expires max;
}
参数 含义
none 没有 Referer 头也允许(直接输 URL 访问)
blocked Referer 被防火墙/代理过滤后也允许
www.bilibili.com 白名单域名(可多个),支持 *. 通配符和正则

高频坑:

  • none 和 blocked 必须一起写 ,单独写 none 会报错:the "none" or "blocked" referers are specified ... without any valid referer
  • 正则 location 抢前缀块会导致防盗链不生效(location 优先级问题)
  • Referer 什么时候会带上 :页面里的 img/script/link 等资源请求会带(来源是当前页面 URL);地址栏直接输入、或超链接跳转不带 Referer(属 none)
  • 浏览器缓存也会让"改了配置还看到图"

3.13 rewrite 地址重写

依赖 pcre(正则库),由 ngx_http_rewrite_module 解析。

nginx 复制代码
rewrite ^/rewrite/url\w*$  https://www.bilibili.com;      # 跳外网
rewrite ^/rewrite/(testbreak)\w*$  /$1 last;              # 捕获组 + last
rewrite ^/rewrite/(testreturn)\w*$  /$1 last;

核心指令:

指令 作用
set $key value; 设置变量(不能和 nginx 预设全局变量重名)
if (条件) {} 条件判断:~ 区分大小写、~* 不区分;-f 文件存在、-d 目录存在、-e 文件或目录存在、-x 可执行;前面加 ! 取反
break 退出 rewrite,不匹配其他 location,在当前 root 找资源
return code [text/url] 直接返回状态码/重定向;301 永久、302 临时
rewrite regex replacement [flag] 重写规则

flag 四种:

flag 行为
last 匹配后去其他 location 块继续匹配(最常用)
break 停止 rewrite,不换 location,在本 location 的 root 下找文件
redirect 返回 302 临时重定向(浏览器地址栏变化)
permanent 返回 301 永久重定向

应用场景: 域名跳转(www→不带 www)、域名镜像(旧目录跳新目录)、URL 简化(长地址正则转短)、防盗链完善。

实战教训:rewrite 多次失败大多是缺括号/缺斜杠/正则写错 ;~^/rewrite/(testbreak)\w*$ 里捕获组 $1 配合 last 是最常用组合。

3.14 URL 组成(请求报文里)

浏览器地址栏 URL ≠ 请求报文里的 URL:

组成部分 地址栏(你看到的) 请求行里实际发出
协议 http:// ✅ ❌(版本单独写 HTTP/1.1)
主机 192.168.228.128:81 ✅ ❌(放 Host 请求头)
路径 /server/44.html ✅ ✅
参数 ?name=jidai ✅ ✅
锚点 #top ✅ ❌(根本不发,浏览器自留地)
复制代码
实际请求行:GET /server/44.html?name=jidai HTTP/1.1
            Host: 192.168.228.128:81
nginx 变量 含义 对应
$request_uri 请求行里原样(路径+参数,未解码) /server/44.html?name=jidai
$uri nginx 处理后的路径(去参数、可被 rewrite 改) /server/44.html
$args 查询参数(= $query_string) name=jidai
$scheme 协议 http
$host 主机(不带端口) 192.168.228.128

四、代理

4.1 正向代理 vs 反向代理

复制代码
正向代理:客户端 → 代理 → 目标服务器,代表【客户端】,隐藏客户端 IP
反向代理:客户端 → 代理 → 后端多台服务器,代表【服务器】,隐藏后端真实服务器
对比项 正向代理 反向代理
配置方 客户端(浏览器/本机设置) 服务端配置,客户端无感知
代表对象 客户端 后端服务器集群
隐藏对象 客户端 IP 后端服务器 IP
客户端感知 知道代理存在 以为代理就是目标服务器
典型场景 内网出口、梯子 Nginx 负载均衡、统一入口、HTTPS

记忆口诀:正向藏客户端,反向藏服务器。

4.2 正向代理配置

nginx 复制代码
server {
    listen 8090;
    resolver 8.8.8.8;                       # DNS 解析器
    location / {
        proxy_pass http://$host$request_uri;  # 拿客户端请求的 host 和 url
        proxy_set_header Host $host;
    }
}

链路: 客户端在浏览器/系统配置代理 IP+端口 → 请求到代理端 nginx → nginx 拿 Host 和 URL 用 proxy_pass http://$host$request_uri 转发 → 服务端响应原路返回。

4.3 反向代理配置

nginx 复制代码
server {
    listen 80;
    location / {
        proxy_pass http://192.168.56.101;    # 转发到后端
        proxy_set_header username jidai;     # 添加/修改请求头
    }
}
指令 作用
proxy_pass url 转发地址(可带路径、可带变量)
proxy_set_header 字段 值 添加/删除请求头(如 Host、X-Real-IP)
proxy_redirect redirect replacement 修改后端返回的 Location/Refresh 头

实战教训:

  • 后端 IP 写错(192.168 写成 192.128/192.169)→ 502/超时
  • if (!-f $request_filename) 对目录 / 永远"不存在" → 无限 302 死循环,改用 if (!-e ...)

4.4 安全隔离

客户端永远不直接连后端,只连代理(nginx)一个入口;防火墙只开放代理的 80/443,后端全藏内网,客户端根本不知道它们存在。


五、HTTPS 与 SSL

5.1 HTTP vs HTTPS

对比 HTTP HTTPS
传输内容 密码、账号、请求体明文,抓包可见 加密,抓包看到乱码
流量劫持 运营商/中间人可篡改页面(插广告) 篡改即失效
身份验证 无法确认对方是谁 证书验证服务器身份

HTTPS = HTTP + TLS;TLS 是 SSL 3.0 的继任者,网课先讲 SSL,学完不用重学,同一套东西。

5.2 自签证书(一键生成,2048 位)

bash 复制代码
mkdir -p /root/cert
openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout /root/cert/server.key -out /root/cert/server.crt \
  -days 365 -subj "/CN=www.jidai.com"

必须 2048 位!Rocky 9 的 OpenSSL 3 默认安全等级拒绝 1024 位 证书:

SSL_CTX_use_certificate() failed (SSL: error:0A00018F:SSL routines::ee key too small)

5.3 HTTPS server 完整配置

nginx 复制代码
server {
    listen       443 ssl;
    server_name  www.jidai.com;

    # ① 证书与私钥(必须成对,且私钥不能带密码)
    ssl_certificate      /root/cert/server.crt;
    ssl_certificate_key  /root/cert/server.key;

    # ② 协议版本:只留 TLSv1.2 / TLSv1.3,禁用 SSLv3、TLSv1.0、TLSv1.1
    ssl_protocols        TLSv1.2 TLSv1.3;

    # ③ 加密套件:优先服务端套件,剔除匿名和弱算法
    ssl_ciphers          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:HIGH:!aNULL:!MD5:!RC4:!3DES;
    ssl_prefer_server_ciphers  on;

    # ④ 会话复用:减少握手开销,提升 HTTPS 性能
    ssl_session_cache    shared:SSL:10m;   # 10m 约可缓存 4 万个会话
    ssl_session_timeout  10m;
    ssl_session_tickets  on;

    location / {
        root   html;
        index  index.html index.htm;
    }
}
指令 作用 常用值
listen 443 ssl 监听 443 并开启 SSL(ssl 不能漏,否则按明文 HTTP 处理) 443 ssl / 443 ssl http2
ssl_certificate 服务器证书(公钥),含证书链 /root/cert/server.crt
ssl_certificate_key 私钥文件,权限建议 600 /root/cert/server.key
ssl_protocols 允许的 TLS 版本 TLSv1.2 TLSv1.3
ssl_ciphers 加密套件列表,! 表示排除 HIGH:!aNULL:!MD5
ssl_prefer_server_ciphers 以服务端套件顺序为准 on
ssl_session_cache 会话缓存,shared:名称:大小 shared:SSL:10m
ssl_session_timeout 会话缓存有效期 10m

前提:编译时必须带 --with-http_ssl_module,否则 nginx -t 直接报 unknown directive "ssl"。用 nginx -V | grep ssl 确认。

5.4 HTTP 强制跳转 HTTPS

浏览器默认走 80 端口,需要把 http:// 的请求 301 到 https://。两种写法:

写法一:return 301(推荐,性能更好)

nginx 复制代码
server {
    listen       80;
    server_name  www.jidai.com;
    return 301 https://$host$request_uri;   # 保留原路径和参数
}

写法二:rewrite(老写法,功能等价)

nginx 复制代码
server {
    listen       80;
    server_name  www.jidai.com;
    rewrite ^(.*)$ https://$host$request_uri permanent;
}
对比 return 301 rewrite ... permanent
执行阶段 rewrite 阶段直接返回,不再走 location 匹配 需走完 rewrite 流程
性能 略优 略差
可读性 直观 正则需理解
推荐度 ✅ 首选 兼容旧配置

关键点:

  • 用 $host$request_uri 而不是写死域名,能同时兼容多域名和带参数请求;
  • 301 是永久重定向,浏览器会缓存,调试期建议先用 302,确认无误再改 301;
  • 80 和 443 必须是两个独立 server 块,不能写在同一个 server 里。

5.5 HTTPS 常见报错排查表

报错 / 现象 原因 解决命令 / 方法
SSL_CTX_use_PrivateKey() failed (SSL: key values mismatch) 证书与私钥不匹配(用了别的证书对应的 key) 比对模数:`openssl x509 -noout -modulus -in server.crt
unable to load certificate / PEM_read_bio_X509 证书文件格式错误或路径写错 openssl x509 -in server.crt -noout -text 能正常输出即格式正确;检查 ssl_certificate 路径
浏览器提示「证书链不完整」/ 部分设备报不安全 只配了站点证书,没拼中间 CA 合并证书链:cat server.crt intermediate.crt > fullchain.crt,ssl_certificate 指向 fullchain.crt
SSL_ERROR_RX_RECORD_TOO_LONG 用 https:// 访问了一个没开 SSL 的端口 (如 80),或 listen 443 漏写 ssl 确认 listen 443 ssl;;用 curl -I https://域名 验证;80 端口只做跳转
浏览器提示「不安全 / NET::ERR_CERT_AUTHORITY_INVALID」 自签证书不被信任(学习环境正常现象) 点「继续访问」验收;或把 server.crt 导入系统受信任根证书;生产环境换正式 CA 证书
SSL: error:0A00018F:ee key too small 证书密钥位数太低(1024 位),OpenSSL 3 拒绝 重新生成 2048 位:openssl req -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 365 -subj "/CN=www.jidai.com"
no "ssl_certificate" is defined for the "listen ... ssl" 写了 listen 443 ssl 但没配证书 补上 ssl_certificate 与 ssl_certificate_key 两行
unknown directive "ssl" 编译时没加 --with-http_ssl_module `nginx -V
访问 443 超时 / 连接被拒 防火墙没放行 443 firewall-cmd --permanent --add-port=443/tcp && firewall-cmd --reload;`ss -tlnp
curl 报 certificate has expired 证书过期 openssl x509 -in server.crt -noout -dates 查看有效期,重新签发

排查三板斧:nginx -t 看配置语法 → tail -f logs/error.log 看握手错误 → curl -vkI https://域名 看证书链和协议版本。

自签证书下 curl 报 ssl_verify_result=18(self-signed certificate)属正常,加 -k 跳过校验即可。

六、负载均衡

6.1 为什么需要负载均衡

服务器处理并发能力有限、可能宕机。系统扩展两种方式:

扩展方式 思路 代价 上限
纵向扩展(scale up) 一台机器加 CPU/内存 花钱换硬件 受硬件限制
横向扩展(scale out) 加机器多台干活 需要负载均衡器分发 理论上无限

负载均衡器侧重内容一样 (分发到集群),反向代理侧重内容不一样(转发到不同后端)。

6.2 七层 vs 四层负载均衡

概念 在第几层 对应知识
浏览器输 URL、Host 头 7 应用层 HTTP、server_name 匹配
80/443 端口 4 传输层 listen 80、443 ssl
IP 地址 3 网络层 192.168.228.128
nginx 负载均衡 7 层 (HTTP) 按 URL/Host/Cookie 分发,能看到 HTTP 内容
四层负载均衡(如 LVS) 4 层 (TCP/IP) 只按 IP+端口转发,更快但看不到内容

6.3 upstream 配置(7 层负载均衡)

nginx 复制代码
upstream backend {
    server 192.168.56.101:80;
    server 192.168.56.101:8080;
    server 192.168.56.101:5672;
}
server {
    listen 81;
    location / {
        proxy_pass http://backend;
    }
}
upstream server 状态参数 作用
weight=2 权重,默认 1
down 当前 server 不参与负载均衡
backup 预留备份服务器,其他全挂了才上
max_fails + fail_timeout 允许失败次数 + 失败后暂停时间(故障转移)
max_conns 最大连接数

高频坑:upstream 里 server 只能写 IP:端口,不能带路径 !server 192.168.56.101:80/server1; 会报 invalid host in upstream。路径属于 location/proxy_pass 层。

6.4 负载均衡算法一览

算法 配置 分配规则 官方内置? 适用/注意
轮询 (默认) 轮流分发 ✅ 默认、最常用
加权轮询 weight=2 按权重比例分 ✅ 服务器性能不同时
ip_hash ip_hash; 按客户端 IP 哈希,同一 IP 固定同一台 ✅ 会话保持;单机压测 IP 全相同会全打一台,负载均衡失效
least_conn least_conn; 谁连接少分给谁 ✅ 生产推荐,请求耗时不均时
url_hash hash $request_uri; 按 URL 哈希,同一 URL 固定一台 ✅ 缓存命中场景(配 consistent 是一致性哈希)
fair 第三方模块 按后端响应时间,谁快多分谁 ❌ 需编译 用得少,官方有 least_conn 替代

ip_hash 和 url_hash 区别:ip_hash 按客户端 IP(单机压测 IP 全相同会全打一台、NAT 后一堆人共享一个 IP 也没意义);url_hash 按 URL(IP 不同没关系)。

6.5 四层负载均衡(stream 模块,用的少)

方案 类型 特点 适用
LVS 内核态 L4 性能最高,经典方案 大规模高并发
HAProxy 专业 L4/L7 代理 功能全 中小规模讲究
云负载均衡(SLB/NLB) 云厂商托管 免运维 云上主流
nginx stream Web 服务器兼职 配置简单、与 nginx 统一管理 小项目顺带转发端口

LVS 不是中间件 :它是 Linux 内核自带功能(ip_vs 模块),内核态转发所以性能高;配上 ipvsadm 工具配置规则,三大模式:NAT / DR / TUN。

nginx 做 4 层只是"兼职"(stream 块在 main 层,和 http 平级),生产主流是 LVS/HAProxy/云 LB。

nginx 复制代码
stream {
    upstream mysql_pool {
        server 192.168.56.101:3306;
        server 192.168.56.101:3307;
    }
    server {
        listen 33000;
        proxy_pass mysql_pool;
    }
}

6.6 高可用(keepalived)------ 了解概念即可

技术 解决什么 核心机制 类似物
keepalived IP 高可用:主挂了 VIP 漂到备 VRRP 心跳 + VIP 虚拟IP + 主备漂移 ≈ Redis 哨兵(故障切换)
Redis 主从 数据冗余(复制) RDB/AOF 同步 只是"备胎",不会自动切换
Redis 哨兵 自动故障转移 心跳监控 + 选举新主 ≈ keepalived

记忆:"keepalived ≈ Redis 哨兵"(都做故障切换),Redis 主从只是复制数据。 非运维方向了解概念即可。

6.7 动静分离

nginx 复制代码
# 静态资源 → nginx 自己
location ~* \.(html|css|js|png|jpg)$ {
    root html;
    expires max;
}
# 动态请求 → 转发 Tomcat
location / {
    proxy_pass http://192.168.56.101:8080;
}

6.8 JMeter 压测验证负载均衡(实战)

测试目标:压 81 端口(upstream 池),观察请求是否被轮询分发到 80/8080/5672。

JMeter 使用要点:

项 要点
测试计划结构 线程组(nginx) → HTTP请求采样器 → 聚合报告/查看结果树
线程组 200 线程、Ramp-up 1s、循环 1 次
HTTP 请求 协议 http(默认值别写成 tcp,否则 100% 异常)、服务器 IP、端口 81、路径 /

全链路排错顺序(压测失败排查):

层 检查 现象
JMeter 配置 协议是否 http、有没有 HTTP 请求采样器 全异常、平均 21084ms≈连接超时
后端服务 `ps -ef grep nginx` 看后端是否运行
网络 从 Windows 测 后端IP:80(python socket) 防火墙只放行 22 导致 80/8080/5672 全被拒
防火墙 firewall-cmd --list-all 放行后端所有池端口
负载均衡验证 看三台后端 access.log 或响应内容 轮询时应三台都出现请求

实战教训:手动启动的 nginx 重启虚拟机后不会自动启动 ,开机后要手动 /usr/local/nginx/sbin/nginx(或配 systemd 服务)。演示/考试前先确认两台机器的 nginx 都在跑。


七、开发高频避坑汇总

前面六章里,坑是散落在各处的:有的藏在安装步骤的引用块里,有的写在某个配置示例的注释后面。真到线上排查时,往往记不住「这个报错在哪一章见过」。所以这一节把全文出现过的踩坑点集中复盘一遍,整理成一张可直接对照排查的清单表------按「现象 → 原因 → 定位命令 → 解决方式」四列组织,遇到问题先按现象搜表,再照着命令验证。

7.1 排查清单(20 条)

# 现象 原因 定位命令 解决方式
1 启动报 bind() failed (98: Address already in use) 80 端口已被占用(nginx 自己已在跑,或 httpd 等别的服务占着) `ss -tlnp grep :80、ps -ef
2 平滑升级时 cp 报 ETXTBSY: 文本文件忙 旧 nginx 进程还在运行,二进制文件被占用,不能直接覆盖 `ps -ef grep nginx`
3 执行 make upgrade 后版本没变、新模块也没有 make upgrade 只做信号切换,不做编译和安装 nginx -V 看版本与编译参数 先 make && make install(或手动 cp objs/nginx),再走 USR2/QUIT 流程
4 新增模块后 HTTPS / gzip 突然不能用了 增量编译时 ./configure 只写了新参数,旧参数没带上,旧模块全丢 `nginx -V grep -E "ssl
5 ./configure 报 --sbin-path=... 没有那个文件或目录 多行写法里 \ 后面多了空格,或最后一行也加了 \ 逐行看 cat -A 或肉眼检查行尾 每行末尾 \ 后不留空格 ,最后一行不加 \
6 防火墙放行了端口,外部还是访问不通 加了 --permanent 但没 --reload,规则没生效 firewall-cmd --list-all firewall-cmd --reload;后端机要放行负载均衡池的所有端口(80/8080/5672)
7 负载均衡池里所有后端 100% 超时 后端机防火墙只放行了 22,池端口全被拒 从客户端 telnet 后端IP 80 或 firewall-cmd --list-all 后端机逐个放行池端口并 reload
8 防盗链配置报 the "none" or "blocked" referers are specified ... without any valid referer valid_referers 里只写了 none,没写 blocked nginx -t 直接报错定位 写成 valid_referers none blocked www.bilibili.com;,none 和 blocked 必须一起写
9 防盗链配了但图片照样被外站引用 正则 location 抢走了前缀块的请求,防盗链块根本没命中 tail -f logs/access.log 看请求落到哪个 location 用 ^~ /server 让前缀命中即停,或调整正则范围
10 直接输 URL 访问图片被 403 地址栏直访不带 Referer ,属于 none 场景,而白名单里没放 none 浏览器 F12 看请求头有无 Referer 白名单补 none(和 blocked 一起写)
11 改了配置还看到旧图片 / 旧页面 浏览器强缓存命中,请求根本没到 nginx F12 Network 看 from disk cache;curl -I 看响应头 强刷 Ctrl+F5;调试期用 expires -1 关掉强缓存再验证
12 root 配了却 404,文件明明存在 root 是路径拼接(root + location 路径),不是替换 error.log 里会打印实际查找的完整路径 想替换前缀就用 alias;用 root 时确认拼接后的路径真实存在
13 alias 配完 404 或路径多了一层 location 以 / 结尾时 alias 也必须以 / 结尾,否则拼接错位 error.log 看实际路径 两边斜杠保持一致:location /images/ { alias /data/img/; }
14 某个 location 死活不生效,请求被别的块接走 没搞清优先级:= > ^~ > 正则 > 普通前缀(取最长),正则一旦命中就覆盖前缀 nginx -T 看完整生效配置 精确匹配用 =,要挡住正则用 ^~,别指望「最长前缀」赢过正则
15 跨域请求被浏览器拦截 Access-Control-Allow-Origin 写成 http:192.168.228.128,少了一个斜杠 F12 Console 看 CORS 报错原文 改成 http://192.168.228.128,或调试期先用 *
16 自签证书启动报 ee key too small Rocky 9 的 OpenSSL 3 默认安全等级拒绝 1024 位密钥 `openssl x509 -in server.crt -noout -text grep "Public-Key"`
17 浏览器报 SSL_ERROR_RX_RECORD_TOO_LONG 用 https:// 访问了没开 SSL 的端口,或 listen 443 漏写 ssl curl -I https://域名、`ss -tlnp grep :443`
18 反向代理 502 / 超时 后端 IP 写错(192.168 写成 192.128/192.169),或后端服务没起 tail -f logs/error.log、`ps -ef grep nginx`(后端机)
19 反向代理出现无限 302 死循环 if (!-f $request_filename) 对目录 / 永远判定「不存在」 浏览器看地址栏反复跳转;access.log 刷屏 改用 if (!-e $request_filename),-e 同时判断文件或目录
20 重启虚拟机后站点全挂,ps 里没有 nginx 手动启动的 nginx 不会开机自启 `ps -ef grep nginx、ip addr` 确认 IP 是否漂移

7.2 三条通用排查心法

清单之外,再补三条贯穿全文的排查思路,遇到表里没有的新问题也能照着走:

  1. 先看语法,再看日志,最后看网络 。nginx -t 能挡掉一大半配置错误;tail -f logs/error.log 会直接告诉你文件找不到、端口被占、证书不匹配;前两步都过了还访问不通,才去查防火墙、SELinux、IP 漂移。
  2. 改完必 reload,reload 前必 -t 。nginx -t 通过再 nginx -s reload,是全文出现次数最多的一条纪律------不 reload 配置不生效,语法错就 reload 会让旧 worker 继续跑旧配置,看起来「改了没用」。
  3. 怀疑缓存时,先排除浏览器 。配置类问题排查到一半发现「怎么改都一样」,八成是浏览器强缓存或 DNS 缓存。用 curl -I 绕过浏览器直接看响应头,能立刻区分是服务端没生效还是客户端没刷新。

一句话收尾:这张表不用背,收藏起来按现象搜就行。真正要记住的是那三条心法------语法、日志、网络,按顺序走,绝大多数 Nginx 问题都能在十分钟内定位到根因。

相关推荐
Star(up up up)1 小时前
Docker系列---Dockerfile镜像文件
人工智能·经验分享·学习·程序人生·docker·容器·github
January12071 小时前
【AI方法笔记】2026-11-02:模型流式吐 JSON 时,前端会遇到四种崩法
前端·人工智能·笔记·json
snysy2 小时前
# 磁盘IO性能fio测试实操笔记
笔记·磁盘io·fio
外收内放2 小时前
ENSP学习记录(4)
服务器·学习·智能路由器
fb_123452 小时前
K8s StatefulSet五大有状态集群实战_Nginx_Etcd_Redis_Cassandra_MySQL
nginx·kubernetes·etcd
承渊政道2 小时前
Linux网络学习【五种IO模型与⾮阻塞IO】
linux·网络·学习·ubuntu·io模型·非阻塞io
无心水3 小时前
20、大数据架构设计理论与实践 核心考点与学习笔记
大数据·笔记·学习·架构师·系统架构设计师·软考系统架构设计师·架构设计师
程序员梅雨3 小时前
【从零开始学习数据仓库 | 第三篇】: Flume——数据采集基石
java·大数据·数据仓库·后端·学习·flume
acd120093 小时前
域名解析缓存带来的隐性故障,很多排查都漏掉了这一层
java·运维·nginx