Nginx: 高性能 Web 服务器
Nginx (发音为 "engine-x") 是一款高性能的HTTP和反向代理服务器。本交互式手册将帮助您从入门到精通,掌握其核心概念与实践。
高并发与高性能
采用异步、事件驱动架构,单个工作进程可处理数千并发连接,内存占用极低。
强大的反向代理
作为反向代理,可实现负载均衡、SSL终止、缓存静态内容,提升应用安全性和可伸缩性。
灵活的负载均衡
支持轮询、最少连接、IP哈希等多种算法,有效分发流量至后端服务器集群。
Nginx vs. Apache
| 特性 | Nginx | Apache |
|---|---|---|
| 架构模型 | 事件驱动,异步非阻塞 | 进程驱动/线程驱动 |
| 并发处理 | 非常高,资源消耗低 | 良好,高并发下资源消耗高 |
| 静态内容 | 性能极高 | 良好 |
| 动态内容 | 通过FastCGI等代理给后端处理 | 可内嵌模块 (mod_php) 直接处理 |
安装指南
根据您的操作系统平台,选择对应的安装方式。我们推荐使用官方源或稳定可靠的软件仓库进行安装。
在 Ubuntu 上安装
使用 `apt` 包管理器是最直接的方式。
1. 更新包列表并安装 Nginx:
sudo apt update
sudo apt install nginx
2. 配置防火墙 (UFW):
sudo ufw allow 'Nginx Full'
sudo ufw enable
在 CentOS 上安装
推荐使用 EPEL 仓库或 Nginx 官方仓库。
1. 安装 EPEL 并安装 Nginx:
sudo yum install epel-release -y
sudo yum install nginx -y
2. 启动服务并配置防火墙:
sudo systemctl start nginx
sudo systemctl enable nginx
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
使用 Docker 部署
Docker 提供了轻量、隔离的部署环境。
1. 运行一个简单的 Nginx 容器:
docker run --name my-nginx -p 8080:80 -d nginx
此命令会将主机的 8080 端口映射到容器的 80 端口。
2. 挂载自定义内容和配置:
docker run --name my-custom-nginx -p 8080:80 -d \
-v /path/to/your/content:/usr/share/nginx/html:ro \
-v /path/to/your/conf.d:/etc/nginx/conf.d:ro \
nginx
在 WSL (Windows Subsystem for Linux) 上安装
安装过程与在原生 Linux 发行版 (如Ubuntu) 上基本一致。
1. 在您的 WSL (Ubuntu) 终端中执行:
sudo apt update
sudo apt install nginx
2. 启动服务:
sudo service nginx start
WSL 可能不支持 `systemctl`,请使用 `service` 命令。启动后,您可以在 Windows 浏览器中通过 `http://localhost` 访问。
Nginx 工作模型
Nginx 的高性能归功于其独特的 **Master-Worker** 进程模型和**事件驱动**架构。这个组合使其能以极低的资源消耗处理海量并发连接。
Master-Worker 进程模型
Nginx 启动后,会创建一个 Master 主进程和数个 Worker 工作进程。
Master 进程
- **不处理请求**:只负责管理 Worker 进程。
- **读取配置**:解析并验证配置文件。
- **绑定端口**:执行需要 root 权限的操作,如绑定到 80/443 端口。
- **管理 Worker**:启动、停止、监控 Worker 进程,并在 Worker 异常退出时重启它。
- **平滑重载**:接收到 `nginx -s reload` 信号后,启动带有新配置的 Worker 进程,并通知旧 Worker 进程在处理完当前请求后优雅退出。
Worker 进程
- **处理所有请求**:每个 Worker 都是一个独立的单线程进程,负责接收、处理和响应客户端请求。
- **低权限运行**:以 `nginx.conf` 中指定的非特权用户(如 `www-data`)身份运行,增强安全性。
- **数量配置**:`worker_processes` 指令通常设置为服务器的 CPU 核心数,以充分利用硬件。
事件驱动架构
这是 Nginx 高并发能力的核心。与传统“一个连接一个进程/线程”的模型不同,Nginx 的单个 Worker 进程可以处理数千个连接。
- **非阻塞 I/O**:当一个操作(如读写网络数据)需要等待时,Worker 进程不会被阻塞。它会注册一个事件,然后继续处理其他就绪的连接。
- **事件通知机制**:使用高效的系统调用(如 Linux 上的 `epoll`)来监听大量连接上的事件(新连接、数据可读等)。
- **资源高效**:极大地减少了内存占用和CPU上下文切换的开销,因为不需要为每个连接维护独立的进程或线程堆栈。
配置文件结构
Nginx 的配置由一系列指令和块组成。理解其层级结构是配置的关键。点击下方图示的不同区块来查看其核心指令和作用。
worker_processes auto;
worker_connections 768;
}
listen 80;
server_name example.com;
root /var/www/html;
try_files $uri /index.html;
}
}
http 块
定义HTTP服务器的主要配置,所有 `server` 块都位于此块内。
include mime.types;: 包含MIME类型映射文件。access_log: 设置访问日志的路径和格式。sendfile on;: 启用高效的文件传输模式。keepalive_timeout: 设置长连接的超时时间。
静态内容服务
Nginx 在服务静态文件(如HTML, CSS, JS, 图片)方面极为高效。核心指令是 `root` 和 `alias`。
`root` 指令
将请求的 URI 附加到 `root` 指定的路径后,形成完整的文件路径。
location /images/ {
root /data/www;
}
# 请求 /images/cat.jpg
# -> 查找 /data/www/images/cat.jpg
`alias` 指令
用 `alias` 指定的路径替换掉 `location` 匹配的URI部分。
location /images/ {
alias /data/assets/;
}
# 请求 /images/cat.jpg
# -> 查找 /data/assets/cat.jpg
单页应用 (SPA) 配置示例
`try_files` 是配置Vue、React等单页应用的关键,它将所有找不到文件的请求都转发给 `index.html`,交由前端路由处理。
server {
listen 80;
server_name my-spa.com;
root /var/www/my-spa/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
反向代理
Nginx 最核心的功能之一。它接收客户端请求,转发给后端应用服务器,并将响应返回给客户端。
基本配置
使用 `proxy_pass` 将请求代理到后端。同时,使用 `proxy_set_header` 将客户端的真实信息(如IP地址、Host)传递给后端。
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
代理 WebSocket
代理 WebSocket 需要正确处理 `Upgrade` 和 `Connection` 头部,以完成协议升级。
location /socket/ {
proxy_pass http://backend_websocket_server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s; # 保持长连接
}
负载均衡
通过 `upstream` 模块将流量分发到多个后端服务器,提高应用的可用性和可伸缩性。点击下方按钮,查看不同算法如何分发10个模拟请求。
Upstream 配置示例
http {
upstream my_backend {
# least_conn; # 或者 ip_hash;
server backend1.example.com weight=3;
server backend2.example.com;
server backend3.example.com backup;
}
server {
location / {
proxy_pass http://my_backend;
}
}
}
性能优化
通过调整 Worker 进程和连接处理参数,可以显著提升 Nginx 在高负载下的表现。
Worker 配置
`worker_processes` 通常应设置为服务器的CPU核心数,以充分利用硬件资源并减少上下文切换。
# 通常在 nginx.conf 的顶层
worker_processes auto;
连接数计算器
服务器最大连接数约等于 `worker_processes` × `worker_connections`。尝试调整下方参数,查看理论最大值。
启用 Gzip 压缩
压缩响应体可以显著减少传输数据量,加快客户端加载速度。这是最基本也是最有效的优化手段之一。
# 在 http 块中添加
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
安全加固
配置 Nginx 以增强 Web 应用的安全性,防止常见攻击。
配置 SSL/TLS (HTTPS)
为您的站点启用 HTTPS 是安全的基础。使用强加密协议和套件,并自动将 HTTP 重定向到 HTTPS。
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
}
限制请求速率
使用 `limit_req_zone` 和 `limit_req` 指令可以防止暴力破解和 DoS 攻击。
# 在 http 块中
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
# 在 server 或 location 块中
location /login {
limit_req zone=mylimit burst=20 nodelay;
# ... proxy_pass ...
}
内容缓存
Nginx 可以缓存来自后端服务器的响应,极大地提升性能并降低后端负载。这对于不经常变化的动态内容或静态API响应尤其有效。
配置缓存路径和区域
首先,需要在 `http` 块中使用 `proxy_cache_path` 定义一个缓存区域。
# 在 http 块中
proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache_zone:10m max_size=10g inactive=60m use_temp_path=off;
/var/cache/nginx/my_cache: 缓存文件在磁盘上的存储路径。levels=1:2: 缓存目录的层级结构,有助于提升查找效率。keys_zone=my_cache_zone:10m: 在共享内存中创建一个名为 `my_cache_zone` 的区域,大小为 10MB,用于存储缓存键和元数据。max_size=10g: 缓存总大小的上限。inactive=60m: 如果缓存在 60 分钟内未被访问,则将其从缓存中删除。
在 Location 中启用缓存
在需要缓存的 `location` 块中,使用 `proxy_cache` 指令引用之前定义的缓存区域。
location /api/data/ {
proxy_pass http://backend_api;
proxy_cache my_cache_zone; # 启用名为 my_cache_zone 的缓存
proxy_cache_valid 200 302 10m; # 对 200 和 302 响应缓存 10 分钟
proxy_cache_valid 404 1m; # 对 404 响应缓存 1 分钟
proxy_cache_key "$scheme$request_method$host$request_uri"; # 定义缓存键
# 在响应头中添加缓存状态,便于调试
add_header X-Proxy-Cache $upstream_cache_status;
}
响应头中的 `X-Proxy-Cache` 将显示 `HIT` (命中缓存)、`MISS` (未命中)、`EXPIRED` (缓存过期)等状态,非常有助于调试。
URL 重写
Nginx 的 `ngx_http_rewrite_module` 模块允许您使用正则表达式修改请求 URI,实现 URL 清理、重定向或内部路由。
`rewrite` 指令
`rewrite` 是核心指令,语法为:`rewrite regex replacement [flag];`
指令参数
regex: 用于匹配请求 URI 的 PCRE 正则表达式。replacement: 如果正则匹配成功,用于替换 URI 的字符串。可以包含正则表达式的捕获组(如 `$1`, `$2`)。flag: (可选) 控制重写行为的标志。
重写标志 (Flags)
last: 停止处理当前 `rewrite` 模块的指令集,并使用重写后的 URI 开始新一轮的 `location` 匹配。break: 停止处理当前 `rewrite` 模块的指令集,像 `break` 在 `server` 块中一样,但重写后的 URI 不会重新匹配 `location`。redirect: 返回一个 302 临时重定向。permanent: 返回一个 301 永久重定向。
重写示例
将旧 API 路径重写为新路径
# /users/123 -> /api/v1/users/123
rewrite ^/users/(.*)$ /api/v1/users/$1 last;
HTTP 到 HTTPS 的永久重定向
server {
listen 80;
server_name example.com;
# 虽然 return 更好,但 rewrite 也能实现
rewrite ^ https://$host$request_uri? permanent;
}
**最佳实践**: 尽可能使用 `return` 指令进行简单的重定向,因为它更高效。对于需要捕获和重组 URI 的复杂逻辑,`rewrite` 是不二之选。避免在 `if` 指令中使用 `rewrite`,因为这可能导致不可预测的行为。
常见错误排查
当 Nginx 遇到问题时,它会返回特定的 HTTP 状态码。理解这些错误的含义是快速定位和解决问题的关键。
502 Bad Gateway
**含义**: Nginx 作为代理,从后端服务器收到了一个无效的响应。
常见原因与解决方案
- **后端服务未运行或崩溃**: 确保您的应用服务器(如 Node.js, PHP-FPM, uWSGI)正在运行。检查其日志文件以寻找错误。
- **Nginx 配置错误**: 检查 `proxy_pass` 指令中的地址和端口是否正确,确保 Nginx 可以访问到后端服务。
- **防火墙或网络问题**: 确保 Nginx 服务器和后端服务器之间的网络是通的,没有防火墙规则阻止它们通信。
- **后端服务过载**: 如果后端服务因请求过多而无响应,可能会导致 502。考虑优化后端或增加服务器数量。
504 Gateway Timeout
**含义**: Nginx 作为代理,在等待后端服务器响应时超时。
常见原因与解决方案
- **后端处理时间过长**: 后端应用执行一个耗时操作(如复杂的数据库查询或大文件处理)超过了 Nginx 的超时设置。
# 增加超时时间 proxy_read_timeout 300s; proxy_connect_timeout 300s; proxy_send_timeout 300s; - **网络延迟**: Nginx 与后端服务器之间的网络连接缓慢或不稳定。
- **后端服务负载高**: 与 502 类似,后端服务过载也可能导致响应缓慢,最终超时。
413 Content Too Large
**含义**: 客户端发送的请求体(如文件上传)的大小超过了 Nginx 配置的上限。
解决方案
- 在 `http`, `server`, 或 `location` 块中增加 `client_max_body_size` 的值。
# 允许最大 100MB 的请求体 client_max_body_size 100M;
常用指令速查
一份快速参考,涵盖了配置 Nginx 时最常用的一些指令和变量。
核心指令
server { ... }: 定义虚拟主机。location [modifier] /uri/ { ... }: 定义URI路由。listen <port>;: 监听端口。server_name <name>;: 定义主机名。root <path>;: 设置文档根目录。index <file>;: 设置索引文件。try_files <file...> <uri>;: 检查文件是否存在。proxy_pass <url>;: 代理请求。upstream <name> { ... }: 定义后端服务器池。return <code> [text|URL];: 返回响应或重定向。rewrite <regex> <replacement> [flag];: 重写URL。
常用变量
$host: 请求的主机名。$uri: 当前请求的URI (不带参数)。$request_uri: 原始请求的完整URI (带参数)。$args/$query_string: 请求参数。$remote_addr: 客户端IP地址。$scheme: 请求协议 (http/https)。$request_method: 请求方法 (GET, POST)。$document_root: 当前请求的根目录。$request_filename: 映射到的文件系统路径。$http_<header>: 获取请求头,如$http_user_agent。