项目介绍

Nginx(发音 "engine-x")是由 Igor Sysoev 于 2004 年发布的高性能 HTTP 和反向代理服务器,同时也是 IMAP/POP3 代理服务器。它以事件驱动(event-driven)的异步非阻塞架构闻名,能以极低的内存占用处理数万并发连接。

根据 W3Techs 统计,Nginx 是全球使用量最大的 Web 服务器,为超过 30% 的网站提供服务,包括 Netflix、Airbnb、Dropbox 等知名企业。2019 年 F5 Networks 收购了 Nginx Inc.,但开源版本仍然活跃维护。

项目信息详情
开发团队F5 / Nginx Inc.(原作者 Igor Sysoev)
GitHub Stars26,000+
官方网站nginx.org
开源协议BSD-2-Clause License
技术栈C 语言
架构模型事件驱动(Event-Driven)、异步非阻塞
主要用途Web 服务器 / 反向代理 / 负载均衡 / HTTP 缓存
一句话理解:Nginx 就像互联网的"交通调度中心" — 接收所有用户请求,把它们高效地分发给后端应用,同时负责 HTTPS 加密、静态文件服务、缓存加速等工作。

Nginx vs Apache vs Caddy vs Traefik

对比维度 Nginx Apache Caddy Traefik
架构模型 事件驱动、异步非阻塞 进程/线程模型(MPM) Go 协程 Go 协程
高并发性能 极强(C10K+) 较弱(重线程) 良好 良好
内存占用 极低 较高 中等 中等
配置方式 自定义配置文件 httpd.conf / .htaccess Caddyfile(极简) 自动发现(Docker 标签)
HTTPS 自动化 需手动配置 Certbot 需手动配置 全自动 HTTPS 全自动 HTTPS
模块/插件 丰富(编译时加载) 最丰富(运行时加载) Go 插件系统 中间件
容器编排支持 需手动配置 需手动配置 一般 原生 Docker/K8s
学习曲线 中等 中等 简单 中等
适用场景 高并发生产环境 传统 PHP 托管 小型项目/快速部署 微服务/容器化部署
选择建议:追求极致性能和灵活配置选 Nginx;需要自动 HTTPS 和零配置体验选 Caddy;Docker/K8s 环境优先考虑 Traefik;传统 PHP 项目可用 Apache。大多数生产环境推荐 Nginx。

安装部署

方式 1 包管理器安装(推荐)

各大 Linux 发行版都内置 Nginx 包,一条命令即可安装:
# Ubuntu / Debian
sudo apt update
sudo apt install nginx -y

# CentOS / RHEL / Rocky Linux
sudo yum install epel-release -y
sudo yum install nginx -y

# Arch Linux
sudo pacman -S nginx

# macOS (Homebrew)
brew install nginx
安装后常用命令:
# 启动
sudo systemctl start nginx

# 开机自启
sudo systemctl enable nginx

# 查看状态
sudo systemctl status nginx

# 测试配置文件语法
sudo nginx -t

# 重新加载配置(不中断服务)
sudo nginx -s reload

方式 2 源码编译安装

需要自定义模块或最新版本时,使用源码编译:
# 安装编译依赖
sudo apt install build-essential libpcre3 libpcre3-dev zlib1g-dev libssl-dev libgeoip-dev -y

# 下载源码
wget https://nginx.org/download/nginx-1.26.2.tar.gz
tar -xzf nginx-1.26.2.tar.gz
cd nginx-1.26.2

# 配置(带常用模块)
./configure \
  --prefix=/etc/nginx \
  --sbin-path=/usr/sbin/nginx \
  --conf-path=/etc/nginx/nginx.conf \
  --error-log-path=/var/log/nginx/error.log \
  --http-log-path=/var/log/nginx/access.log \
  --pid-path=/var/run/nginx.pid \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_gzip_static_module \
  --with-http_stub_status_module

# 编译 & 安装
make && sudo make install
注意:源码编译安装需要手动创建 systemd 服务文件。生产环境建议使用官方仓库安装以获得安全更新。

方式 3 Docker 部署

适合容器化环境,快速启动:
# 快速启动
docker run -d --name nginx \
  -p 80:80 -p 443:443 \
  -v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \
  -v /path/to/html:/usr/share/nginx/html:ro \
  nginx:alpine
Docker Compose(推荐):
# docker-compose.yml version: "3.8" services: nginx: image: nginx:alpine restart: always ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./conf.d:/etc/nginx/conf.d:ro - ./html:/usr/share/nginx/html:ro - ./certs:/etc/nginx/certs:ro - ./logs:/var/log/nginx
提示:使用 nginx:alpine 镜像体积仅约 40MB,比默认镜像小 3 倍以上。

核心配置

配置 1 nginx.conf 整体结构

Nginx 配置文件采用层级结构,主配置文件通常在 /etc/nginx/nginx.conf
# 全局块 — 影响 Nginx 整体运行 user nginx; worker_processes auto; # 自动匹配 CPU 核心数 error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; # events 块 — 连接处理配置 events { worker_connections 1024; # 每个 worker 最大连接数 use epoll; # Linux 高效事件模型 multi_accept on; # 一次接受多个新连接 } # http 块 — HTTP 服务配置 http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # 引入独立站点配置 include /etc/nginx/conf.d/*.conf; }

配置 2 Server Block(虚拟主机)

每个 server 块定义一个虚拟主机,类似 Apache 的 VirtualHost:
# /etc/nginx/conf.d/example.conf server { listen 80; server_name example.com www.example.com; root /var/www/example; index index.html index.htm; # 访问日志 access_log /var/log/nginx/example.access.log; error_log /var/log/nginx/example.error.log; # 默认 location location / { try_files $uri $uri/ =404; } # 静态资源缓存 location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ { expires 30d; add_header Cache-Control "public, immutable"; } }
最佳实践:每个站点使用独立的配置文件放在 /etc/nginx/conf.d/ 目录下,而不是直接修改 nginx.conf 主文件。

配置 3 Location 匹配规则

Location 指令决定如何处理不同的 URL 路径,优先级从高到低:
# 1. 精确匹配(最高优先级) location = /api/health { return 200 "OK"; } # 2. 前缀匹配(优先于正则) location ^~ /static/ { root /var/www; } # 3. 正则匹配(区分大小写) location ~ \.php$ { ... } # 4. 正则匹配(不区分大小写) location ~* \.(jpg|png|gif)$ { ... } # 5. 普通前缀匹配 location /api/ { ... } # 6. 默认匹配(最低优先级) location / { ... }
注意:正则匹配按照配置文件中的顺序执行,第一个匹配的规则生效。前缀匹配则选择最长匹配。

配置 4 Upstream(上游服务器组)

Upstream 定义一组后端服务器,用于负载均衡和反向代理:
upstream backend { # 负载均衡策略(默认轮询) # least_conn; # 最少连接 # ip_hash; # IP 哈希(会话保持) # hash $request_uri consistent; # 一致性哈希 server 127.0.0.1:3000 weight=3; # 权重 3 server 127.0.0.1:3001 weight=2; # 权重 2 server 127.0.0.1:3002 backup; # 备用服务器 # 健康检查参数 server 127.0.0.1:3003 max_fails=3 fail_timeout=30s; # 长连接复用 keepalive 32; }

反向代理实战

场景 1 反向代理 Node.js / Python 应用

最常见的使用场景 — 将 Nginx 作为前端代理转发请求到后端应用:
server { listen 80; server_name app.example.com; location / { 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; } }
提示:X-Real-IPX-Forwarded-For 头部让后端应用能获取到客户端的真实 IP,而非 Nginx 的 IP。

场景 2 负载均衡

将流量分发到多个后端实例:
upstream app_cluster { least_conn; # 最少连接策略 server 10.0.0.1:3000; server 10.0.0.2:3000; server 10.0.0.3:3000; keepalive 32; } server { listen 80; server_name app.example.com; location / { proxy_pass http://app_cluster; proxy_http_version 1.1; proxy_set_header Connection ""; } }

场景 3 WebSocket 代理

WebSocket 需要特殊的头部处理来支持协议升级:
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name ws.example.com; location /ws { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_read_timeout 86400s; # 长连接超时 } }

场景 4 gRPC 代理

Nginx 1.13.10+ 支持原生 gRPC 代理:
server { listen 443 ssl http2; server_name grpc.example.com; ssl_certificate /etc/nginx/certs/fullchain.pem; ssl_certificate_key /etc/nginx/certs/privkey.pem; location / { grpc_pass grpc://127.0.0.1:50051; error_page 502 = /error502grpc; } location = /error502grpc { internal; default_type application/grpc; add_header grpc-status 14; add_header grpc-message "upstream unavailable"; return 204; } }

场景 5 代理缓存

缓存后端响应,大幅减少后端压力:
# 在 http 块中定义缓存区 proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off; server { location /api/ { proxy_pass http://backend; proxy_cache my_cache; proxy_cache_valid 200 302 10m; # 200/302 缓存 10 分钟 proxy_cache_valid 404 1m; # 404 缓存 1 分钟 proxy_cache_use_stale error timeout updating http_500 http_502 http_503; add_header X-Cache-Status $upstream_cache_status; } }

场景 6 限流(Rate Limiting)

防止恶意请求和 DDoS 攻击:
# 在 http 块中定义限流区 limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; limit_conn_zone $binary_remote_addr zone=conn_limit:10m; server { location /api/ { limit_req zone=api_limit burst=20 nodelay; limit_conn conn_limit 10; # 每 IP 最多 10 个并发连接 limit_req_status 429; # 超限返回 429 proxy_pass http://backend; } }
参数解读:rate=10r/s 表示每秒 10 个请求,burst=20 允许突发 20 个请求排队,nodelay 表示突发请求不延迟立即处理。

场景 7 基础认证(Basic Auth)

为管理后台或内部 API 添加密码保护:
# 生成密码文件 # sudo apt install apache2-utils # sudo htpasswd -c /etc/nginx/.htpasswd admin server { location /admin/ { auth_basic "Admin Area"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://127.0.0.1:8080; } }

场景 8 基于地理位置路由

使用 GeoIP 模块根据访客 IP 所在地区分流:
# 需要编译 --with-http_geoip_module geoip_country /usr/share/GeoIP/GeoIP.dat; map $geoip_country_code $backend { default http://us-backend; CN http://cn-backend; JP http://jp-backend; } server { location / { proxy_pass $backend; } }

场景 9 健康检查

被动健康检查(开源版)会在请求失败时自动摘除后端节点:
upstream backend { server 10.0.0.1:3000 max_fails=3 fail_timeout=30s; server 10.0.0.2:3000 max_fails=3 fail_timeout=30s; server 10.0.0.3:3000 backup; # 主节点都挂掉时启用 }
说明:max_fails=3 表示连续失败 3 次后标记为不可用,fail_timeout=30s 表示 30 秒后重新尝试。主动健康检查需要 Nginx Plus 或使用第三方模块 nginx_upstream_check_module

场景 10 蓝绿部署 / 灰度发布

利用 Nginx 实现零停机部署和灰度发布:
# 蓝绿部署:通过切换 upstream 实现 upstream blue { server 10.0.0.1:3000; } upstream green { server 10.0.0.2:3000; } # 灰度发布:按比例分流 split_clients "${remote_addr}" $variant { 10% green; # 10% 流量到新版本 * blue; # 90% 流量到旧版本 } server { location / { proxy_pass http://$variant; } }
生产提示:灰度发布时应同时监控新版本的错误率和响应时间,确认稳定后再逐步增大流量比例。

HTTPS 配置

HTTPS 1 Let's Encrypt + Certbot 免费证书

使用 Certbot 自动获取和续期免费 SSL 证书:
# 安装 Certbot
sudo apt install certbot python3-certbot-nginx -y

# 自动配置 Nginx + 获取证书
sudo certbot --nginx -d example.com -d www.example.com

# 测试自动续期
sudo certbot renew --dry-run

# Certbot 会自动设置 cron/timer 续期
提示:Certbot 会自动修改 Nginx 配置文件,添加 SSL 相关指令并设置 HTTP 到 HTTPS 的重定向。

HTTPS 2 SSL 安全优化配置

生产环境推荐的 SSL 安全配置:
server { listen 443 ssl http2; server_name example.com; # 证书文件 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # 协议版本 — 只启用 TLS 1.2 和 1.3 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; ssl_prefer_server_ciphers on; # SSL 会话缓存 ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; }

HTTPS 3 HTTP/2 启用

HTTP/2 可以显著提升页面加载速度,Nginx 1.9.5+ 原生支持:
server { listen 443 ssl http2; # 添加 http2 即可 server_name example.com; ... }
HTTP/2 的优势:
- 多路复用:单个 TCP 连接并行传输多个请求/响应
- 头部压缩:HPACK 压缩减少冗余头部开销
- 服务器推送:主动推送关联资源
- 二进制分帧:更高效的数据传输

HTTPS 4 HSTS(严格传输安全)

强制浏览器始终使用 HTTPS 访问:
server { listen 443 ssl http2; server_name example.com; # HSTS — 告诉浏览器未来 1 年内只用 HTTPS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # 其他安全头部 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; } # HTTP 强制跳转 HTTPS server { listen 80; server_name example.com www.example.com; return 301 https://example.com$request_uri; }
警告:启用 HSTS 后,如果证书过期或 HTTPS 不可用,用户将完全无法访问网站。请确保证书自动续期正常工作后再启用。

性能优化

优化 1 Worker 进程与连接数

合理配置 worker 数量和连接数是性能调优的基础:
worker_processes auto; # 等于 CPU 核心数 worker_rlimit_nofile 65535; # 最大文件描述符 events { worker_connections 4096; # 每个 worker 的最大连接数 use epoll; # Linux 使用 epoll multi_accept on; # 一次接受所有新连接 }
计算公式:最大并发连接数 = worker_processes x worker_connections。4 核 CPU + 4096 连接 = 最多 16,384 个并发连接。同时需要确保系统 ulimit -n 值足够大。

优化 2 Keepalive 长连接

复用 TCP 连接减少握手开销:
http { # 客户端长连接 keepalive_timeout 65; # 空闲超时 keepalive_requests 1000; # 单连接最大请求数 # 后端长连接(配合 upstream keepalive) upstream backend { server 127.0.0.1:3000; keepalive 32; # 保持 32 个空闲长连接 } server { location / { proxy_pass http://backend; proxy_http_version 1.1; # 必须使用 HTTP/1.1 proxy_set_header Connection ""; # 清空 Connection 头 } } }

优化 3 Gzip 压缩

压缩响应内容可减少 60%-80% 的传输大小:
http { gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; # 压缩级别 1-9,6 是性价比最佳 gzip_min_length 256; # 小于 256 字节不压缩 gzip_types text/plain text/css text/javascript application/javascript application/json application/xml application/xml+rss image/svg+xml; }
进阶:使用 gzip_static on; 可以直接发送预压缩的 .gz 文件,避免每次请求都实时压缩,适合构建工具已生成 .gz 文件的场景。

优化 4 静态资源缓存

合理的缓存策略可以大幅减少重复请求:
server { # 带 hash 的静态资源 — 长期缓存 location ~* \.(css|js)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # 图片/字体 — 中期缓存 location ~* \.(png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 30d; add_header Cache-Control "public"; access_log off; } # HTML — 不缓存或短期缓存 location ~* \.html$ { expires -1; add_header Cache-Control "no-cache"; } }

优化 5 Buffer 与超时调优

调整缓冲区和超时参数以适应不同场景:
http { # 客户端请求体缓冲 client_body_buffer_size 16k; client_max_body_size 100m; # 最大上传文件大小 client_header_buffer_size 1k; large_client_header_buffers 4 16k; # 代理缓冲 proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; # 超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; send_timeout 60s; }
注意:如果后端有大文件上传需求,需要增大 client_max_body_size;如果后端响应较慢(如 AI 推理),需要增大 proxy_read_timeout

常见问题(50 个)

一、HTTP 错误与状态码 (10 个)

#1 502 Bad Gateway

502 Bad Gateway - nginx
Nginx 无法连接到上游后端服务器:
1. 检查后端服务是否正在运行:systemctl status your-app
2. 确认 proxy_pass 的地址和端口是否正确
3. 查看后端日志确认是否崩溃
4. 检查防火墙是否允许 Nginx 访问后端端口
5. 如果后端是 PHP-FPM,检查 socket 路径:ls -la /var/run/php/

#2 504 Gateway Timeout

504 Gateway Time-out - nginx
后端服务响应超时:
1. 增大代理超时参数:
proxy_connect_timeout 300s;
proxy_send_timeout    300s;
proxy_read_timeout    300s;

2. 检查后端是否有慢查询或死循环
3. 如果是 PHP-FPM,增大 request_terminate_timeout
4. 检查后端服务器资源(CPU / 内存 / 磁盘 IO)

#3 413 Request Entity Too Large

413 Request Entity Too Large - nginx
上传文件超过 Nginx 允许的最大大小(默认 1MB):
1. 在 http / server / location 块中增大限制:
client_max_body_size 100m;

2. 如果使用 PHP,同时修改 php.ini:
upload_max_filesize = 100M
post_max_size = 100M

#4 403 Forbidden

403 Forbidden - nginx
Nginx 没有权限访问请求的资源:
1. 检查文件/目录权限:ls -la /var/www/html/
2. 确保 Nginx 运行用户(通常 nginxwww-data)有读取权限
3. 检查 SELinux 状态:getenforce,如果为 Enforcing 可能阻止访问
4. 检查是否配置了 deny all; 或缺少 index 指令
5. 目录浏览未开启时访问目录也会返回 403

#5 404 Not Found

404 Not Found - nginx
请求的资源不存在:
1. 检查 root 指令指向的目录是否正确
2. 确认文件确实存在:ls -la /var/www/html/path/to/file
3. SPA 应用需要配置 try_files $uri $uri/ /index.html;
4. 检查 location 匹配规则是否正确
5. 区分大小写问题(Linux 文件系统区分大小写)

#6 499 Client Closed Request

access.log 中出现大量 499 状态码
客户端在 Nginx 返回响应前主动关闭了连接:
1. 后端响应太慢,客户端超时断开 — 优化后端性能
2. 用户频繁刷新或取消请求 — 正常现象
3. 健康检查探针超时 — 调整探针超时时间
4. 配置 proxy_ignore_client_abort on; 让后端继续处理

#7 301/302 重定向循环

ERR_TOO_MANY_REDIRECTS(浏览器提示重定向次数过多)
HTTP 和 HTTPS 之间的重定向形成循环:
1. 检查是否同时配置了 HTTP→HTTPS 和 HTTPS→HTTP 的重定向
2. 如果在 CDN/负载均衡后面,用 $http_x_forwarded_proto 而非 $scheme 判断:
if ($http_x_forwarded_proto = "http") {
    return 301 https://$host$request_uri;
}

3. 检查后端应用是否也在做重定向

#8 400 Bad Request — Request Header Or Cookie Too Large

400 Bad Request: Request Header Or Cookie Too Large
请求头或 Cookie 超过 Nginx 默认缓冲区:
1. 增大头部缓冲区:
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;

2. 检查客户端是否携带了过多或过大的 Cookie
3. 清理不必要的 Cookie,减少 Cookie 大小

#9 408 Request Timeout

408 Request Timeout - nginx
客户端在规定时间内未发送完整请求:
1. 增大客户端超时:
client_body_timeout   60s;
client_header_timeout 60s;

2. 检查客户端网络质量(慢速网络)
3. 大文件上传时需要更大的超时值

#10 429 Too Many Requests

429 Too Many Requests - nginx
触发了 Nginx 的限流配置:
1. 调整限流参数:增大 rateburst
2. 对受信任的 IP 白名单放行:
geo $limit {
    default 1;
    10.0.0.0/8 0;    # 内网不限流
}
map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=api:10m rate=10r/s;

3. 检查是否有爬虫或异常流量

二、配置与启动问题 (10 个)

#11 nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
端口 80 被其他进程占用:
1. 查看占用端口的进程:sudo lsof -i :80sudo ss -tlnp | grep :80
2. 停止占用进程(通常是 Apache):sudo systemctl stop apache2
3. 或者修改 Nginx 监听端口
4. 如果是 Nginx 残留进程:sudo killall nginx 后重启

#12 nginx: [emerg] unknown directive

nginx: [emerg] unknown directive "proxy_pass" in /etc/nginx/conf.d/app.conf:10
使用了未加载的模块指令:
1. 检查 Nginx 编译时是否包含了所需模块:nginx -V
2. 常见缺失模块:--with-http_ssl_module--with-http_v2_module
3. 包管理器安装的通常包含常用模块
4. 第三方模块需要手动编译加载

#13 nginx -t 测试通过但 reload 后配置不生效

修改配置文件后 nginx -s reload 但行为未改变
常见原因:
1. 修改了错误的配置文件 — 用 nginx -T 查看实际加载的配置
2. 浏览器缓存 — 清除缓存或使用无痕模式测试
3. CDN 缓存 — 清除 CDN 缓存
4. include 路径错误导致修改的文件未被包含
5. 使用 nginx -t 确认没有语法错误

#14 nginx: [emerg] "server" directive is not allowed here

nginx: [emerg] "server" directive is not allowed here in /etc/nginx/nginx.conf:50
server 块放在了错误的位置:
1. server 块必须在 http 块内部
2. 检查配置文件的大括号是否匹配
3. 检查 include 的文件中是否嵌套了 http 块
# 正确结构
http {
    server { ... }
}

# 错误:server 在 http 外面
server { ... }
http { ... }

#15 nginx: [warn] conflicting server name

nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored
同一个 server_name 在多个 server 块中重复定义:
1. 检查所有配置文件:grep -r "server_name example.com" /etc/nginx/
2. 删除重复的 server 块
3. 确保每个域名只在一个 server 块中定义

#16 nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)

nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
配置文件不存在:
1. 确认 Nginx 安装路径:which nginxnginx -V
2. 使用指定配置文件启动:nginx -c /path/to/nginx.conf
3. 重新安装 Nginx 恢复默认配置
4. Docker 中检查卷挂载路径是否正确

#17 SELinux 阻止 Nginx 连接后端

connect() to 127.0.0.1:3000 failed (13: Permission denied) while connecting to upstream
SELinux 阻止了 Nginx 的网络连接(常见于 CentOS/RHEL):
1. 临时关闭 SELinux 测试:sudo setenforce 0
2. 永久允许 Nginx 网络连接:
sudo setsebool -P httpd_can_network_connect 1

3. 如果代理到非标准端口,还需要:
sudo semanage port -a -t http_port_t -p tcp 3000

#18 worker_connections are not enough

worker_connections are not enough while connecting to upstream
当前连接数超过了配置的上限:
1. 增大 worker_connections
events {
    worker_connections 4096;
}

2. 同时增大系统文件描述符限制:
# /etc/security/limits.conf
nginx soft nofile 65535
nginx hard nofile 65535

3. 增大 worker_rlimit_nofile 65535;

#19 upstream sent too big header

upstream sent too big header while reading response header from upstream
后端返回的响应头超过了 Nginx 的缓冲区:
1. 增大代理缓冲区:
proxy_buffer_size          128k;
proxy_buffers              4 256k;
proxy_busy_buffers_size    256k;

2. 如果使用 FastCGI(PHP-FPM):
fastcgi_buffer_size        128k;
fastcgi_buffers            4 256k;
fastcgi_busy_buffers_size  256k;

#20 Nginx 进程 CPU 占用 100%

top 显示 nginx worker 进程 CPU 100%
可能原因和解决方案:
1. 配置了错误的正则匹配导致回溯 — 简化 location 正则
2. 大量 SSL 握手 — 启用 ssl_session_cache 缓存会话
3. 过多的日志写入 — 关闭不必要的 access_log
4. 遭受 DDoS 攻击 — 配置限流和防火墙规则
5. 使用 perf top -p $(pgrep nginx) 分析热点

三、SSL / HTTPS 问题 (10 个)

#21 SSL 证书错误 — NET::ERR_CERT_AUTHORITY_INVALID

浏览器提示"您的连接不是私密连接"
证书不受信任的常见原因:
1. 使用了自签名证书 — 生产环境应使用 Let's Encrypt 等 CA 签发的证书
2. 证书链不完整 — 确保 ssl_certificate 使用 fullchain.pem(包含中间证书)
3. 证书已过期 — 检查到期时间:openssl x509 -in cert.pem -noout -dates
4. 域名不匹配 — 证书的 CN/SAN 必须包含访问的域名

#22 SSL_do_handshake() failed

SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number)
SSL 握手失败:
1. 确认后端是否使用 HTTPS — proxy_pass 使用 http:// 还是 https://
2. 端口 443 监听了 SSL 但请求用 HTTP 访问
3. 检查 ssl_protocols 是否与客户端兼容
4. CDN 到源站的连接协议是否一致

#23 Certbot 续期失败

Certbot renew failed: Challenge did not pass
Let's Encrypt 证书续期失败:
1. HTTP-01 验证需要 80 端口可访问 — 确保防火墙开放 80 端口
2. 确认 /.well-known/acme-challenge/ 路径可访问:
location /.well-known/acme-challenge/ {
    root /var/www/certbot;
}

3. DNS 解析是否正确指向服务器
4. 检查 Certbot 日志:/var/log/letsencrypt/letsencrypt.log

#24 Mixed Content 警告

浏览器控制台:Mixed Content: The page was loaded over HTTPS but requested an insecure resource
HTTPS 页面引用了 HTTP 资源:
1. 将所有资源引用改为 HTTPS 或使用协议相对 URL(//example.com/...
2. 在 Nginx 中添加 CSP 头部自动升级:
add_header Content-Security-Policy "upgrade-insecure-requests" always;

3. 确保后端应用生成的 URL 使用 HTTPS
4. 设置正确的 X-Forwarded-Proto 头部让后端知道使用 HTTPS

#25 SSL 性能问题 — 握手慢

HTTPS 首次访问明显比 HTTP 慢
SSL 握手优化:
1. 启用 SSL 会话缓存:
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

2. 启用 OCSP Stapling 避免客户端查询:
ssl_stapling on;
ssl_stapling_verify on;

3. 使用 TLS 1.3(0-RTT 握手):ssl_protocols TLSv1.2 TLSv1.3;
4. 使用 ECDSA 证书(比 RSA 更快)

#26 no "ssl_certificate" is defined for the "listen ... ssl"

nginx: [emerg] no "ssl_certificate" is defined for the "listen ... ssl" directive
监听了 SSL 端口但未配置证书:
1. 添加证书配置:
ssl_certificate     /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;

2. 确认证书文件路径存在且 Nginx 有读取权限
3. 如果证书尚未申请,先去掉 ssl 关键字

#27 SSL certificate problem: unable to get local issuer certificate

curl: (60) SSL certificate problem: unable to get local issuer certificate
证书链不完整:
1. 确保 ssl_certificate 文件包含完整证书链(服务器证书 + 中间证书)
2. 使用 Let's Encrypt 时用 fullchain.pem 而非 cert.pem
3. 验证证书链:openssl s_client -connect example.com:443 -servername example.com
4. 在线检测:SSL Labs Server Test

#28 多域名共享同一 IP — SNI 问题

访问 A 域名显示 B 域名的证书
SNI(Server Name Indication)相关问题:
1. 确保每个 server 块的 server_name 正确
2. 检查默认 server 块的证书是否正确:
server {
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate /path/to/default.pem;
    return 444;  # 拒绝未知域名
}

3. 旧版客户端不支持 SNI — 需要独立 IP 或通配符证书

#29 PEM_read_bio_X509 错误

nginx: [emerg] PEM_read_bio_X509_AUX() failed (SSL: error:0906D06C)
证书文件格式错误:
1. 检查证书文件是否为 PEM 格式(以 -----BEGIN CERTIFICATE----- 开头)
2. 如果是 DER 格式,需转换:openssl x509 -in cert.der -inform DER -out cert.pem -outform PEM
3. 文件编码问题 — 确保是 UTF-8 无 BOM
4. 证书和私钥不要放在同一个文件中

#30 通配符证书配置

如何为 *.example.com 所有子域名配置 HTTPS
通配符证书需要使用 DNS-01 验证方式:
# Certbot DNS 验证(以 Cloudflare 为例)
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d example.com \
  -d "*.example.com"
配置中可以在多个 server 块中复用同一张证书:
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

四、反向代理问题 (10 个)

#31 后端获取不到客户端真实 IP

后端日志中所有请求的 IP 都是 127.0.0.1
需要正确设置代理头部:
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;
后端应用读取 X-Real-IPX-Forwarded-For 头部获取真实 IP。如果有多层代理,需要配置 set_real_ip_fromreal_ip_header

#32 WebSocket 连接断开

WebSocket connection to 'wss://...' failed
WebSocket 代理配置不完整:
1. 必须设置协议升级头部:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

2. 增大读取超时防止空闲断开:proxy_read_timeout 86400s;
3. 如果使用 CDN,确保 CDN 支持 WebSocket

#33 proxy_pass 末尾斜杠问题

代理后路径不正确,多了或少了路径前缀
proxy_pass 末尾有无斜杠行为完全不同:
# 请求: /api/users
# 带斜杠 — 去掉匹配的前缀
location /api/ {
    proxy_pass http://backend/;  # → backend 收到 /users
}

# 不带斜杠 — 保留完整路径
location /api/ {
    proxy_pass http://backend;   # → backend 收到 /api/users
}
关键规则:如果 proxy_pass 包含 URI(即使只是一个 /),Nginx 会将匹配的 location 前缀替换掉;如果不包含 URI,则传递完整的原始请求路径。

#34 代理后端返回的 Location 头部不正确

后端重定向时 URL 指向了内部地址(如 http://127.0.0.1:3000/...)
使用 proxy_redirect 改写后端返回的 Location 头:
proxy_redirect http://127.0.0.1:3000/ /;
# 或自动改写
proxy_redirect default;
同时确保设置了 Host 头:
proxy_set_header Host $host;

#35 代理后端的 Cookie 丢失或路径不对

登录状态无法保持,Cookie 未正确传递
使用 proxy_cookie_pathproxy_cookie_domain 改写 Cookie:
# 改写 Cookie 路径
proxy_cookie_path /internal-app/ /;

# 改写 Cookie 域名
proxy_cookie_domain backend.internal example.com;
如果使用子路径代理,确保后端应用的 Cookie 路径设置兼容。

#36 upstream timed out (110: Connection timed out)

upstream timed out (110: Connection timed out) while connecting to upstream
Nginx 无法在规定时间内连接到后端:
1. 检查后端是否可达:curl -v http://127.0.0.1:3000
2. 增大连接超时:proxy_connect_timeout 60s;
3. 检查防火墙 / iptables 规则
4. 后端连接池已满 — 增加后端 worker 数量
5. DNS 解析慢 — 使用 IP 地址代替域名

#37 代理大文件时内存占用过高

Nginx 代理大文件下载时内存飙升
默认情况下 Nginx 会缓冲后端响应到内存。关闭缓冲让数据直接流式传输:
# 关闭代理缓冲
proxy_buffering off;

# 或者使用临时文件缓冲
proxy_max_temp_file_size 1024m;
proxy_temp_path /var/cache/nginx/temp;
对于视频流或大文件下载场景,建议关闭缓冲。

#38 负载均衡节点不均匀

多个后端节点的请求量差异很大
常见原因和解决方案:
1. ip_hash 策略可能导致分配不均 — 改用 least_conn
2. 检查是否有节点被标记为 down 或 backup
3. 使用 weight 参数按性能分配:
upstream backend {
    least_conn;
    server 10.0.0.1:3000 weight=3;  # 高性能机器
    server 10.0.0.2:3000 weight=1;  # 低性能机器
}

4. 长连接可能导致请求集中 — 减小 keepalive

#39 SPA 应用路由刷新 404

Vue/React 单页应用刷新页面返回 404
SPA 应用的所有路由都需要指向 index.html:
server {
    listen 80;
    server_name app.example.com;
    root /var/www/app/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # API 代理
    location /api/ {
        proxy_pass http://127.0.0.1:3000;
    }
}
try_files 会先查找实际文件,找不到则回退到 index.html 让前端路由处理。

#40 跨域(CORS)配置

Access to XMLHttpRequest has been blocked by CORS policy
在 Nginx 中统一配置 CORS 头部:
location /api/ {
    # CORS 头部
    add_header Access-Control-Allow-Origin $http_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    add_header Access-Control-Allow-Credentials true always;

    # 预检请求直接返回
    if ($request_method = OPTIONS) {
        return 204;
    }

    proxy_pass http://backend;
}
安全提示:生产环境不要使用 * 作为 Allow-Origin,应该明确指定允许的域名。

五、性能与运维问题 (10 个)

#41 access.log 文件过大

access.log 占用大量磁盘空间
配置日志轮转和优化:
1. 使用 logrotate(通常已默认配置):
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 nginx adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

2. 静态资源关闭日志:access_log off;
3. 使用缓冲写入:access_log /var/log/nginx/access.log main buffer=32k flush=5s;

#42 Nginx 平滑升级(热升级)

如何在不停机的情况下升级 Nginx 版本
Nginx 支持热升级二进制文件:
# 1. 备份旧二进制
sudo cp /usr/sbin/nginx /usr/sbin/nginx.old

# 2. 替换新二进制(编译安装后)
sudo cp objs/nginx /usr/sbin/nginx

# 3. 发送 USR2 信号启动新进程
sudo kill -USR2 `cat /var/run/nginx.pid`

# 4. 优雅关闭旧 worker
sudo kill -WINCH `cat /var/run/nginx.pid.oldbin`

# 5. 确认新版本正常后关闭旧主进程
sudo kill -QUIT `cat /var/run/nginx.pid.oldbin`
推荐:包管理器安装的用户直接 apt upgrade nginx 即可,systemd 会处理重启。

#43 如何查看 Nginx 实时连接状态

想要监控 Nginx 的活跃连接数和请求速率
启用 stub_status 模块:
# 添加状态页面
server {
    listen 127.0.0.1:8080;
    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}
访问后输出如下:
Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
可以配合 Prometheus + nginx-exporter + Grafana 做可视化监控。

#44 Nginx 内存占用异常增长

Nginx worker 进程内存持续增长不释放
可能原因:
1. 代理缓冲过大 — 减小 proxy_buffersproxy_buffer_size
2. 缓存区配置过大 — 检查 proxy_cache 相关配置
3. 第三方模块内存泄漏 — 禁用可疑模块测试
4. 定期重启 worker 进程限制内存:
worker_shutdown_timeout 10s;

5. 使用 worker_rlimit_core 限制 core dump 大小

#45 Nginx 配置自动化管理

多台服务器的 Nginx 配置如何统一管理
推荐的配置管理方案:
1. Git 版本控制:将 /etc/nginx/ 纳入 Git 管理
2. Ansible:使用 Ansible playbook 批量部署配置
3. Consul Template:根据服务发现自动生成配置
4. NginxConfig.io:在线生成 Nginx 配置的可视化工具
5. 自动化流程:修改配置 → Git push → CI/CD → nginx -t → reload

#46 Nginx 防止恶意爬虫和扫描

日志中大量恶意扫描请求(如扫描 /wp-admin, /phpmyadmin)
多层防护策略:
# 1. 屏蔽常见扫描路径
location ~* /(wp-admin|wp-login|phpmyadmin|\.env|\.git) {
    return 444;
}

# 2. 屏蔽恶意 User-Agent
if ($http_user_agent ~* (scrapy|curl|wget|python-requests|Go-http-client)) {
    return 403;
}

# 3. 限制请求速率
limit_req_zone $binary_remote_addr zone=scan:10m rate=2r/s;
location / {
    limit_req zone=scan burst=5 nodelay;
}

4. 配合 fail2ban 自动封禁恶意 IP

#47 open() failed (24: Too many open files)

open() "/var/www/..." failed (24: Too many open files)
文件描述符不足:
1. 增大 Nginx 进程的文件描述符限制:
# nginx.conf 全局块
worker_rlimit_nofile 65535;

2. 增大系统级限制:
# /etc/security/limits.conf
nginx soft nofile 65535
nginx hard nofile 65535

# /etc/sysctl.conf
fs.file-max = 2097152

3. 如果使用 systemd:在 nginx.service 中添加 LimitNOFILE=65535

#48 Nginx 作为 TCP/UDP 代理(Stream 模块)

如何用 Nginx 代理数据库、Redis 等非 HTTP 服务
使用 stream 模块代理四层流量:
# nginx.conf(与 http 块同级)
stream {
    upstream mysql_backend {
        server 10.0.0.1:3306;
        server 10.0.0.2:3306 backup;
    }

    server {
        listen 3306;
        proxy_pass mysql_backend;
        proxy_connect_timeout 10s;
        proxy_timeout 300s;
    }
}
注意:stream 模块需要编译时包含 --with-stream。包管理器安装的 Nginx 通常已包含。

#49 Nginx 与 Docker 网络问题

Docker 容器中的 Nginx 无法访问其他容器的服务
Docker 网络注意事项:
1. 使用 Docker Compose 时,容器间通过服务名通信:
# proxy_pass 使用服务名而非 localhost
proxy_pass http://app:3000;

2. 不同 Compose 项目需要共享 Docker 网络
3. 使用 host.docker.internal 访问宿主机服务
4. Nginx 启动时 DNS 解析失败 — 添加 resolver:
resolver 127.0.0.11 valid=30s;  # Docker 内置 DNS

#50 Nginx 的局限性与替代方案

什么场景不适合用 Nginx
Nginx 并非万能,以下场景可能需要其他方案:
- 自动 HTTPS:不想手动配证书 → 考虑 Caddy(全自动 HTTPS)
- 容器编排:K8s 原生集成 → 考虑 Traefik 或 Envoy
- API 网关:需要认证、限流、计费 → 考虑 Kong(基于 Nginx)或 APISIX
- 动态配置:频繁变更上游 → 考虑 Envoy 或 Nginx Plus(商业版)
- .htaccess 支持:需要目录级配置 → Apache 仍是唯一选择
- 服务网格:微服务间通信 → 考虑 Istio + Envoy