Nginx: 高性能 Web 服务器

Nginx (发音为 "engine-x") 是一款高性能的HTTP和反向代理服务器。本交互式手册将帮助您从入门到精通,掌握其核心概念与实践。

高并发与高性能

采用异步、事件驱动架构,单个工作进程可处理数千并发连接,内存占用极低。

强大的反向代理

作为反向代理,可实现负载均衡、SSL终止、缓存静态内容,提升应用安全性和可伸缩性。

灵活的负载均衡

支持轮询、最少连接、IP哈希等多种算法,有效分发流量至后端服务器集群。

Nginx vs. Apache

特性 Nginx Apache
架构模型 事件驱动,异步非阻塞 进程驱动/线程驱动
并发处理 非常高,资源消耗低 良好,高并发下资源消耗高
静态内容 性能极高 良好
动态内容 通过FastCGI等代理给后端处理 可内嵌模块 (mod_php) 直接处理

安装指南

根据您的操作系统平台,选择对应的安装方式。我们推荐使用官方源或稳定可靠的软件仓库进行安装。

Ubuntu
CentOS
Docker
WSL

在 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 的配置由一系列指令和块组成。理解其层级结构是配置的关键。点击下方图示的不同区块来查看其核心指令和作用。

user www-data;
worker_processes auto;
events {
worker_connections 768;
}
http {
server {
listen 80;
server_name example.com;
location / {
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`。尝试调整下方参数,查看理论最大值。

理论最大连接数: 4096

启用 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