Nginx 服务
本文合并自:01-Nginx完全指南.md、03-Nginx-HTTPS配置与systemd管理.md
本文覆盖 Nginx 的简介与架构特性、YUM 与源码两种安装方式、目录结构与命令行参数、nginx.conf 逐段解析(main / events / http / server / location)、虚拟主机、静态资源与目录浏览、访问控制、日志与切割、反向代理、负载均衡、代理缓存、rewrite 重写、与 PHP 集成、HTTPS 证书配置、systemd 服务管理、性能调优、故障排查与课后练习。
1. Nginx 简介与特性
Nginx(读作 "engine x")是一款轻量级的 Web 服务器 / 反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在 BSD-like 协议下发行。由俄罗斯程序设计师 Igor Sysoev 开发,最初供俄国大型入口网站及搜索引擎 Rambler 使用。
特点:
- CPU、内存等资源消耗非常低,运行稳定
- 官方测试能够支撑 5 万并发连接
- 中国大陆使用 Nginx 的网站有:百度、新浪、网易、腾讯等
- 配置简洁,模块化设计,支持热加载配置(
nginx -s reload不中断服务)
Nginx 官网: http://nginx.org/
常见架构缩写:
| 缩写 | 含义 |
|---|---|
| LNMP | Linux + Nginx + MySQL/MariaDB + PHP |
| LAMP | Linux + Apache + MySQL/MariaDB + PHP |
反向代理与缓存相关软件: Squid、Varnish、ATS、Nginx
负载均衡(LB)相关软件: Nginx、HAProxy、LVS
可以通过以下命令查看各大网站使用的 Web 服务器:
curl -I www.sina.com.cn
HTTP/1.1 302 Moved Temporarily
Server: nginx
...
现在大型网站几乎统一使用 Nginx 或 Nginx 的二次开发版本(如 Tengine、OpenResty 等)。Nginx 相对于 Apache 的优势:资源占用少、支持大并发。
1.1 与 Apache 的架构对比
| 对比项 | Apache(prefork / worker) | Nginx |
|---|---|---|
| 并发模型 | 一个连接对应一个进程或线程 | 异步非阻塞事件驱动,一个 worker 处理成千上万连接 |
| 资源消耗 | 连接数增长时进程/线程数线性增长,内存占用高 | 内存占用低且基本恒定 |
| 静态资源 | 处理能力一般 | 处理静态文件、反向代理性能强(sendfile 零拷贝) |
| 动态内容 | 内置模块(如 mod_php)直接解析 |
自身不解析动态语言,通过 fastcgi_pass / proxy_pass 转发 |
| 稳定性 | 成熟稳定,模块生态庞大 | 稳定,配置修改可热加载 |
| 配置方式 | httpd.conf + .htaccess(目录级) |
nginx.conf 单一体系,无 .htaccess |
| 适用场景 | 复杂的动态应用、需要 .htaccess 的虚拟主机 |
高并发入口、静态资源服务、反向代理与负载均衡 |
生产上常见组合是 Nginx 在前做静态资源与反向代理,Apache/Tomcat/PHP-FPM 在后处理动态请求,即动静分离。
1.2 epoll 事件驱动模型
Nginx 在 Linux 下默认使用 epoll 事件模型:
- select/poll:每次调用都要把全部待监听的文件描述符集合从用户态拷贝到内核态,并线性遍历所有描述符,复杂度 O(n),且受
FD_SETSIZE(通常 1024)限制。 - epoll:在内核中维护一棵红黑树保存被监听的描述符,通过回调把"就绪"的描述符放入就绪链表,
epoll_wait只返回真正就绪的事件,复杂度接近 O(1),描述符数量只受系统ulimit -n限制。
因此 Nginx 用少量 worker 进程就能承载海量并发连接,这是它资源占用低的根本原因。
事件模型选择:
| 操作系统 | 推荐模型 |
|---|---|
| Linux | epoll(默认) |
| FreeBSD / OpenBSD | kqueue |
| Solaris | /dev/poll、eventport |
| 不支持高效模型时 | select |
配置方式:
events {
use epoll;
}
1.3 master / worker 进程模型
Nginx 启动后有两类进程:
nginx: master process ← root 启动,负责读配置、绑定端口、管理 worker
├── nginx: worker process ← 以 user 指令指定的普通用户运行,真正处理请求
├── nginx: worker process
├── nginx: cache manager process ← 启用 proxy_cache 时出现,清理过期缓存
└── nginx: cache loader process ← 启动时把磁盘缓存元数据载入共享内存
- master 进程:不处理业务请求,只负责加载 / 校验配置文件、绑定监听套接字、fork 与监控 worker 进程、接收管理信号(HUP / TERM / USR1 / USR2)。因为要绑定 80/443 等特权端口,master 通常以 root 运行。
- worker 进程:数量由
worker_processes决定,各自独立、平等地争抢并处理连接;单个 worker 崩溃不会影响其他 worker,master 会立即再拉起一个新的。
信号与命令的对应关系:
| 信号 | 等价命令 | 作用 |
|---|---|---|
TERM / INT |
nginx -s stop |
快速停止 |
QUIT |
nginx -s quit |
优雅停止(处理完当前请求) |
HUP |
nginx -s reload |
重读配置,启动新 worker,旧 worker 处理完请求后退出 |
USR1 |
nginx -s reopen |
重新打开日志文件(日志切割用) |
USR2 |
— | 平滑升级二进制程序 |
启动后可以观察进程关系:
ps -ef | grep nginx
root 84432 1 0 10:01 ? 00:00:00 nginx: master process nginx
nobody 84433 84432 0 10:01 ? 00:00:00 nginx: worker process
2. Nginx 安装
2.1 YUM 安装
# 安装 epel 源
yum install epel-release -y
yum clean all
yum makecache
# 安装 nginx
yum install nginx -y
# 启动
systemctl start nginx
systemctl enable nginx
YUM 安装的关键路径:
| 项目 | 路径 |
|---|---|
| 主配置文件 | /etc/nginx/nginx.conf |
| 子配置目录 | /etc/nginx/conf.d/*.conf |
| 网站根目录 | /usr/share/nginx/html |
| 日志目录 | /var/log/nginx/ |
| PID 文件 | /run/nginx.pid |
| 模块目录 | /usr/share/nginx/modules/*.conf |
2.2 源码编译安装
源码安装可以自定义模块、路径和编译参数,是生产环境推荐的方式。
1)下载源码包
wget http://nginx.org/download/nginx-1.16.0.tar.gz
2)创建 Nginx 用户和组
groupadd nginx
useradd -r -s /sbin/nologin -g nginx nginx
id nginx
uid=987(nginx) gid=1001(nginx) 组=1001(nginx)
3)解压
tar -xf nginx-1.16.0.tar.gz -C /usr/src
cd /usr/src/nginx-1.16.0/
ls
auto CHANGES CHANGES.ru conf configure contrib html LICENSE man README src
4)安装编译依赖
| 依赖库 | 对应的 Nginx 模块 | 说明 |
|---|---|---|
| pcre / pcre-devel | http_rewrite_module | Perl 兼容正则表达式库 |
| zlib / zlib-devel | http_gzip_module | 数据压缩库 |
| openssl / openssl-devel | http_ssl_module | SSL/TLS 加密通信 |
| gcc / gcc-c++ | 编译工具 | C/C++ 编译器 |
yum install -y pcre pcre-devel zlib zlib-devel openssl openssl-devel gcc gcc-c++
yum install -y make perl net-tools
5)配置、编译、安装
# 配置(添加 SSL 支持)
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module
# 可通过以下命令查看所有配置参数
./configure --help
# 编译并安装
make && make install
6)确认安装结果
ls /usr/local/nginx/
conf html logs sbin
7)添加环境变量
echo "export PATH=$PATH:/usr/local/nginx/sbin" >> /etc/profile
source /etc/profile
2.3 手动编译依赖库(不使用 yum 开发包)
如果不能用 yum 安装开发库,也可以逐个下载依赖源码编译,再在 ./configure 时用 --with-pcre / --with-zlib / --with-openssl 指定依赖的源码目录。
Nginx 及依赖包下载地址:
| 组件 | 说明 | 下载地址 |
|---|---|---|
| Nginx | Web 服务器 / 反向代理 | http://nginx.org/download/nginx-1.8.0.tar.gz |
| zlib | gzip 模块依赖 | http://zlib.net/zlib-1.2.8.tar.gz |
| PCRE | rewrite 模块依赖 | http://www.pcre.org/ |
| OpenSSL / openssl-fips | SSL 功能依赖 | http://www.openssl.org/source/openssl-fips-2.0.9.tar.gz |
将安装包放到 /home/zwr/nginx_install 目录下,依次编译安装(注意根据实际下载的版本替换文件名):
cd /home/zwr/nginx_install
# 1. 安装 openssl-fips-2.0.9
tar -zxvf openssl-fips-2.0.9.tar.gz
cd openssl-fips-2.0.9
./config --prefix=/opt/openssl-fips-2.0.9
make && make install
# 2. 安装 zlib-1.2.8
cd /home/zwr/nginx_install
tar -zxvf zlib-1.2.8.tar.gz
cd zlib-1.2.8
./configure --prefix=/opt/zlib-1.2.8
make && make install
# 3. 安装 pcre-8.37
cd /home/zwr/nginx_install
tar -zxvf pcre-8.37.tar.gz
cd pcre-8.37
./configure --prefix=/opt/pcre-8.37
make && make install
依赖就绪后,进入 Nginx 源码目录编译安装。关键是必须带上 --with-http_ssl_module,否则 Nginx 无法支持 HTTPS。
# 4. 安装 nginx
cd /home/zwr/nginx_install
tar -zxvf nginx-1.8.0.tar.gz
cd nginx-1.8.0
./configure \
--prefix=/opt/nginx-1.8.0 \
--with-pcre=../pcre-8.37 \
--with-zlib=../zlib-1.2.8 \
--with-openssl=../openssl-fips-2.0.9 \
--with-http_ssl_module
make && make install
如果使用 yum 安装开发库,则编译命令更简洁:
cd /usr/src/nginx-1.8.0
./configure --prefix=/usr/local/nginx --with-http_ssl_module
make && make install
编译安装完成后,校验配置并启动 Nginx:
cd /opt/nginx-1.8.0/sbin # 或 /usr/local/nginx/sbin
./nginx -t # 检测配置是否正确
./nginx # 启动
netstat -ntlp | grep nginx # 查看监听端口
2.4 编译参数与常用模块
| 参数 | 说明 |
|---|---|
--prefix=/usr/local/nginx |
指定安装路径 |
--user=nginx |
运行 worker 进程的用户 |
--group=nginx |
运行 worker 进程的组 |
--with-http_ssl_module |
启用 HTTPS/SSL 支持 |
--with-http_gzip_static_module |
启用 gzip 静态压缩 |
--with-http_stub_status_module |
启用状态监控页面 |
--with-http_realip_module |
获取代理链后的客户端真实 IP |
--with-http_v2_module |
启用 HTTP/2 |
--with-stream |
启用四层(TCP/UDP)代理 |
--with-pcre=../pcre-8.37 |
指定 PCRE 源码目录(手动编译依赖时使用) |
--with-zlib=../zlib-1.2.8 |
指定 zlib 源码目录 |
--with-openssl=../openssl-fips-2.0.9 |
指定 OpenSSL 源码目录 |
--add-module=../ngx_cache_purge-2.3/ |
添加第三方模块(如缓存清除) |
2.5 启动与验证
# 启动
nginx
# 检查端口
lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 84432 root 6u IPv4 142705 0t0 TCP *:http (LISTEN)
nginx 84433 nobody 6u IPv4 142705 0t0 TCP *:http (LISTEN)
netstat -tunlp | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 84432/nginx: master
如果没有
lsof和netstat命令,安装:yum install -y lsof net-tools
浏览器输入服务器 IP,看到 "Welcome to nginx!" 表示启动成功。
3. 目录结构与命令行参数
3.1 源码安装的目录结构
/usr/local/nginx/
├── conf/ 配置文件目录
│ ├── nginx.conf 主配置文件
│ ├── nginx.conf.default 主配置文件默认备份
│ ├── mime.types MIME 类型映射表
│ ├── fastcgi_params FastCGI 参数
│ └── cert/ (自建)证书存放目录
├── html/ 默认网站根目录(index.html、50x.html)
├── logs/ 日志目录(access.log、error.log、nginx.pid)
└── sbin/nginx 主程序
3.2 命令行参数
nginx -h
nginx version: nginx/1.16.0
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/local/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
常用命令:
| 命令 | 说明 |
|---|---|
nginx -v |
查看版本 |
nginx -V |
查看版本和编译参数(用于确认是否含 --with-http_ssl_module) |
nginx -t |
测试配置文件语法 |
nginx -T |
测试配置并输出完整配置内容(含 include 展开) |
nginx -s stop |
快速停止 Nginx |
nginx -s quit |
优雅停止 Nginx(处理完当前请求) |
nginx -s reload |
平滑重载配置(不中断服务) |
nginx -s reopen |
重新打开日志文件 |
nginx -c /path/nginx.conf |
指定配置文件启动 |
# 确认已编译进 SSL 模块
/opt/nginx-1.8.0/sbin/nginx -V
修改配置文件后先
nginx -t检查语法,再使用nginx -s reload即可在不重启的情况下使配置生效。
4. nginx.conf 结构详解
4.1 配置文件结构总览
Nginx 配置文件主要分为 4 个部分:
# 全局块(main):影响所有其他部分的设置
user nginx;
worker_processes auto;
error_log logs/error.log;
pid logs/nginx.pid;
# events 块:影响 Nginx 服务器与客户端的网络连接
events {
worker_connections 1024;
}
# http 块:HTTP 服务相关全局配置
http {
include mime.types;
default_type application/octet-stream;
# upstream 块:上游服务器(反向代理 / 负载均衡)
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# server 块:虚拟主机配置
server {
listen 80;
server_name localhost;
# location 块:URL 匹配后的处理
location / {
root html;
index index.html index.htm;
}
}
}
各部分的关系:
server继承mainlocation继承serverupstream既不会继承指令,也不会被继承,它有自己的特殊指令
配置文件层级关系图:
main(全局配置)
├── events(网络连接事件)
└── http(HTTP 服务全局配置)
├── upstream(后端服务器组)
└── server(虚拟主机)
└── location(URL 匹配)
4.2 main 段(全局块)
全局块设置的指令将影响其他所有部分。
# 运行 worker 进程的用户和组
user nginx nginx;
# worker 工作进程数,auto 表示自动匹配 CPU 核心数
worker_processes auto;
# CPU 粘性(高并发时减少多核切换开销)
# 四核示例:worker_cpu_affinity 0001 0010 0100 1000;
worker_cpu_affinity auto;
# 错误日志路径和级别(debug | info | notice | warn | error | crit)
error_log logs/error.log;
# error_log logs/error.log notice;
# error_log logs/error.log info;
# PID 文件路径
pid logs/nginx.pid;
# worker 进程可以打开的最大文件描述符数(默认未设置,系统上限为 65535)
worker_rlimit_nofile 65535;
| 指令 | 说明 |
|---|---|
user |
指定 worker 进程运行的用户和组,决定了对网站目录的读写权限 |
worker_processes |
worker 进程数量,auto 自动等于 CPU 核心数 |
worker_cpu_affinity |
把 worker 绑定到指定 CPU 核心(CPU 亲和性) |
error_log |
错误日志文件与级别 |
pid |
master 进程 PID 文件路径,systemd 的 PIDFile 必须与之一致 |
worker_rlimit_nofile |
单个 worker 可打开的最大文件描述符数 |
worker_processes 设置建议:
- 可设为 CPU 核心数:
grep ^processor /proc/cpuinfo | wc -l - 设为
auto自动检测 - 如果开启了 SSL 和 gzip,可设为逻辑 CPU 数量甚至 2 倍以减少 I/O 操作
- 如果服务器还有其他服务,应适当减少
worker_cpu_affinity: 在高并发情况下,通过设置 CPU 粘性来降低多核切换造成的寄存器现场重建开销。四核显式写法:
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
error_log 级别由低到高:debug、info、notice、warn、error、crit、alert、emerg。生产环境建议 warn 或 error,排错时临时调为 info / debug(debug 需编译时带 --with-debug)。
4.3 events 段
events 块配置 Nginx 服务器与客户端的网络连接行为。
events {
# 使用 epoll 事件模型(Linux 下高效模型)
use epoll;
# 每个 worker 进程的最大并发连接数
worker_connections 65535;
# 一个 worker 同时接收多个新连接(可选)
multi_accept on;
}
worker_connections: 每个 worker 进程能并发处理的最大连接数(包含与客户端或后端被代理服务器间的所有连接数)。
最大连接数计算公式:
| Nginx 角色 | 公式 |
|---|---|
| HTTP 服务器 | worker_processes × worker_connections / 2 |
| 反向代理服务器 | worker_processes × worker_connections / 4 |
作为 HTTP 服务器时,浏览器的一个连接会占用 Nginx 2 个描述符(客户端连接 + 打开的文件);作为反向代理时,还要额外占用与后端的连接,所以除以 4。
worker_connections值不能超过worker_rlimit_nofile的设置。
4.4 http 段基础指令
http 块包含 HTTP 服务相关的全局配置,如文件传输、日志、压缩、代理等。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# 客户端请求体大小限制(上传文件时需调整)
client_max_body_size 10m;
client_body_buffer_size 128k;
# 响应客户端超时
send_timeout 60;
# 隐藏版本号
server_tokens off;
# 引入子配置文件
include /etc/nginx/conf.d/*.conf;
}
指令说明:
| 指令 | 说明 |
|---|---|
include mime.types |
引入 MIME 类型映射表;也可用 include conf.d/*.conf 拆分虚拟主机配置 |
default_type application/octet-stream |
默认 MIME 类型(二进制流) |
sendfile on |
开启高效文件传输(零拷贝),减少内核态到用户态的上下文切换。下载等磁盘 I/O 重负载应用可设为 off |
tcp_nopush on |
在 sendfile 开启时有效,合并数据包一次发送,防止网络阻塞 |
tcp_nodelay on |
长连接时禁用 Nagle 算法,提高数据实时性 |
keepalive_timeout 65 |
长连接超时时间(秒)。大量小文件可减少重建连接开销;大文件上传需注意超时 |
send_timeout |
响应客户端超时,仅限于两个连接活动之间的时间 |
client_max_body_size |
允许客户端请求的最大单文件字节数(上传大文件必须调大,否则报 413) |
client_body_buffer_size |
缓冲区代理缓冲客户端请求的最大字节数 |
client_header_timeout |
读取客户端请求头超时 |
client_body_timeout |
读取客户端请求体超时 |
types_hash_max_size |
MIME 类型哈希表大小 |
server_tokens off |
响应头中隐藏 Nginx 版本号 |
生产环境常见的一组客户端与超时参数(来自反向代理实战配置):
http {
# 缓冲区代理缓冲用户端请求的最大字节数,可理解为保存到本地再传给用户
client_max_body_size 50m;
client_body_buffer_size 256k;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
}
4.5 MIME 类型
mime.types 文件定义了文件扩展名与 MIME 类型的映射,Nginx 根据它设置 Content-Type 响应头。当请求的文件类型未匹配到时,使用 default_type。
4.6 gzip 压缩
http {
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 6;
gzip_types text/html text/plain text/css text/javascript
application/json application/javascript
application/x-javascript application/xml;
gzip_vary on;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";
}
指令说明:
| 指令 | 说明 |
|---|---|
gzip on |
开启 gzip 压缩输出 |
gzip_min_length 1k |
允许压缩的最小字节数(从 Content-Length 获取),建议大于 1k,小于 1k 可能越压越大 |
gzip_buffers 4 16k |
以 16k 为单位,申请原始数据大小 4 倍的内存 |
gzip_http_version 1.0 |
识别 HTTP 协议版本,默认 1.1 |
gzip_comp_level 6 |
压缩比 1-9,1 最快压缩率最低,9 最慢压缩率最高(消耗 CPU),推荐 4-6 |
gzip_types |
匹配 MIME 类型压缩,text/html 总是会被压缩 |
gzip_vary on |
在响应头添加 Vary: Accept-Encoding,让前端缓存服务器缓存压缩后的页面 |
gzip_proxied any |
反向代理时启用,后端返回含 Via 头时压缩 |
gzip_disable |
对匹配 User-Agent 的客户端禁用压缩(如低版本 IE) |
验证压缩是否生效:
curl -I -H "Accept-Encoding: gzip" http://www.example.com/index.html
# 响应头出现 Content-Encoding: gzip 即成功
4.7 server 段(虚拟主机)
每个 server 块代表一个虚拟主机,通过监听地址/端口和域名来区分。
server {
listen 80;
server_name localhost;
root /usr/local/nginx/html;
index index.html index.htm;
charset utf-8;
access_log logs/host.access.log main;
}
| 指令 | 说明 |
|---|---|
listen 80 |
监听端口,小于 1024 需要 root 启动。可写为 listen *:80、listen 127.0.0.1:80、listen 80 default_server、listen [::]:80 |
server_name |
服务器域名,支持多个域名、通配符(*.example.com)和正则匹配 |
root |
网站根目录 |
index |
默认首页文件,按顺序查找 |
charset |
页面默认字符集 |
access_log |
该虚拟主机独立的访问日志 |
error_page |
自定义错误页面 |
4.8 location 段(基本用法)
location 用于匹配特定 URL 并定义处理方式。
语法:
location [ = | ~ | ~* | ^~ ] /uri/ {
# 配置
}
| 修饰符 | 说明 |
|---|---|
= |
精确匹配,优先级最高 |
^~ |
普通字符匹配,匹配成功后不再匹配正则 |
~ |
区分大小写的正则匹配 |
~* |
不区分大小写的正则匹配 |
/uri/ |
普通前缀匹配 |
/ |
通用匹配,默认匹配 |
匹配优先级(从高到低):
=精确匹配^~前缀匹配(匹配后停止正则匹配)~/~*正则匹配(按配置文件中的顺序,第一个匹配生效)- 普通前缀匹配(最长匹配优先)
/通用匹配
示例:
# 精确匹配
location = / {
# 只匹配根目录
}
# 区分大小写的正则匹配
location ~ \.php$ {
# 匹配 .php 结尾的请求
}
# 不区分大小写的正则匹配
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
# 匹配静态资源
}
# 前缀匹配
location ^~ /images/ {
# 匹配 /images/ 开头的请求,不再进行正则匹配
}
# 通用匹配
location / {
# 所有未匹配的请求
}
详见 10-03-Nginx-location匹配规则.md
5. 虚拟主机
5.1 基于 IP 的虚拟主机
为服务器绑定多个 IP,每个 IP 对应一个虚拟主机:
server {
listen 80;
server_name 192.168.0.30;
location / {
root test1;
index index.html index.htm;
}
}
server {
listen 80;
server_name 192.168.0.65;
location / {
root test2;
index index.html index.htm;
}
}
# 绑定虚拟 IP
ifconfig ens33:0 192.168.0.65/24
# 创建测试页面
mkdir /usr/local/nginx/test1 /usr/local/nginx/test2
echo "test1" > /usr/local/nginx/test1/index.html
echo "test2" > /usr/local/nginx/test2/index.html
nginx -s reload
验证:
curl 192.168.0.30 # 输出 test1
curl 192.168.0.65 # 输出 test2
5.2 基于端口的虚拟主机
同一 IP 的不同端口对应不同虚拟主机:
server {
listen 80;
server_name 1.1.1.3;
location / {
root test1;
index index.html index.htm;
}
}
server {
listen 8080;
server_name 1.1.1.3;
location / {
root test2;
index index.html index.htm;
}
}
验证:
curl 1.1.1.3 # test1
curl 1.1.1.3:8080 # test2
5.3 基于域名的虚拟主机
通过 DNS 解析将不同域名指向同一 IP,Nginx 根据 Host 头区分:
server {
listen 80;
server_name www.example.com;
location / {
root /nginx/web;
index index.html index.htm;
}
}
server {
listen 80;
server_name api.example.com;
location / {
root /nginx/web2;
index index.html index.htm;
}
}
本地测试可在 /etc/hosts 添加:
1.1.1.3 www.example.com api.example.com
验证:
curl http://www.example.com # web 目录
curl http://api.example.com # web2 目录
基于域名的虚拟主机是生产环境最常用的方式,只需一个 IP 即可承载大量站点。
6. 静态资源与目录浏览
6.1 root 与 index
location / {
root /var/www/html;
index index.html index.htm index.php;
}
root:定义请求对应的文件根目录,最终文件路径 =root+ URIindex:定义默认访问的文件名,按顺序查找
6.2 静态资源缓存与过期时间
location ~* \.(gif|jpg|jpeg|png|ico|css|js|svg|woff2?)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
expires 设置 Expires 与 Cache-Control 响应头,让浏览器在有效期内直接使用本地缓存,减少回源请求。
6.3 目录浏览 autoindex
Nginx 默认不允许列出目录内容。开启方式:
location /images/ {
root /var/www/nginx-default/images;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
| 指令 | 说明 |
|---|---|
autoindex on |
开启目录浏览 |
autoindex_exact_size off |
on 显示精确字节数;off 显示 kB/MB/GB |
autoindex_localtime on |
on 显示服务器本地时间;off 显示 GMT 时间 |
生产环境的网站根目录一般应关闭 autoindex,仅在内部下载站点开启。
6.4 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
可以自定义错误页面,将不同错误码重定向到指定页面。
7. 访问控制
7.1 基于 IP 的 allow / deny
访问控制可以放在 location、server 或 http 块中。规则按顺序匹配,满足任一规则即停止。
写法一:location 级控制
server {
listen 80;
server_name www.example.com;
location / {
root /nginx/web;
index index.html index.htm;
deny 192.168.0.117;
allow all;
}
}
写法二:server 级控制
server {
listen 80;
server_name www.example.com;
deny 192.168.0.117;
allow all;
location / {
root /nginx/web;
index index.html index.htm;
}
}
写法三:http 全局控制
http {
deny 192.168.0.117;
allow all;
server {
listen 80;
server_name www.example.com;
location / {
root /nginx/web;
index index.html index.htm;
}
}
}
注意: 如果全局和局部都配置了且冲突,局部配置优先。
IP 段控制示例:
location /nginx-status {
stub_status on;
access_log off;
allow 192.168.10.100;
allow 172.29.73.0/24;
deny all;
}
常见的禁止访问规则:
# 禁止访问隐藏文件(.git、.svn、.env 等)
location ~ /\. {
deny all;
}
# 禁止访问敏感目录
location ~ ^/(WEB-INF)/ {
deny all;
}
7.2 基本认证 basic auth 与 htpasswd
使用 htpasswd 生成密码文件(该命令来自 httpd-tools / httpd-devel 包):
yum install -y httpd-tools
# 创建密码文件并添加用户 admin(-c 表示新建文件,会覆盖已有文件)
htpasswd -c /usr/local/nginx/htpasswd admin
# 再添加用户 sean(不要加 -c,否则覆盖)
htpasswd /usr/local/nginx/htpasswd sean
# 查看
cat /usr/local/nginx/htpasswd
在配置中启用:
location /nginxstatus {
stub_status on;
access_log off;
auth_basic "NginxStatus";
auth_basic_user_file /usr/local/nginx/htpasswd;
allow 192.168.10.0/24;
deny all;
}
| 指令 | 说明 |
|---|---|
auth_basic "提示语" |
开启基本认证,字符串为弹窗提示;设为 off 可在子 location 中关闭继承的认证 |
auth_basic_user_file |
密码文件路径,需 Nginx 运行用户可读,建议权限 640 |
访问时浏览器会弹出用户名密码框;命令行验证:
curl -u admin:123456 http://192.168.10.10/nginxstatus
7.3 stub_status 状态监控
编译时需添加 --with-http_stub_status_module 参数。
location /nginxstatus {
stub_status on;
access_log on;
auth_basic "nginxstatus";
}
访问 http://your-server/nginxstatus:
Active connections: 3
server accepts handled requests
206909 206909 207011
Reading: 0 Writing: 1 Waiting: 2
| 指标 | 说明 |
|---|---|
| Active connections | 当前活动连接数 |
| accepts | 已接收的连接总数 |
| handled | 成功创建握手的连接总数 |
| requests | 总共处理的请求数 |
| Reading | 正在读取请求头的连接数 |
| Writing | 正在发送响应的连接数 |
| Waiting | 等待中的空闲连接数(长连接) |
若
accepts与handled不相等,说明有连接被丢弃,通常是超过了worker_connections或文件描述符上限。
8. 日志管理
8.1 log_format 与 access_log
在 nginx.conf 的 http 段中定义日志格式并启用:
http {
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;
# 关闭某个 location 的日志
# access_log off;
}
access_log 可以出现在 http、server、location 中,就近生效;log_format 只能定义在 http 段。
8.2 日志变量全表
| 变量 | 说明 |
|---|---|
$remote_addr |
客户端 IP 地址 |
$remote_user |
客户端用户名(基本认证) |
$time_local |
访问时间和时区 |
$request |
请求的 URI 和 HTTP 协议 |
$status |
HTTP 响应状态码 |
$body_bytes_sent |
发送给客户端的文件体内容字节数 |
$bytes_sent |
发送给客户端的总字节数(含响应头) |
$http_referer |
来源页面 URL |
$http_user_agent |
客户端浏览器信息 |
$http_x_forwarded_for |
经过代理时的客户端真实 IP |
$request_time |
请求处理总耗时(秒,精度毫秒) |
$upstream_addr |
后端服务器地址(反向代理时) |
$upstream_status |
后端返回的状态码 |
$upstream_response_time |
后端响应耗时 |
$upstream_cache_status |
缓存状态(HIT / MISS / EXPIRED / BYPASS / UPDATING / STALE) |
$host |
请求头中的 Host |
$server_name |
匹配到的虚拟主机名 |
$request_uri |
完整的原始请求 URI(含参数) |
$uri |
规范化后的 URI(不含参数) |
$args / $query_string |
请求参数 |
$is_args |
若有参数则为 ?,否则为空 |
$scheme |
协议(http / https) |
$request_method |
请求方法(GET / POST 等) |
排查性能问题时常用的扩展格式:
log_format timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct=$upstream_connect_time '
'uht=$upstream_header_time urt=$upstream_response_time '
'cache=$upstream_cache_status';
8.3 日志切割脚本
vim /usr/local/nginx/sbin/nginx_logrotate.sh
#!/bin/bash
logpath="/usr/local/nginx/logs"
year=$(date -d 'yesterday' +'%Y')
month=$(date -d 'yesterday' +'%m')
day=$(date -d 'yesterday' +'%Y-%m-%d')
mkdir -p "$logpath/$year/$month"
mv "$logpath/access.log" "$logpath/$year/$month/$day.accesslog"
# 发送 USR1 信号让 Nginx 重新生成空日志文件
kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)
加入定时任务:
crontab -e
01 2 * * * sh /usr/local/nginx/sbin/nginx_logrotate.sh
关键点:
mv之后旧的文件句柄仍被 worker 持有,必须发送USR1(等价nginx -s reopen)让 Nginx 重新创建并打开新的日志文件,否则新日志会继续写入被改名的文件。
8.4 使用 logrotate 切割
也可以使用系统自带的 logrotate 工具(YUM 安装时已自带 /etc/logrotate.d/nginx)。源码安装可手动编写:
vim /etc/logrotate.d/nginx
/usr/local/nginx/logs/*.log {
daily
rotate 30
missingok
notifempty
dateext
compress
delaycompress
sharedscripts
postrotate
[ -f /usr/local/nginx/logs/nginx.pid ] && kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
endscript
}
| 参数 | 说明 |
|---|---|
daily |
每天切割(可选 weekly / monthly / size 100M) |
rotate 30 |
保留 30 份历史日志 |
missingok |
日志文件不存在时不报错 |
notifempty |
文件为空时不切割 |
dateext |
切割后的文件名带日期后缀 |
compress / delaycompress |
压缩历史日志,延迟一轮再压缩 |
sharedscripts |
多个日志文件只执行一次 postrotate |
postrotate ... endscript |
切割后执行的命令,此处发送 USR1 重新打开日志 |
手动测试:
logrotate -vf /etc/logrotate.d/nginx
9. 反向代理
9.1 基础反向代理
架构说明:
client (3.3.3.x)
|
| eth0: 3.3.3.5
+-- Nginx 反向代理 --+
eth1: 192.168.224.10
|
|
Web 服务器: 192.168.224.11
在 Nginx 服务器上:
yum install -y nginx
编辑 /etc/nginx/nginx.conf,在 server 块中添加 location:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name 3.3.3.5;
root /usr/share/nginx/html;
index index.php index.html;
location / {
proxy_pass http://192.168.224.11/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
systemctl restart nginx
lsof -i:80
客户端访问 http://3.3.3.5/ 即可看到后端 Web 服务器的内容。
验证缓存: 关闭后端 Web,客户端也无法访问,说明 Nginx 默认没有缓存功能。
proxy_pass 末尾斜线的区别:
| 写法 | 请求 /nba/1.html 转发到后端的路径 |
|---|---|
proxy_pass http://backend;(无 /) |
/nba/1.html(保留原始 URI) |
proxy_pass http://backend/;(有 /) |
/1.html(去掉 location 匹配的前缀) |
9.2 proxy_set_header 说明
以下两句是外网转内网双网段架构必需的配置:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
| 指令 | 说明 |
|---|---|
proxy_set_header Host $host |
将客户端请求的原始 Host 头传递给后端,后端虚拟主机才能正确匹配 |
proxy_set_header X-Real-IP $remote_addr |
传递客户端真实 IP |
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for |
追加代理链中的客户端 IP(比 $remote_addr 更完整) |
proxy_set_header X-Forwarded-Proto $scheme |
告知后端原始请求协议,HTTPS 卸载时必需 |
为什么需要代理?
- 安全 DMZ: 后端服务器隐藏在内网,不直接暴露给客户端
- 缓存加速: 代理服务器可缓存静态内容,减轻后端压力
- 统一入口: 便于做负载均衡、限流、灰度、SSL 卸载
9.3 超时与缓冲参数
http {
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_max_temp_file_size 1024m;
proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
}
指令说明:
| 指令 | 说明 |
|---|---|
proxy_connect_timeout |
Nginx 与后端服务器连接超时时间 |
proxy_read_timeout |
连接成功后,与后端两个成功响应之间的超时时间(后端处理慢导致 504 时需调大) |
proxy_send_timeout |
向后端服务器发送请求的超时时间 |
proxy_buffer_size 4k |
保存后端响应头信息的缓冲区大小 |
proxy_buffers 4 32k |
单个连接缓存后端响应的缓冲区数量和大小(网页平均在 32k 以下时这样设置) |
proxy_busy_buffers_size 64k |
高负荷下缓冲大小(通常为 proxy_buffers 的 2 倍) |
proxy_max_temp_file_size |
响应超出缓冲区时写入临时文件的最大值,设为 0 禁用 |
proxy_temp_file_write_size |
每次写临时文件的大小,大于该值时将从 upstream 服务器传递请求而不缓冲到磁盘 |
proxy_temp_path |
临时文件目录及目录层级 |
proxy_ignore_client_abort on |
不允许代理端主动关闭连接 |
proxy_next_upstream |
在何种情况下把请求转给下一台后端,如 error timeout http_502 http_503 |
生产反向代理常用的完整 http 段参数示例:
http {
include mime.types;
default_type application/octet-stream;
include /opt/nginx-1.8.0/conf/reverse-proxy.conf;
sendfile on;
keepalive_timeout 65;
gzip on;
# 缓冲区代理缓冲用户端请求的最大字节数,可理解为保存到本地再传给用户
client_max_body_size 50m;
client_body_buffer_size 256k;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
# Nginx 与后端服务器连接超时时间(代理连接超时)
proxy_connect_timeout 300s;
# 连接成功后,后端服务器响应时间(代理接收超时)
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# 保存用户头信息的缓冲区大小
proxy_buffer_size 64k;
# proxy_buffers 缓冲区,网页平均在 32k 以下时这样设置
proxy_buffers 4 32k;
# 高负荷下缓冲大小(proxy_buffers * 2)
proxy_busy_buffers_size 64k;
# 缓存文件夹大小,大于该值时将从 upstream 服务器传递请求而不缓冲到磁盘
proxy_temp_file_write_size 64k;
# 不允许代理端主动关闭连接
proxy_ignore_client_abort on;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
9.4 网站数据切分(七层调度)
网站数据切分本质上是七层调度。例如将新闻和体育内容分发到不同后端服务器。
架构:
client
|
Nginx (3.3.3.5)
|
+-- web1 (192.168.224.11) -- /nba/
+-- web2 (192.168.224.12) -- /cba/
在 server 块中配置:
location /nba/ {
proxy_pass http://192.168.224.11/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /cba/ {
proxy_pass http://192.168.224.12/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
systemctl restart nginx
客户端验证:
http://3.3.3.5/nba/→ web1http://3.3.3.5/cba/→ web2
9.5 动静分离
根据文件扩展名将静态资源和动态请求分发到不同后端:
# 静态资源 → web1
location ~ \.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ {
proxy_pass http://192.168.224.11;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
# 动态请求 → web2
location ~ \.(php|cgi|txt)$ {
proxy_pass http://192.168.224.12;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
在两台 Web 服务器上分别创建 1.txt 和 1.html,访问 http://nginxIP/1.txt 和 http://nginxIP/1.html 观察内容差异。
10. 负载均衡(upstream)
10.1 upstream 基本配置
在 http 块中、server 块之前定义后端服务器组:
http {
upstream backendweb {
server 192.168.224.11 weight=1 max_fails=2 fail_timeout=1s;
server 192.168.224.12 weight=1 max_fails=2 fail_timeout=1s;
}
server {
listen 80;
server_name 3.3.3.5;
location ~ \.(txt|html)$ {
proxy_pass http://backendweb;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
}
backendweb是自定义名称,在proxy_pass中通过http://backendweb引用。
10.2 负载均衡算法
| 算法 | 说明 |
|---|---|
round-robin |
轮询(默认),平均分配请求 |
weight |
权重,数值越大分配越多,用于后端服务器性能不均的情况 |
ip_hash |
按客户端 IP 哈希分配,实现会话保持 |
least_conn |
最少连接优先,把请求交给当前活动连接数最少的后端 |
hash $request_uri |
按 URL 哈希分配,提高缓存命中率 |
fair |
按后端响应时间分配(需要第三方模块 upstream_fair) |
url_hash |
按访问 URL 的哈希结果分配(第三方模块) |
权重模式:
upstream backendweb {
server 192.168.224.11 weight=3;
server 192.168.224.12 weight=1;
}
最少连接: 适合请求处理时长差异较大的场景(如长连接、大文件下载)。
upstream backendweb {
least_conn;
server 192.168.224.11;
server 192.168.224.12;
}
10.3 健康检查与 backup / down
| 参数 | 说明 |
|---|---|
weight=N |
权重,默认 1 |
max_fails=N |
允许失败的次数,超过则标记为不可用 |
fail_timeout=Ns |
失败超时时间(秒),在此时间内失败 max_fails 次则认为不健康,并在该时间内不再分配请求 |
backup |
备用服务器,主服务器全部宕机后才启用 |
down |
标记为永久离线(常用于临时下线维护某台机器) |
max_conns=N |
该后端的最大并发连接数 |
upstream backendweb {
server 192.168.224.11 weight=1 max_fails=2 fail_timeout=1s;
server 192.168.224.12 weight=1 max_fails=2 fail_timeout=1s;
server 192.168.224.13 down; # 维护中,不参与调度
server 192.168.224.14 backup; # 备机,前面都挂了才启用
}
配合 proxy_next_upstream 让失败请求自动重试下一台:
location / {
proxy_pass http://backendweb;
proxy_next_upstream error timeout http_502 http_503 http_504;
}
Nginx 开源版的健康检查是被动的:只有真实请求失败才会标记后端不可用。若需要主动探测,可使用 Tengine 的
ngx_http_upstream_check_module或商业版 Nginx Plus。
10.4 会话保持 ip_hash
同一 IP 客户端一旦被调度到某台后端,后续请求始终调度到同一台:
upstream backendweb {
ip_hash;
server 192.168.224.11 weight=1 max_fails=2 fail_timeout=1s;
server 192.168.224.12 weight=1 max_fails=2 fail_timeout=1s;
}
注意:
ip_hash按客户端 IP 的网段进行哈希。如果测试客户端都在同一内网网段,可能都会被调度到同一台后端。公网不同网段的客户端 IP 则会均匀分配。优点:配置方便;缺点:不能完全做到负载均衡。此外
ip_hash不能与weight、backup同时使用。
其他会话保持方案:
- 后端应用把 Session 存到 Redis / Memcached(推荐,彻底解耦)
- 使用
sticky第三方模块基于 Cookie 保持 - 使用
hash $cookie_jsessionid按 Cookie 哈希
10.5 url_hash 提高缓存命中率
使用 hash $request_uri 将同一 URL 的请求只调度给同一台后端缓存服务器:
upstream squid {
hash $request_uri;
server 192.168.224.12 weight=1 max_fails=2 fail_timeout=3s;
server 192.168.224.13 weight=1 max_fails=2 fail_timeout=3s;
}
新请求仍然会轮询,但已请求过的 URL 再次访问时会调度到第一次缓存它的服务器,提高缓存命中率。加上
consistent参数(hash $request_uri consistent;)可在增删后端时减少缓存失效范围。
负载均衡需要注意的四个方面:
- 算法:round-robin / weight / ip_hash / least_conn / hash 等
- 健康检查:max_fails + fail_timeout
- 会话保持:ip_hash 或 sticky 模块,或将 Session 外置
- 数据一致:rsync / drbd / 共享存储 / 分布式存储
11. 代理缓存(proxy_cache)
Nginx 自身默认不缓存后端响应,需要显式配置 proxy_cache_path + proxy_cache;若还需要按 URL 主动清除缓存,则要编译第三方模块 ngx_cache_purge。
11.1 编译缓存清除模块
# 安装依赖
yum install pcre-devel zlib-devel gcc gcc-c++ -y
# 下载源码
wget http://nginx.org/download/nginx-1.14.2.tar.gz
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
# 解压
tar xf nginx-1.14.2.tar.gz -C /usr/src/
tar xf ngx_cache_purge-2.3.tar.gz -C /usr/src/
# 编译(添加缓存模块)
cd /usr/src/nginx-1.14.2/
./configure --prefix=/usr/local/nginx \
--user=nginx --group=nginx \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--add-module=../ngx_cache_purge-2.3/
make && make install
11.2 缓存配置详解
架构:
client
|
Nginx 反向代理 + 缓存 (3.3.3.5)
|
LNMP (3.3.3.3)
user nginx nginx;
worker_processes 2;
error_log logs/error.log info;
pid logs/nginx.pid;
events {
worker_connections 65535;
use epoll;
}
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" "$upstream_cache_status"';
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
# 临时文件目录
proxy_temp_path /usr/local/nginx/proxy_temp_dir 1 2;
# 缓存路径配置
proxy_cache_path /usr/local/nginx/proxy_cache_dir/cache
levels=1:2
keys_zone=cache:100m
inactive=1d
max_size=10g;
upstream web {
server 3.3.3.3 weight=1 max_fails=2 fail_timeout=30s;
}
server {
listen 80;
server_name 3.3.3.5;
access_log logs/host.access.log main;
# 静态内容缓存
location / {
proxy_pass http://web;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_cache cache;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 10m;
add_header X-Cache '$upstream_cache_status from $host';
expires 1d;
}
# PHP 等动态请求不缓存
location ~ .*\.(php|cgi)$ {
proxy_pass http://web;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
}
proxy_cache_path 参数说明:
| 参数 | 说明 |
|---|---|
/usr/local/nginx/proxy_cache_dir/cache |
缓存文件存放目录 |
levels=1:2 |
缓存目录层级,第一级 1 个字符,第二级 2 个字符,如 cache/a/1b |
keys_zone=cache:100m |
共享内存区名称为 cache,分配 100MB 内存(存放缓存 key 与元数据) |
inactive=1d |
缓存文件 1 天未被访问则由 cache manager 进程删除 |
max_size=10g |
缓存硬盘最大容量 10GB |
server / location 段缓存指令说明:
| 指令 | 说明 |
|---|---|
proxy_cache cache |
指定使用的共享内存区名称 |
proxy_cache_key $host$uri$is_args$args |
设置缓存 key |
proxy_cache_valid 200 304 10m |
对 200/304 响应缓存 10 分钟 |
proxy_cache_min_uses N |
请求 N 次后才开始缓存 |
proxy_cache_methods |
允许缓存的请求方法,默认 GET HEAD |
proxy_no_cache / proxy_cache_bypass |
满足条件时不写缓存 / 不读缓存 |
add_header X-Cache '$upstream_cache_status' |
响应头显示缓存状态 |
expires 1d |
设置浏览器缓存过期时间为 1 天 |
$upstream_cache_status 可能值:
| 状态 | 说明 |
|---|---|
HIT |
缓存命中 |
MISS |
未命中,从后端获取 |
EXPIRED |
缓存已过期,已回源刷新 |
BYPASS |
命中 proxy_cache_bypass 规则,直接回源 |
UPDATING |
缓存过期但正在被其他请求更新,返回旧内容 |
STALE |
后端异常,返回过期的旧缓存 |
创建缓存目录并启动:
mkdir -p /usr/local/nginx/proxy_cache_dir/cache
/usr/local/nginx/sbin/nginx
# 如遇句柄数限制
ulimit -n 65535
11.3 缓存验证
# 第一次请求 — MISS
curl -I http://3.3.3.5/static/image/common/logo.png
HTTP/1.1 200 OK
Server: nginx/1.14.2
...
X-Cache: MISS from 3.3.3.5
# 第二次请求 — HIT
curl -I http://3.3.3.5/static/image/common/logo.png
HTTP/1.1 200 OK
Server: nginx/1.14.2
...
X-Cache: HIT from 3.3.3.5
查看缓存目录结构:
ls /usr/local/nginx/proxy_cache_dir/cache
0 1 2 3 5 6 7 9 a b d e f
11.4 缓存清除脚本
vim /tmp/purge_nginx_cache.sh
#!/bin/bash
cachedir=/usr/local/nginx/proxy_cache_dir/cache
grep -ra "$1" "$cachedir" | grep "$1" | awk -F':' '{print $1,$3}' | while read cacheurl url; do
rm -rf "$cacheurl"
echo "$url 被清除"
done
echo "缓存清除成功"
使用方法:
# 清除所有 .png 结尾的缓存
sh /tmp/purge_nginx_cache.sh .png$
# 手动搜索缓存文件(末尾要有 $)
grep -ra .png$ /usr/local/nginx/proxy_cache_dir/cache/
编译了 ngx_cache_purge 后,也可以配置一个专用 location 通过 URL 清除:
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 192.168.0.0/24;
deny all;
proxy_cache_purge cache $host$1$is_args$args;
}
访问 http://3.3.3.5/purge/static/image/common/logo.png 即可清除对应缓存。
12. Squid 缓存加速架构(扩展实验)
12.1 架构说明
client (192.168.1.x)
|
| 公网 IP: 192.168.1.18 (test.squid.com)
Nginx 反向代理
| 内网 IP: 3.3.3.5 (双网卡)
|
+-- Squid 缓存 (3.3.3.4)
| 命中(hit) → 直接返回
| 未命中(miss) → 从后端获取
|
+-- 动态 .php 直接转发
|
LNMP 后端 (3.3.3.3)
实验前准备:
- 所有机器配置主机名并在
/etc/hosts互相绑定 - 关闭 firewalld 和 selinux
- 关闭 NetworkManager,配置静态 IP
- 配置本地 yum、epel 源
- 时间同步
12.2 后端 LNMP 配置
在 LNMP 服务器(3.3.3.3)上安装相关 RPM 包:
yum install epel-release -y
yum install -y nginx
yum install mariadb mariadb-server php php-mysql php-gd libjpeg* \
php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring \
php-bcmath php-mhash php-fpm php-pecl-zendopcache -y
systemctl restart mariadb.service
systemctl enable mariadb.service
配置 PHP-FPM(/etc/php-fpm.d/www.conf):
listen = /var/run/php-fpm/fastcgi.socket
php_flag[display_errors] = on
user = nginx
group = nginx
listen.owner = nginx
listen.group = nginx
chown nginx.nginx /var/run/php-fpm/
systemctl start php-fpm.service
systemctl enable php-fpm.service
配置 Nginx(/etc/nginx/nginx.conf):
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
use epoll;
worker_connections 65535;
}
http {
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 /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name 192.168.224.11;
root /usr/share/nginx/html;
index index.php index.html;
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/fastcgi.socket;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
systemctl start nginx.service
systemctl enable nginx.service
部署 Discuz 论坛:
mkdir /usr/share/nginx/html/discuz/
unzip Discuz_X3.3_SC_UTF8.zip -d /usr/share/nginx/html/discuz/
cd /usr/share/nginx/html/discuz/
mv upload/* .
rm upload/ -rf
chown nginx.nginx /usr/share/nginx/html/discuz -R
数据库授权:
MariaDB [(none)]> create database discuz;
MariaDB [(none)]> grant all on discuz.* to 'discuz'@'localhost' identified by '123';
MariaDB [(none)]> flush privileges;
浏览器访问 http://3.3.3.3/discuz/ 进行安装(数据库名/用户名/密码均为 discuz/123)。
12.3 前端 Nginx 配置
在 Nginx 反向代理服务器(3.3.3.5)上:
yum install -y epel-*
yum install -y nginx
编辑 /etc/nginx/nginx.conf:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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 /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
upstream squid {
server 3.3.3.4;
}
upstream web {
server 3.3.3.3;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name 3.3.3.5;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
# PHP 动态请求 -> 后端 LNMP
location ~ .*\.php$ {
proxy_pass http://web;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
# 静态资源 -> Squid 缓存
location ~ .*\.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ {
proxy_pass http://squid;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
# 其他请求 -> Squid
location / {
proxy_pass http://squid;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
systemctl restart nginx
lsof -i:80
12.4 Squid 配置
在 Squid 服务器(3.3.3.4)上:
yum install squid openssl -y
编辑 /etc/squid/squid.conf(可清空后写入):
http_access allow all
acl purge_admin src 127.0.0.1
acl purge method PURGE
http_access allow purge_admin purge
http_access deny all purge
http_port 80 accel vhost vport
cache_dir ufs /var/spool/squid 256 16 256
cache_peer 3.3.3.3 parent 80 0 no-query originserver name=web
cache_peer_domain web test.squid.com
cache_peer_domain web 3.3.3.5
coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
关键指令说明:
| 指令 | 说明 |
|---|---|
http_access allow all |
允许所有访问(生产环境需按需限制) |
http_port 80 accel vhost vport |
反向代理模式,监听 80 端口 |
cache_dir ufs ... |
缓存目录格式、路径、大小(MB)、一级/二级目录数 |
cache_peer |
指定后端父服务器,originserver 表示源站 |
cache_peer_domain |
绑定域名和前端 Nginx IP |
systemctl restart squid
lsof -i:80
查询已缓存内容:
/usr/bin/squidclient -p 80 mgr:objects | grep png
12.5 验证与缓存命中
客户端绑定 hosts(或搭建 DNS):
3.3.3.5 test.squid.com
访问 http://test.squid.com/ 或 http://3.3.3.5/ 可看到 Discuz 论坛。
验证缓存命中:
curl -I http://test.squid.com/static/image/common/logo.png
HTTP/1.1 200 OK
Server: nginx/1.12.2
...
Age: 29
X-Cache: HIT from server.com
X-Cache-Lookup: HIT from server.com:80
Via: 1.1 server.com (squid/3.5.20)
关闭 Squid 后访问,网站将没有图片等静态元素。重启 Squid 后恢复正常。
12.6 Squid 缓存清除
单条清除(必须在 Squid 本机执行):
squidclient -m PURGE -h 127.0.0.1 -p 80 \
http://3.3.3.4/static/image/common/logo.png
批量清除脚本:
vim /tmp/purge_squid.sh
#!/bin/bash
squidcache_path="/var/spool/squid/"
squidclient_path="/usr/bin/squidclient"
grep -a -r "$1" "$squidcache_path"/* | strings | grep ^"http" | while read url; do
$squidclient_path -h 127.0.0.1 -m PURGE -p 80 "$url" > /dev/null 2>&1
echo "$url 被清除"
done
使用方法:
sh /tmp/purge_squid.sh .txt # 清除所有 .txt 缓存
sh /tmp/purge_squid.sh . # 清除所有缓存
sh /tmp/purge_squid.sh /aaa/ # 清除 URL 中含 /aaa/ 的缓存
12.7 多台 Squid 负载均衡
增加 Squid2(192.168.224.13),配置与 Squid1 相同。修改前端 Nginx:
upstream squid {
hash $request_uri;
server 192.168.224.12 weight=1 max_fails=2 fail_timeout=3s;
server 192.168.224.13 weight=1 max_fails=2 fail_timeout=3s;
}
使用
hash $request_uri使同一 URL 的请求始终调度到同一台 Squid,提高缓存命中率。
13. rewrite 地址重写
13.1 rewrite 指令语法
rewrite <正则表达式> <替换内容> [flag];
可以出现在 server、location、if 块中。Nginx 按配置顺序依次匹配 rewrite 规则,除非遇到 last / break / redirect / permanent 终止。
flag 说明:
| flag | 类型 | 说明 |
|---|---|---|
last |
内部跳转 | 停止当前 location 中的 rewrite 处理,用新 URI 重新发起一轮 location 匹配 |
break |
内部跳转 | 停止当前的 rewrite 处理,不再重新匹配 location,直接用新 URI 在当前 location 继续执行 |
redirect |
外部跳转 | 返回 302 临时重定向,浏览器地址栏改变 |
permanent |
外部跳转 | 返回 301 永久重定向,浏览器地址栏改变,对 SEO 友好 |
记忆要点:
last和break客户端看不到跳转(URL 不变);redirect和permanent客户端能看到跳转。在location中滥用last容易造成循环,Nginx 有 10 次内部跳转上限,超过报 500。
13.2 if 条件判断
if ($request_method = POST) {
return 405;
}
# 变量匹配正则(~ 区分大小写,~* 不区分,! 取反)
if ($http_user_agent ~* "MSIE|Trident") {
rewrite ^(.*)$ /ie/$1 break;
}
# 文件/目录/可执行文件是否存在
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?s=$1 last;
}
# 防盗链
if ($http_referer !~* "^https?://([^/]+\.)?example\.com") {
return 403;
}
| 判断符 | 说明 |
|---|---|
= / != |
字符串相等 / 不相等 |
~ / ~* |
正则匹配(区分 / 不区分大小写) |
!~ / !~* |
正则不匹配 |
-f / !-f |
文件存在 / 不存在 |
-d / !-d |
目录存在 / 不存在 |
-e / !-e |
文件或目录存在 / 不存在 |
-x / !-x |
文件可执行 / 不可执行 |
if只能写在server或location中,且不支持else。官方建议尽量用try_files、多个location或map替代复杂的if。
13.3 return 指令
return 比 rewrite 更高效,能直接返回状态码或跳转:
return 403; # 直接返回状态码
return 404 "not found\n"; # 返回状态码和文本
return 301 https://$server_name$request_uri; # 301 跳转
return 200 '{"status":"ok"}'; # 返回 JSON(配合 default_type application/json)
13.4 常见案例
1)不带 www 的域名跳转到带 www 的域名
server {
listen 80;
server_name example.com;
return 301 http://www.example.com$request_uri;
}
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.html;
}
等价的 rewrite 写法:
server {
listen 80;
server_name example.com www.example.com;
if ($host != 'www.example.com') {
rewrite ^/(.*)$ http://www.example.com/$1 permanent;
}
}
2)旧域名整体跳转到新域名
server {
listen 80;
server_name old.example.com;
rewrite ^/(.*)$ http://new.example.com/$1 permanent;
}
3)目录调整跳转
# /2024/xxx.html -> /archive/2024/xxx.html
rewrite ^/2024/(.*)$ /archive/2024/$1 last;
4)伪静态:把静态 URL 映射到动态脚本
# /article-123.html -> /article.php?id=123
location / {
rewrite ^/article-([0-9]+)\.html$ /article.php?id=$1 last;
}
# ThinkPHP / Laravel 常用的伪静态(PATH_INFO 模式)
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 传统写法
location / {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?s=$1 last;
}
}
# Discuz 伪静态示例
rewrite ^([^\.]*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last;
rewrite ^([^\.]*)/forum-(\w+)-([0-9]+)\.html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last;
rewrite ^([^\.]*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last;
5)根据设备类型跳转到手机站
if ($http_user_agent ~* "(android|iphone|ipad|windows phone)") {
rewrite ^(.*)$ http://m.example.com$1 redirect;
}
6)禁止某些 User-Agent
if ($http_user_agent ~* "curl|wget|python-requests") {
return 403;
}
调试 rewrite 规则时可临时开启日志:
error_log logs/error.log notice;
rewrite_log on;
14. 与 PHP 集成(fastcgi_pass)
Nginx 本身不能解析 PHP,需要把 .php 请求通过 FastCGI 协议交给 PHP-FPM 处理。
14.1 安装并配置 PHP-FPM
yum install -y php php-fpm php-mysql php-gd php-mbstring php-xml
systemctl start php-fpm
systemctl enable php-fpm
/etc/php-fpm.d/www.conf 关键配置(Unix Socket 方式):
listen = /var/run/php-fpm/fastcgi.socket
php_flag[display_errors] = on
user = nginx
group = nginx
listen.owner = nginx
listen.group = nginx
也可以使用 TCP 方式监听:
listen = 127.0.0.1:9000
chown nginx.nginx /var/run/php-fpm/
systemctl restart php-fpm
14.2 Nginx 侧配置
Unix Socket 方式(本机部署,性能更好):
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/fastcgi.socket;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
TCP 方式(PHP-FPM 可在其他主机):
location ~ \.php$ {
root /var/www/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
| 指令 | 说明 |
|---|---|
fastcgi_pass |
PHP-FPM 的地址(Unix socket 或 IP:端口) |
fastcgi_index |
请求以 / 结尾时补全的默认脚本名 |
fastcgi_param SCRIPT_FILENAME |
告知 PHP-FPM 要执行的脚本绝对路径,配置错误会导致 "File not found" |
include fastcgi_params |
引入 Nginx 自带的 FastCGI 通用参数 |
fastcgi_connect_timeout / fastcgi_read_timeout / fastcgi_send_timeout |
与 PHP-FPM 的超时时间,脚本执行慢导致 504 时需调大 |
fastcgi_buffer_size / fastcgi_buffers |
接收 PHP-FPM 响应的缓冲区 |
14.3 验证
cat > /usr/share/nginx/html/info.php <<'EOF'
<?php phpinfo(); ?>
EOF
nginx -t && nginx -s reload
curl http://127.0.0.1/info.php
浏览器访问 http://server-ip/info.php 出现 PHP 信息页即集成成功(测试完毕请删除该文件)。
15. HTTPS 配置
15.1 确认编译时包含 SSL 模块
Nginx 默认编译参数不包含 SSL 支持。在 ./configure 阶段必须显式加上:
./configure --with-http_ssl_module
make && make install
可通过下面的命令查看已编译进 Nginx 的参数,确认其中含有 --with-http_ssl_module:
/opt/nginx-1.8.0/sbin/nginx -V
# 或
/usr/local/nginx/sbin/nginx -V
15.2 openssl 生成自签证书(测试环境)
mkdir -p /usr/local/nginx/cert
cd /usr/local/nginx/cert
# 1. 生成 2048 位 RSA 私钥(不加密,避免启动时要求输入密码)
openssl genrsa -out server.key 2048
# 若需要带密码的私钥
openssl genrsa -des3 -out server-pass.key 2048
# 去掉私钥密码
openssl rsa -in server-pass.key -out server.key
# 2. 生成证书签名请求 CSR(交互式填写信息)
openssl req -new -key server.key -out server.csr
交互填写内容示例:
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Beijing
Locality Name (eg, city) [Default City]:Beijing
Organization Name (eg, company) [Default Company Ltd]:Example Inc
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:www.example.com
Email Address []:admin@example.com
A challenge password []: (直接回车)
Common Name 必须填写实际访问的域名,否则浏览器会提示证书与域名不匹配。
# 3. 用私钥自签证书,有效期 365 天
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# 一条命令直接生成私钥 + 自签证书(非交互)
openssl req -newkey rsa:2048 -nodes -keyout server.key \
-x509 -days 3650 -out server.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Example/CN=www.example.com"
# 4. 查看证书内容
openssl x509 -in server.crt -noout -text
openssl x509 -in server.crt -noout -dates # 查看有效期
# 5. 校验私钥与证书是否匹配(两条命令输出的 MD5 应一致)
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5
# 6. 收紧私钥权限
chmod 600 server.key
15.3 商业证书的准备与放置
从证书服务商处下载证书(通常为 .pem / .crt 与 .key 两个文件)。在 Nginx 安装目录下创建 cert 目录,将证书文件放入其中:
mkdir -p /opt/nginx-1.8.0/conf/cert
# 将下载好的证书上传到该目录,例如:
# 1991970_test.jiuhexian.cn.pem
# 1991970_test.jiuhexian.cn.key
.pem 是证书文件(包含公钥证书链),.key 是私钥文件,二者必须成对使用,且私钥文件权限建议设置为 600。
如果服务商提供了中间证书(CA bundle),需要把站点证书在前、中间证书在后拼接成一个文件,否则部分客户端会报证书链不完整:
cat server.crt intermediate.crt > fullchain.pem
15.4 443 SSL server 块配置
server {
listen 443 ssl;
server_name localhost;
ssl_certificate cert.pem;
ssl_certificate_key cert.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
商业证书 + 加密套件的完整示例:
# HTTPS server
server {
listen 443 ssl;
server_name www.tx97106.com; # 证书绑定的域名
ssl on;
root html;
index index.html index.htm;
ssl_certificate /usr/local/nginx/cert/1947226_www.tx97106.com.pem;
ssl_certificate_key /usr/local/nginx/cert/1947226_www.tx97106.com.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
SSL 关键配置项说明:
| 配置项 | 作用 |
|---|---|
listen 443 |
监听 HTTPS 默认端口(新版应写作 listen 443 ssl;) |
ssl on |
在该 server 块启用 SSL(Nginx 1.15 后已废弃,建议改用 listen 443 ssl;) |
ssl_certificate |
证书文件路径(.pem / .crt),可用相对 conf 目录的路径或绝对路径 |
ssl_certificate_key |
私钥文件路径(.key) |
ssl_session_cache |
SSL 会话缓存,shared:SSL:10m 表示所有 worker 共享 10MB |
ssl_session_timeout |
SSL 会话缓存超时时间 |
ssl_protocols |
启用的 TLS 协议版本,生产建议只保留 TLSv1.2 TLSv1.3 |
ssl_ciphers |
加密套件列表 |
ssl_prefer_server_ciphers |
优先使用服务端加密套件 |
ssl_stapling / ssl_stapling_verify |
启用 OCSP Stapling,加快证书状态校验 |
proxy_pass |
反向代理到后端的协议、地址与端口 |
现代推荐的安全基线:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:HIGH:!aNULL:!MD5:!RC4:!3DES;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_stapling_verify on;
15.5 Nginx 代理 HTTPS 后端
主配置 nginx.conf 通过 include 引入反向代理配置文件,代理配置单独放在 conf/reverse-proxy.conf:
http {
include mime.types;
default_type application/octet-stream;
include /opt/nginx-1.8.0/conf/reverse-proxy.conf;
# ... 其余全局代理缓冲、超时参数见第 9.3 节
}
reverse-proxy.conf 内容:
server {
listen 443;
server_name test.kaojiwang.cn; # 改成你的域名
ssl on;
index index.html index.htm;
# 证书与私钥路径(相对 conf 目录,也可写绝对路径)
ssl_certificate cert/1991970_test.jiuhexian.cn.pem;
ssl_certificate_key cert/1991970_test.jiuhexian.cn.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_pass https://120.77.145.44:8080; # 后端 HTTPS 服务地址
}
}
校验并重载配置:
/opt/nginx-1.8.0/sbin/nginx -t # 检查语法
/opt/nginx-1.8.0/sbin/nginx -s reload # 平滑重载
浏览器访问 https://test.kaojiwang.cn 即可验证证书与代理是否生效。
若后端使用的是自签证书,
proxy_pass https://...可能报证书校验错误,必要时可在location中加入proxy_ssl_verify off;(生产环境请慎用并配置正确的 CA)。
15.6 HTTP 强制跳转 HTTPS
再添加一个监听 80 端口的 server 块,将所有 HTTP 请求 301 重定向到 HTTPS。推荐使用 return 301:
server {
listen 80;
server_name www.tx97106.com; # 使用证书绑定的域名替换 localhost
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name www.tx97106.com;
# ssl_certificate / ssl_certificate_key 等配置同上
}
也可使用 rewrite 写法,效果等价:
server {
listen 80;
server_name www.tx97106.com;
rewrite ^(.*)$ https://$host$1 permanent;
}
两种写法对比:
| 写法 | 示例 | 说明 |
|---|---|---|
return 301 |
return 301 https://$server_name$request_uri; |
Nginx 官方推荐,执行效率高,语义清晰 |
rewrite ... permanent |
rewrite ^(.*)$ https://$host$1 permanent; |
通过正则重写,permanent 即 301 永久重定向 |
其中 $server_name 取自 server_name 指令,$host 取自请求头中的 Host,$request_uri 保留完整的请求路径与参数,确保跳转后路径不丢失。
校验并生效:
/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx -s reload
使用浏览器或 curl 验证跳转:
curl -I http://www.tx97106.com/
输出中可见 301 Moved Permanently 与 Location: https://... 即表示配置生效。
15.7 HSTS(HTTP 严格传输安全)
在 HTTPS 的 server 块中添加响应头,告知浏览器在指定时间内只能通过 HTTPS 访问本站,可防止 SSL 剥离攻击:
server {
listen 443 ssl;
server_name www.example.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
| 参数 | 说明 |
|---|---|
max-age=31536000 |
有效期(秒),31536000 即 1 年 |
includeSubDomains |
对所有子域名同样强制 HTTPS(确认所有子域都已支持 HTTPS 再加) |
preload |
申请加入浏览器 HSTS 预加载列表(提交后很难撤销,谨慎使用) |
always |
即使是错误响应也添加该头 |
验证:
curl -I https://www.example.com/ | grep -i strict
注意: HSTS 头只能加在 HTTPS 响应中;一旦下发,浏览器在
max-age内会拒绝 HTTP 访问,上线前务必确认证书链完整、续期机制正常。
16. systemd 管理 Nginx
通过源码 make install 安装的 Nginx 不会自动生成 systemd 服务单元,因此无法直接使用 systemctl 管理。下面手动创建 nginx.service,实现开机自启与统一的启停控制。
16.1 确认安装路径与 PID 文件
假设 Nginx 安装在 /usr/local/nginx,主程序为 /usr/local/nginx/sbin/nginx,配置文件为 /usr/local/nginx/conf/nginx.conf。
为了让 systemd 能正确跟踪进程,需要让 Nginx 把 PID 写入固定文件。在 nginx.conf 的全局段加入:
pid /var/run/nginx.pid;
16.2 创建 systemd 单元文件
在 /usr/lib/systemd/system/ 下新建 nginx.service:
vim /usr/lib/systemd/system/nginx.service
写入以下内容:
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
[Install]
WantedBy=multi-user.target
16.3 修改 [Service] 段以匹配源码安装路径
默认单元文件中的路径通常是发行版打包 Nginx 的路径(/usr/sbin/nginx、/etc/nginx/nginx.conf),需要改为源码安装的实际路径:
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
修改后的完整 [Service] 段为:
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
也可以加上启动前的语法检查与优雅退出(可选增强):
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStop=/bin/kill -s QUIT $MAINPID
LimitNOFILE=65535
16.4 单元文件字段说明
| 段 | 字段 | 说明 |
|---|---|---|
[Unit] |
Description |
服务描述 |
[Unit] |
Documentation |
文档地址 |
[Unit] |
After |
在指定 target 之后启动(网络、远程文件系统等) |
[Unit] |
Wants |
弱依赖,希望 network-online.target 就绪 |
[Service] |
Type=forking |
Nginx 启动后以守护进程方式 fork 到后台,systemd 据此识别主进程 |
[Service] |
PIDFile |
Nginx 主进程 PID 文件路径,须与 nginx.conf 中的 pid 指令一致 |
[Service] |
ExecStart |
启动命令,指定 nginx 可执行文件与 -c 配置文件路径 |
[Service] |
ExecReload |
重载命令,向主进程发送 HUP 信号实现平滑重载 |
[Service] |
ExecStop |
停止命令,向主进程发送 TERM 信号优雅退出 |
[Install] |
WantedBy |
设置为 multi-user.target,即在多用户命令行模式下开机自启 |
16.5 关闭原有进程并启用服务
如果之前已用二进制方式启动过 Nginx,需要先停止,避免端口冲突:
pkill -9 nginx
ps -aux | grep nginx
重新加载 systemd 配置,使其识别新建的单元文件:
systemctl daemon-reload
之后即可使用 systemctl 管理 Nginx:
systemctl start nginx # 启动
systemctl enable nginx # 设置开机自启
systemctl restart nginx # 重启
systemctl reload nginx # 平滑重载配置
systemctl status nginx # 查看运行状态
systemctl stop nginx # 停止
enable 执行后,systemd 会在 /etc/systemd/system/multi-user.target.wants/ 下建立 nginx.service 的软链接,从而实现开机自启。
16.6 验证
systemctl status nginx
ps -aux | grep nginx
ss -ntlp | grep nginx
若 status 显示 active (running),且 80/443 端口正常监听,则说明 systemd 已接管源码编译安装的 Nginx。
16.7 SysV 启动脚本(旧系统 / CentOS 6)
在没有 systemd 的环境中,可以编写 /etc/init.d/nginx 脚本:
vim /etc/init.d/nginx
#!/bin/bash
# chkconfig: - 30 21
# description: http service.
. /etc/init.d/functions
NGINX_SBIN="/usr/local/nginx/sbin/nginx"
NGINX_CONF="/usr/local/nginx/conf/nginx.conf"
NGINX_PID="/usr/local/nginx/logs/nginx.pid"
RETVAL=0
prog="Nginx"
start() {
echo -n $"Starting $prog: "
mkdir -p /dev/shm/nginx_temp
daemon $NGINX_SBIN -c $NGINX_CONF
RETVAL=$?
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc -p $NGINX_PID $NGINX_SBIN -TERM
rm -rf /dev/shm/nginx_temp
RETVAL=$?
echo
return $RETVAL
}
reload() {
echo -n $"Reloading $prog: "
killproc -p $NGINX_PID $NGINX_SBIN -HUP
RETVAL=$?
echo
return $RETVAL
}
restart() {
stop
start
}
configtest() {
$NGINX_SBIN -c $NGINX_CONF -t
return 0
}
case "$1" in
start) start ;;
stop) stop ;;
reload) reload ;;
restart) restart ;;
configtest) configtest ;;
*) echo $"Usage: $0 {start|stop|reload|restart|configtest}"
RETVAL=1 ;;
esac
exit $RETVAL
chmod 755 /etc/init.d/nginx
管理命令:
| 命令 | 说明 |
|---|---|
/etc/init.d/nginx start |
启动 |
/etc/init.d/nginx stop |
停止 |
/etc/init.d/nginx restart |
重启 |
/etc/init.d/nginx reload |
平滑重载 |
/etc/init.d/nginx configtest |
测试配置 |
chkconfig --add nginx |
加入系统服务 |
chkconfig nginx on |
开机自启 |
17. 性能调优
17.1 Nginx 配置层面
| 优化项 | 配置建议 |
|---|---|
| worker 进程数 | worker_processes auto,与 CPU 核心数一致 |
| CPU 亲和性 | worker_cpu_affinity auto(或按核显式绑定 0001 0010 0100 1000) |
| 单进程连接数 | worker_connections 65535(根据内存调整) |
| 文件描述符 | worker_rlimit_nofile 65535,配合 ulimit -SHn 65535 |
| 事件模型 | Linux 使用 use epoll,可搭配 multi_accept on |
| 文件传输 | sendfile on、tcp_nopush on、tcp_nodelay on |
| 长连接 | keepalive_timeout 65;upstream 中加 keepalive 32 复用到后端的连接 |
| Gzip 压缩 | gzip on,压缩级别 4-6 |
| 静态缓存 | expires 设置浏览器缓存 |
| 代理缓存 | proxy_cache 减轻后端压力 |
| 隐藏版本 | server_tokens off |
| 静态文件缓存元数据 | open_file_cache max=65535 inactive=60s; |
upstream 长连接示例(显著降低反向代理的 TIME_WAIT):
upstream backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
keepalive 32;
}
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
17.2 文件描述符与 limits
# 临时生效(当前 shell)
ulimit -n 65535
ulimit -SHn 65535
# 查看当前限制
ulimit -a
永久生效,编辑 /etc/security/limits.conf:
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
systemd 管理的服务不读取 limits.conf,需要在 unit 文件中设置:
[Service]
LimitNOFILE=65535
LimitNPROC=65535
systemctl daemon-reload
systemctl restart nginx
# 验证实际生效值
cat /proc/$(cat /var/run/nginx.pid)/limits | grep -i "open files"
17.3 内核参数优化
编辑 /etc/sysctl.conf(或 /etc/sysctl.d/99-nginx.conf):
# 系统级最大文件句柄数
fs.file-max = 655350
# 半连接队列长度(应对 SYN 洪泛与突发连接)
net.ipv4.tcp_max_syn_backlog = 65536
# 已完成连接队列长度,需与 listen backlog 配合
net.core.somaxconn = 65535
# 网卡接收数据包的队列
net.core.netdev_max_backlog = 32768
# socket 读写缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 允许 TIME_WAIT 套接字复用于新连接
net.ipv4.tcp_tw_reuse = 1
# 缩短 FIN_WAIT_2 与 TIME_WAIT 停留时间
net.ipv4.tcp_fin_timeout = 30
# TIME_WAIT 套接字最大数量,超出立即清理
net.ipv4.tcp_max_tw_buckets = 20000
# keepalive 探测
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# 可用的本地端口范围(反向代理需要大量对外连接)
net.ipv4.ip_local_port_range = 1024 65535
# SYN Cookie 防护
net.ipv4.tcp_syncookies = 1
生效并验证:
sysctl -p
sysctl net.core.somaxconn
net.ipv4.tcp_tw_recycle在 NAT 环境下会导致连接异常,且已在较新内核中移除,不要开启。
17.4 压测与观察
# ab 压测(httpd-tools 包)
ab -n 10000 -c 500 http://127.0.0.1/index.html
# 观察连接状态分布
ss -s
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
# 观察 Nginx 状态
curl http://127.0.0.1/nginx_status
调优过程中重点关注:stub_status 中 accepts 与 handled 是否相等(不等说明连接被丢弃)、错误日志中是否出现 worker_connections are not enough 或 too many open files。
18. 故障排查
18.1 通用排查步骤
nginx -t # 1. 配置语法
systemctl status nginx # 2. 服务状态
ss -ntlp | grep nginx # 3. 端口监听
tail -f /var/log/nginx/error.log # 4. 错误日志(最关键)
tail -f /var/log/nginx/access.log # 5. 访问日志与状态码
curl -I http://127.0.0.1/ # 6. 本机自测,排除网络与防火墙
getenforce; systemctl status firewalld # 7. SELinux 与防火墙
18.2 403 Forbidden 排查清单
| 可能原因 | 检查与解决 |
|---|---|
| 目录缺少默认首页且未开 autoindex | 确认 index 指定的文件存在,或临时 autoindex on |
| 文件/目录权限不足 | 目录需 755、文件需 644;namei -l /var/www/html/index.html 逐级检查 |
| 属主与 Nginx 运行用户不匹配 | ps -ef \| grep nginx 看 worker 用户,chown -R nginx:nginx /var/www/html |
nginx.conf 中 user 与实际不符 |
确认 main 段 user nginx; |
deny 规则命中 |
检查 allow / deny 顺序与 IP 段,注意局部覆盖全局 |
| SELinux 阻止 | getenforce;setenforce 0 临时验证;正式方案 chcon -R -t httpd_sys_content_t /var/www/html 或 restorecon -Rv /var/www/html |
| 网站根目录路径写错 | nginx -T \| grep root 确认实际生效的 root |
18.3 502 Bad Gateway 排查清单
502 表示 Nginx 连上了(或没连上)后端但没拿到合法响应,问题基本在后端或连接方式上。
| 可能原因 | 检查与解决 |
|---|---|
| 后端服务未启动 | systemctl status php-fpm / tomcat / 应用进程;ss -ntlp \| grep 9000 |
fastcgi_pass / proxy_pass 地址或端口写错 |
与后端实际监听地址核对(socket 路径、IP、端口) |
| Unix socket 权限问题 | socket 文件属主须与 Nginx worker 用户一致:listen.owner = nginx、listen.group = nginx,并 chown nginx.nginx /var/run/php-fpm/ |
| PHP-FPM 进程数耗尽 | 调大 pm.max_children、pm.max_requests;查看 php-fpm 日志中的 server reached max_children |
| 后端应用崩溃 / OOM | 查看后端日志与 dmesg \| grep -i oom |
| 后端返回响应头过大 | 调大 proxy_buffer_size、fastcgi_buffer_size 与 fastcgi_buffers |
| 防火墙 / SELinux 阻断到后端的连接 | setsebool -P httpd_can_network_connect 1 |
| upstream 全部被标记不可用 | 检查 max_fails / fail_timeout 是否过于激进,查看 $upstream_addr、$upstream_status |
18.4 504 Gateway Time-out 排查清单
504 表示后端在超时时间内没有返回响应,通常是后端处理太慢。
| 可能原因 | 检查与解决 |
|---|---|
| 后端脚本执行时间过长 | 优化 SQL / 代码;把耗时任务改为异步队列 |
| 代理超时设置过小 | 调大 proxy_connect_timeout、proxy_send_timeout、proxy_read_timeout(如 300s) |
| FastCGI 超时过小 | 调大 fastcgi_connect_timeout、fastcgi_send_timeout、fastcgi_read_timeout |
| PHP 自身超时 | php.ini 中 max_execution_time;php-fpm 的 request_terminate_timeout |
| 后端数据库慢 / 锁等待 | 检查慢查询日志、show processlist |
| 后端 worker 全忙排队 | 增加后端实例或调整进程池大小 |
定位耗时的最快方式是在日志格式中加入 rt=$request_time urt=$upstream_response_time,对比 Nginx 总耗时与后端耗时。
18.5 其他常见错误
| 现象 | 原因与处理 |
|---|---|
bind() to 0.0.0.0:80 failed (98: Address already in use) |
端口被占用:ss -ntlp \| grep :80,停掉旧进程(pkill -9 nginx)或改端口 |
too many open files |
文件描述符不足:调大 worker_rlimit_nofile、ulimit -n、LimitNOFILE |
worker_connections are not enough |
调大 worker_connections,并确认不超过 worker_rlimit_nofile |
413 Request Entity Too Large |
调大 client_max_body_size |
404 但文件确实存在 |
root / alias 路径拼接错误;用 nginx -T 查看生效配置,或在 error_log 中看拼出的完整路径 |
500 Internal Server Error |
多为动态脚本报错,查看后端应用日志;rewrite 循环超过 10 次也会 500 |
| PHP 页面被下载而不是执行 | 缺少 location ~ \.php$ 的 fastcgi 配置 |
File not found(PHP) |
SCRIPT_FILENAME 指向的路径不存在,检查 root 与 $document_root$fastcgi_script_name |
| HTTPS 提示证书不受信任 | 自签证书属正常现象;商业证书需检查证书链是否拼接完整、Common Name 是否匹配域名 |
| 修改配置无效 | 忘记 nginx -s reload;或修改的是未被 include 的文件;或被浏览器缓存 |
19. 完整生产配置示例
user nginx nginx;
worker_processes auto;
worker_cpu_affinity auto;
error_log logs/error.log warn;
pid logs/nginx.pid;
worker_rlimit_nofile 65535;
events {
use epoll;
worker_connections 65535;
}
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" '
'"$upstream_cache_status"';
access_log logs/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Gzip 压缩
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_types text/plain text/css text/javascript application/json
application/javascript application/xml;
gzip_vary on;
# 客户端请求设置
client_max_body_size 20m;
client_body_buffer_size 128k;
# 代理设置
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
# 负载均衡
upstream backend {
server 10.0.0.11:8080 weight=1 max_fails=2 fail_timeout=30s;
server 10.0.0.12:8080 weight=1 max_fails=2 fail_timeout=30s;
}
# HTTP 虚拟主机
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.html index.htm index.php;
charset utf-8;
access_log logs/www.access.log main;
# 静态资源由 Nginx 直接处理
location ~* \.(gif|jpg|jpeg|png|ico|css|js|svg|woff2?)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 动态请求转发到后端
location / {
proxy_pass http://backend;
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_next_upstream error timeout http_502 http_503;
}
# PHP 解析
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/fastcgi.socket;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 状态监控
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
# 禁止访问敏感目录
location ~ ^/(WEB-INF)/ {
deny all;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
# HTTPS 虚拟主机
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/www.example.com.pem;
ssl_certificate_key /etc/nginx/ssl/www.example.com.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
root /var/www/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
}
20. 练习
20.1 安装与基础配置
- 在 CentOS 7 上分别用 YUM 和源码两种方式安装 Nginx,写出源码方式所需的依赖包清单,并说明每个依赖对应哪个 Nginx 模块。
- 源码编译时要求同时启用 SSL、gzip 静态压缩和状态监控三个模块,写出完整的
./configure命令。 - 用
nginx -V验证已编译的模块;用nginx -t校验配置;用nginx -s reload平滑生效。说明nginx -s stop与nginx -s quit的区别。 - 画出 Nginx 的 master / worker 进程模型,并说明
HUP、USR1、USR2三个信号各自的用途。
20.2 虚拟主机与静态资源
- 在一台机器上同时配置三个虚拟主机:基于端口(80 / 8080)、基于域名(
www.test.com/bbs.test.com)、基于 IP(主 IP 与ens33:0虚拟 IP),并用curl分别验证。 - 为
/download/目录开启目录浏览,要求显示人类可读的文件大小和服务器本地时间。 - 为图片、CSS、JS 设置 30 天浏览器缓存,用
curl -I验证响应头中出现Expires与Cache-Control。 - 自定义 404 与 50x 错误页面并验证。
20.3 访问控制与日志
- 只允许
192.168.10.0/24访问/nginx_status,其余全部拒绝,并叠加 basic auth 认证(用htpasswd创建admin与test两个用户)。 - 定义一个包含
$request_time、$upstream_addr、$upstream_response_time、$upstream_cache_status的日志格式,并只对某个虚拟主机生效。 - 编写日志切割脚本,按
年/月/日目录归档昨天的 access.log,并通过 crontab 每天 2:01 执行;再用logrotate实现同样的效果,说明两者都必须发送USR1信号的原因。
20.4 反向代理与负载均衡
- 搭建 Nginx(双网卡)+ 两台后端 Web 的反向代理环境,配置
proxy_set_header使后端日志能记录到客户端真实 IP。 - 实现动静分离:
.html/.jpg/.css/.js请求转发到 web1,.php/.cgi请求转发到 web2,并验证。 - 配置 upstream,要求:web1 权重 3、web2 权重 1、web3 作为 backup、web4 标记 down,失败 2 次后 30 秒内不再调度。停掉 web1 与 web2,验证 backup 是否接管。
- 分别用
ip_hash和least_conn测试调度效果,说明ip_hash在同网段客户端测试时可能出现的现象及原因。 - 说明
proxy_pass http://backend;与proxy_pass http://backend/;在location /nba/下的转发路径差异。
20.5 缓存
- 配置
proxy_cache:缓存目录levels=1:2、共享内存 200MB、1 天未访问淘汰、最大 5GB,对 200/304 缓存 10 分钟,并通过X-Cache响应头验证 MISS → HIT 的变化。 - 编写脚本清除所有
.png结尾的缓存文件;再用ngx_cache_purge模块实现通过 URL 清除指定缓存。 - 使用
hash $request_uri对两台缓存服务器做负载均衡,说明它为什么能提高缓存命中率。
20.6 rewrite
- 实现
example.com到www.example.com的 301 跳转,分别写出return和rewrite两种写法。 - 实现伪静态:
/article-123.html→/article.php?id=123,并说明last与break的区别。 - 配置防盗链:非本站 Referer 请求图片时返回 403。
- 检测移动端 User-Agent 并跳转到
m.example.com。
20.7 HTTPS
- 用
openssl生成 2048 位私钥与有效期 365 天的自签证书(Common Name 为www.test.com),配置 443 端口的 SSL server 并验证。 - 校验私钥与证书是否匹配(对比两条
openssl ... modulus | openssl md5的输出)。 - 配置 HTTP 强制跳转 HTTPS,用
curl -I验证返回301与Location头。 - 只保留
TLSv1.2 TLSv1.3,配置推荐加密套件,并添加 HSTS 响应头(1 年、包含子域),说明preload的风险。
20.8 systemd 与调优排错
- 为源码安装的 Nginx 编写
nginx.service,要求PIDFile与nginx.conf中的pid一致,实现start/stop/reload/enable,并验证开机自启软链接的位置。 - 把 Nginx 的文件描述符上限提到 65535:分别通过
ulimit、limits.conf、worker_rlimit_nofile、systemd 的LimitNOFILE四处配置,并用/proc/<pid>/limits验证实际生效值。 - 写出至少 6 个与高并发相关的内核参数及其作用,并说明为什么不应开启
tcp_tw_recycle。 - 故障演练:分别人为制造 403(权限/SELinux)、502(停掉 php-fpm)、504(后端 sleep 超时)三种故障,记录 error.log 中的报错原文和你的排查步骤。
- 用
ab -n 10000 -c 500压测,对比开启 / 关闭 gzip、开启 / 关闭 upstreamkeepalive时的 QPS 差异。
本文档涵盖 Nginx 从安装、配置到生产实战的完整知识体系。修改配置后务必执行
nginx -t验证语法,再通过nginx -s reload平滑生效。
此处评论已关闭