本文整理了 Nginx 在生产环境中常见的问题及解决方案,涵盖配置、性能、安全、故障排查等多个方面,帮助开发者快速定位和解决问题。
目录
- 一、安装与启动问题
- 二、配置相关问题
- 三、反向代理与负载均衡
- 四、性能优化问题
- 五、SSL/HTTPS 问题
- 六、安全相关问题
- 七、日志与故障排查
- 八、实际案例场景
一、安装与启动问题
1.1 Nginx 启动失败
问题现象
$ nginx
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
原因分析
- 端口已被其他进程占用(常见:Apache、另一个 Nginx 实例)
- 权限不足(80/443 端口需要 root 权限)
解决方案
# 1. 查看端口占用
sudo lsof -i :80
sudo netstat -tlnp | grep :80
sudo ss -tlnp | grep :80
# 2. 停止占用进程
sudo kill -9 <PID>
# 3. 或者修改 Nginx 端口
# /etc/nginx/nginx.conf
server {
listen 8080; # 改用非特权端口
# ...
}
# 4. 检查配置语法
sudo nginx -t
# 5. 查看错误日志
sudo tail -f /var/log/nginx/error.log
1.2 权限问题导致启动失败
问题现象
nginx: [emerg] open() "/var/log/nginx/access.log" failed (13: Permission denied)
解决方案
# 1. 检查日志目录权限
ls -la /var/log/nginx/
# 2. 修正权限
sudo chown -R nginx:nginx /var/log/nginx/
sudo chmod -R 755 /var/log/nginx/
# 3. 或者修改配置中的日志路径
# /etc/nginx/nginx.conf
error_log /tmp/nginx_error.log;
access_log /tmp/nginx_access.log;
1.3 worker 进程数配置问题
问题现象
CPU 使用率异常或进程数过多
解决方案
# /etc/nginx/nginx.conf
# 推荐设置为 CPU 核心数
worker_processes auto; # 自动检测
# 或手动指定
# worker_processes 4;
# 查看 CPU 核心数
nproc
# 绑定 CPU 亲和性(高性能场景)
worker_cpu_affinity auto;
二、配置相关问题
2.1 配置文件语法错误
问题现象
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax failed
nginx: [emerg] unknown directive "server_nam" in /etc/nginx/conf.d/site.conf:10
解决方案
# 1. 测试配置语法
sudo nginx -t
# 2. 详细错误输出
sudo nginx -T 2>&1 | head -50
# 3. 常见错误检查清单
# - 缺少分号
# - 括号不匹配
# - 指令拼写错误
# - 使用了未加载模块的指令
# 4. 分段测试配置
# 注释掉部分配置,逐步排查
配置检查清单
# ✅ 正确示例
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
}
# ❌ 常见错误
server {
listen 80 # 缺少分号
server_name example.com
root /var/www/html # 缺少分号
index index.html
} # 缺少闭合括号
2.2 server_name 不匹配问题
问题现象
- 访问域名时返回默认页面或 404
- 多个 server 块配置冲突
解决方案
# server_name 匹配优先级:
# 1. 精确匹配 > 2. 通配符 > 3. 正则 > 4. default_server
server {
listen 80;
server_name www.example.com example.com;
# 精确匹配
}
server {
listen 80;
server_name *.example.com;
# 通配符匹配
}
server {
listen 80;
server_name ~^www\.([0-9]+)\.example\.com$;
# 正则匹配
}
server {
listen 80 default_server;
server_name _;
# 默认服务器,捕获所有未匹配的请求
return 444; # 或返回自定义错误页
}
调试方法
# 查看实际处理的 server 块
curl -v -H “Host: example.com” http://<server-ip>/
# 检查配置加载顺序
nginx -T | grep -A 5 “server_name”
2.3 location 匹配优先级问题
问题现象
- 某些 URL 被错误的 location 处理
- 静态文件被当作动态请求处理
location 匹配规则
# 匹配优先级(从高到低):
# 1. = 精确匹配
# 2. ^~ 前缀匹配(不检查正则)
# 3. ~ 正则匹配(区分大小写)
# 4. ~* 正则匹配(不区分大小写)
# 5. 不带修饰符的前缀匹配
server {
listen 80;
server_name example.com;
# 优先级 1:精确匹配
location = /favicon.ico {
log_not_found off;
access_log off;
}
# 优先级 2:前缀匹配(停止正则检查)
location ^~ /static/ {
alias /var/www/static/;
expires 30d;
}
# 优先级 3:正则匹配
location ~ \.(jpg|jpeg|png|gif|ico)$ {
root /var/www/images;
expires 7d;
}
location ~* \.(css|js)$ {
root /var/www/assets;
expires 1d;
}
# 优先级 5:通用前缀匹配
location /api/ {
proxy_pass http://backend;
}
# 优先级最低:根路径
location / {
try_files $uri $uri/ /index.html;
}
}
调试技巧
# 测试不同 URL 的匹配结果
curl http://example.com/static/style.css
curl http://example.com/api/users
curl http://example.com/images/logo.png
# 开启调试日志
# nginx.conf
error_log /var/log/nginx/error.log debug;
2.4 root 与 alias 使用混淆
问题现象
区别说明
# root: 将 location 路径拼接到 root 后面
# alias: 用 alias 路径替换 location 路径
location /images/ {
root /var/www;
# 请求 /images/logo.png → /var/www/images/logo.png
}
location /static/ {
alias /var/www/assets/;
# 请求 /static/style.css → /var/www/assets/style.css
# 注意:alias 末尾的斜杠很重要
}
# ❌ 错误示例
location /static/ {
alias /var/www/assets; # 缺少末尾斜杠
# 请求 /static/style.css → /var/www/assetsstyle.css (错误)
}
三、反向代理与负载均衡
3.1 后端服务连接失败
问题现象
# error.log
2024/03/09 10:30:45 [error] connect() failed (111: Connection refused)
2024/03/09 10:30:45 [error] upstream timed out (110: Connection timed out)
解决方案
upstream backend {
server 127.0.0.1:8080;
# 配置连接参数
keepalive 32; # 保持连接数
keepalive_timeout 60s;
keepalive_requests 100;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
# 超时设置
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 重试机制
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 10s;
# 传递必要头部
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;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
}
3.2 负载均衡策略配置
问题现象
负载均衡策略
# 1. 轮询(默认)
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 2. 加权轮询
upstream backend {
server 192.168.1.10:8080 weight=3; # 处理 3/6 的请求
server 192.168.1.11:8080 weight=2; # 处理 2/6 的请求
server 192.168.1.12:8080 weight=1; # 处理 1/6 的请求
}
# 3. IP Hash(会话保持)
upstream backend {
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 4. 最少连接
upstream backend {
least_conn;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 5. 公平调度(第三方模块)
upstream backend {
fair;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 6. URL Hash(第三方模块)
upstream backend {
hash $request_uri consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 服务器状态标记
upstream backend {
server 192.168.1.10:8080; # 正常
server 192.168.1.11:8080 backup; # 备份服务器
server 192.168.1.12:8080 down; # 临时下线
server 192.168.1.13:8080 max_fails=3 fail_timeout=30s;
}
3.3 WebSocket 代理配置
问题现象
- WebSocket 连接建立后立即断开
- 升级协议失败
解决方案
server {
listen 80;
server_name ws.example.com;
location /ws/ {
proxy_pass http://backend;
# WebSocket 必需配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
# 超时设置(WebSocket 长连接)
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# 其他头部
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
3.4 获取客户端真实 IP
问题现象
- 后端获取的 IP 是 Nginx 的 IP
- 日志中记录的 IP 不正确
解决方案
# 1. Nginx 配置传递真实 IP
http {
# 设置可信代理
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 127.0.0.1;
# 从哪个头部获取真实 IP
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}
# 2. 传递 IP 到后端
server {
location / {
proxy_pass http://backend;
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;
proxy_set_header X-Forwarded-Host $host;
}
}
# 3. 后端应用获取 IP(以 Java 为例)
public String getClientIp(HttpServletRequest request) {
String ip = request.getHeader(“X-Forwarded-For”);
if (ip != null && !ip.isEmpty() && !“unknown”.equalsIgnoreCase(ip)) {
// X-Forwarded-For 可能包含多个 IP,取第一个
return ip.split(“,”)[0].trim();
}
return request.getHeader(“X-Real-IP”);
}
四、性能优化问题
4.1 静态文件性能优化
问题现象
解决方案
server {
listen 80;
server_name static.example.com;
# 开启 sendfile
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 禁用访问日志(高并发静态文件)
access_log off;
# 静态文件配置
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
root /var/www/images;
# 浏览器缓存
expires 30d;
add_header Cache-Control “public, immutable”;
# 禁用日志
access_log off;
# 压缩(对已压缩文件无效)
gzip_static off;
}
location ~* \.(css|js|html)$ {
root /var/www/assets;
# 浏览器缓存
expires 7d;
add_header Cache-Control “public”;
# 开启 gzip
gzip_static on;
}
# 开启 open_file_cache
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
4.2 Gzip 压缩配置
问题现象
解决方案
http {
# 开启 gzip
gzip on;
# 最小压缩文件大小
gzip_min_length 1k;
# 压缩级别(1-9,越高压缩率越大但 CPU 消耗越多)
gzip_comp_level 5;
# 压缩类型
gzip_types text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss
application/x-javascript;
# 禁用 IE6 gzip
gzip_disable “msie6”;
# Vary 头(支持缓存)
gzip_vary on;
# 代理缓冲压缩
gzip_proxied any;
# 预压缩(需要安装 gzip-static 模块)
# gzip_static on;
}
验证压缩效果
# 检查响应头
curl -H “Accept-Encoding: gzip” -I https://example.com/style.css
# 应该看到
# Content-Encoding: gzip
# Content-Length: <压缩后大小>
# 对比压缩前后
curl -H “Accept-Encoding: gzip” https://example.com/app.js | wc -c
curl https://example.com/app.js | wc -c
4.3 连接数优化
问题现象
# error.log
2024/03/09 10:30:45 [emerg] worker_connections are not enough
解决方案
# 查看系统限制
ulimit -n # 文件描述符限制
# /etc/security/limits.conf 添加
nginx soft nofile 65535
nginx hard nofile 65535
# nginx.conf
user nginx;
worker_processes auto;
events {
# 每个 worker 最大连接数
worker_connections 65535;
# 允许一个 worker 处理多个连接
multi_accept on;
# 使用 epoll(Linux)
use epoll;
}
http {
# keepalive 配置
keepalive_timeout 65;
keepalive_requests 1000;
# 上游连接池
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
}
4.4 缓冲与缓存优化
问题现象
解决方案
http {
# 客户端请求体缓冲
client_body_buffer_size 16k;
client_max_body_size 100m; # 最大上传文件大小
# 客户端请求头缓冲
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
# 代理缓冲
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 24k;
# 快速cgi 缓冲(PHP)
fastcgi_buffering on;
fastcgi_buffer_size 4k;
fastcgi_buffers 8 16k;
fastcgi_busy_buffers_size 24k;
}
五、SSL/HTTPS 问题
5.1 SSL 证书配置
问题现象
# error.log
SSL_do_handshake() failed
certificate verify failed
解决方案
server {
listen 443 ssl http2;
server_name example.com;
# 证书文件
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# 证书链(可选,某些 CA 需要)
# ssl_trusted_certificate /etc/nginx/ssl/chain.pem;
# SSL 优化配置
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# 现代加密配置
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 off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS
add_header Strict-Transport-Security “max-age=63072000” always;
}
# HTTP 自动跳转 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
证书检查
# 检查证书有效期
openssl x509 -in /etc/nginx/ssl/example.com.crt -noout -dates
# 检查证书链
openssl verify -CAfile /etc/nginx/ssl/chain.pem /etc/nginx/ssl/example.com.crt
# 在线检查
# https://www.ssllabs.com/ssltest/
5.2 混合内容问题
问题现象
- 浏览器显示“不安全”
- Console 警告:Mixed Content
解决方案
server {
listen 443 ssl;
server_name example.com;
# 替换 HTTP 资源为 HTTPS
sub_filter ‘http://’ ‘https://’;
sub_filter_once off;
sub_filter_types text/html application/json;
# 内容安全策略
add_header Content-Security-Policy “upgrade-insecure-requests” always;
}
前端修复
<!— ❌ 错误 —>
<script src=“http://cdn.example.com/jquery.js”></script>
<img src=“http://example.com/logo.png”>
<!— ✅ 正确 —>
<script src=“//cdn.example.com/jquery.js”></script>
<script src=“https://cdn.example.com/jquery.js”></script>
<img src=“/logo.png”>
5.3 多域名 SSL 配置
解决方案
# 1. 多证书配置
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
}
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
}
# 2. 通配符证书
server {
listen 443 ssl;
server_name *.example.com;
ssl_certificate /etc/nginx/ssl/wildcard.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/wildcard.example.com.key;
}
# 3. SAN 证书(多域名)
server {
listen 443 ssl;
server_name example.com www.example.com api.example.com;
ssl_certificate /etc/nginx/ssl/san.crt;
ssl_certificate_key /etc/nginx/ssl/san.key;
}
六、安全相关问题
6.1 防止常见攻击
解决方案
http {
# 隐藏 Nginx 版本
server_tokens off;
# 限制请求头大小
large_client_header_buffers 4 8k;
# 限制请求体大小
client_max_body_size 10m;
# 限制请求方法
if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|OPTIONS)$) {
return 405;
}
}
server {
# 防止点击劫持
add_header X-Frame-Options “SAMEORIGIN” always;
# 防止 MIME 类型嗅探
add_header X-Content-Type-Options “nosniff” always;
# XSS 防护
add_header X-XSS-Protection “1; mode=block” always;
# 内容安全策略
add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’ ‘unsafe-inline’; style-src ‘self’ ‘unsafe-inline’;” always;
# 限制请求频率
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req zone=one burst=20 nodelay;
# 限制连接数
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;
}
6.2 IP 访问控制
解决方案
server {
listen 80;
server_name admin.example.com;
# 允许特定 IP
allow 192.168.1.0/24;
allow 10.0.0.100;
# 拒绝其他所有
deny all;
location / {
# ...
}
}
# 地理位置限制(需要 GeoIP 模块)
http {
geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $allowed_country {
default no;
CN yes;
US yes;
}
server {
if ($allowed_country = no) {
return 403;
}
}
}
6.3 DDoS 防护
解决方案
http {
# 限制请求速率
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_req_zone $server_name zone=server_limit:10m rate=50r/s;
# 限制连接数
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# 超时设置
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 65s;
send_timeout 10s;
}
server {
listen 80;
# 应用限制
limit_req zone=req_limit burst=20 nodelay;
limit_conn conn_limit 10;
# 异常 UA 拦截
if ($http_user_agent ~* (wget|curl|scan|bot)) {
return 403;
}
# 空 UA 拦截
if ($http_user_agent = “”) {
return 403;
}
}
七、日志与故障排查
7.1 日志配置
解决方案
http {
# 自定义日志格式
log_format main ‘$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”’;
log_format json escape=json ‘{“time”:“$time_iso8601”,’
‘“remote_addr”:“$remote_addr”,’
‘“method”:“$request_method”,’
‘“uri”:“$request_uri”,’
‘“status”:$status,’
‘“bytes”:$body_bytes_sent,’
‘“referer”:“$http_referer”,’
‘“ua”:“$http_user_agent”,’
‘“request_time”:$request_time}’;
# 访问日志
access_log /var/log/nginx/access.log main;
# 错误日志(级别:debug | info | notice | warn | error | crit | alert | emerg)
error_log /var/log/nginx/error.log warn;
# 按域名分割日志
# server 块中
access_log /var/log/nginx/example.com.access.log main;
error_log /var/log/nginx/example.com.error.log warn;
}
7.2 日志分析
常用分析命令
# 1. 访问量 Top 10 IP
awk ‘{print $1}’ /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# 2. 访问量 Top 10 URL
awk ‘{print $7}’ /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# 3. 状态码统计
awk ‘{print $9}’ /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 4. 404 错误分析
grep “ 404 “ /var/log/nginx/access.log | awk ‘{print $7}’ | sort | uniq -c | sort -rn
# 5. 慢请求分析(请求时间>1s)
awk ‘($NF > 1) {print $7, $NF}’ /var/log/nginx/access.log | sort -k2 -rn | head -20
# 6. 实时日志监控
tail -f /var/log/nginx/access.log
# 7. 错误日志实时监控
tail -f /var/log/nginx/error.log
# 8. 使用 goaccess 可视化分析
goaccess /var/log/nginx/access.log -o report.html —log-format=COMBINED
7.3 故障排查流程
排查步骤
# 1. 检查 Nginx 状态
systemctl status nginx
ps aux | grep nginx
# 2. 测试配置
nginx -t
# 3. 查看错误日志
tail -100 /var/log/nginx/error.log
# 4. 检查端口监听
netstat -tlnp | grep nginx
ss -tlnp | grep nginx
# 5. 检查连接数
netstat -an | grep :80 | wc -l
# 6. 检查系统资源
top
free -h
df -h
# 7. 测试响应
curl -v http://localhost/
curl -I http://localhost/
# 8. 检查 upstream 状态
# 需要配置 status 模块
location /nginx_status {
stub_status on;
allow 127.0.0.1;
deny all;
}
curl http://localhost/nginx_status
常见错误码排查
| 错误码 |
含义 |
排查方向 |
| 400 |
错误请求 |
检查请求格式、URL 编码 |
| 401 |
未授权 |
检查认证配置 |
| 403 |
禁止访问 |
检查权限、IP 限制 |
| 404 |
未找到 |
检查文件路径、location 配置 |
| 405 |
方法不允许 |
检查请求方法限制 |
| 413 |
请求体过大 |
检查 client_max_body_size |
| 414 |
URL 过长 |
检查 large_client_header_buffers |
| 499 |
客户端断开 |
检查后端响应时间 |
| 500 |
服务器错误 |
检查错误日志 |
| 502 |
错误网关 |
检查 upstream 服务状态 |
| 503 |
服务不可用 |
检查后端服务、限流配置 |
| 504 |
网关超时 |
检查 proxy_read_timeout |
八、实际案例场景
案例一:API 网关配置
场景描述
公司微服务架构,需要 Nginx 作为 API 网关,实现反向代理与负载均衡、路由转发、限流、认证等功能。
解决方案
# API 网关配置
upstream user_service {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
keepalive 32;
}
upstream order_service {
server 10.0.2.10:8080;
server 10.0.2.11:8080;
keepalive 32;
}
upstream payment_service {
server 10.0.3.10:8080;
server 10.0.3.11:8080;
keepalive 32;
}
# 限流区域
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_req_zone $server_name zone=service_limit:10m rate=1000r/s;
server {
listen 80;
server_name api.example.com;
# 访问日志
access_log /var/log/nginx/api.access.log json;
error_log /var/log/nginx/api.error.log warn;
# 通用安全头
add_header X-Frame-Options “DENY” always;
add_header X-Content-Type-Options “nosniff” always;
# 健康检查
location /health {
access_log off;
return 200 “OK\n”;
add_header Content-Type text/plain;
}
# 用户服务
location /api/v1/users/ {
limit_req zone=api_limit burst=50 nodelay;
proxy_pass http://user_service;
proxy_http_version 1.1;
proxy_set_header Connection “”;
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_connect_timeout 3s;
proxy_read_timeout 10s;
proxy_send_timeout 10s;
}
# 订单服务
location /api/v1/orders/ {
limit_req zone=api_limit burst=30 nodelay;
proxy_pass http://order_service;
proxy_http_version 1.1;
proxy_set_header Connection “”;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 重试配置
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 2;
}
# 支付服务(需要认证)
location /api/v1/payments/ {
# JWT 验证(需要 auth_request 模块)
auth_request /auth/validate;
limit_req zone=api_limit burst=10 nodelay;
proxy_pass http://payment_service;
proxy_http_version 1.1;
proxy_set_header Connection “”;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 认证子请求
location = /auth/validate {
internal;
proxy_pass http://auth_service/validate;
proxy_http_version 1.1;
proxy_set_header Authorization $http_authorization;
proxy_pass_request_body off;
proxy_set_header Content-Length “”;
proxy_set_header X-Original-URI $request_uri;
}
}
案例二:动静分离配置
场景描述
电商网站,需要分离静态资源和动态请求,优化访问速度。
解决方案
upstream app_servers {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
server {
listen 80;
server_name www.example.com;
root /var/www/html;
index index.html index.htm;
# Gzip 压缩
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript;
# 静态文件缓存配置
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|woff|woff2|ttf|eot)$ {
root /var/www/static;
expires 30d;
add_header Cache-Control “public, immutable”;
access_log off;
# 防盗链
valid_referers none blocked server_names *.example.com example.com;
if ($invalid_referer) {
return 403;
}
}
location ~* \.(css|js)$ {
root /var/www/static;
expires 7d;
add_header Cache-Control “public”;
gzip_static on;
}
# HTML 不缓存
location ~* \.html$ {
root /var/www/html;
expires -1;
add_header Cache-Control “no-cache, no-store, must-revalidate”;
}
# 动态请求代理
location / {
try_files $uri $uri/ @backend;
}
location @backend {
proxy_pass http://app_servers;
proxy_http_version 1.1;
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_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
# 超时
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
# 上传文件
location /upload/ {
client_max_body_size 50m;
client_body_buffer_size 128k;
proxy_pass http://app_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
案例三:HTTPS 全站加密
场景描述
企业官网需要全站 HTTPS,包括 HTTP 自动跳转、HSTS、证书自动更新。
解决方案
# HTTP 服务器 - 强制跳转 HTTPS
server {
listen 80;
server_name www.example.com example.com;
# ACME 挑战(Let’s Encrypt)
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# 其他所有请求跳转 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 服务器
server {
listen 443 ssl http2;
server_name www.example.com example.com;
root /var/www/html;
index index.html;
# SSL 证书
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# SSL 优化
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
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 off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# 安全头
add_header Strict-Transport-Security “max-age=63072000; 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 Content-Security-Policy “default-src ‘self’; script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ https://cdn.example.com; style-src ‘self’ ‘unsafe-inline’ https://fonts.googleapis.com; font-src ‘self’ https://fonts.gstatic.com; img-src ‘self’ data: https:; connect-src ‘self’ https://api.example.com;” always;
# 静态资源
location /static/ {
alias /var/www/static/;
expires 30d;
add_header Cache-Control “public, immutable”;
}
# 动态请求
location / {
try_files $uri $uri/ /index.html;
}
}
证书自动更新脚本
#!/bin/bash
# /usr/local/bin/certbot-renew.sh
# 更新证书
certbot renew —quiet
# 检查 Nginx 配置
nginx -t
# 重载 Nginx
if [ $? -eq 0 ]; then
systemctl reload nginx
echo “Nginx reloaded successfully”
else
echo “Nginx config test failed”
exit 1
fi
定时任务
# crontab -e
# 每天凌晨 2 点检查证书更新
0 2 * * * /usr/local/bin/certbot-renew.sh >> /var/log/certbot-renew.log 2>&1
案例四:高并发直播流媒体
场景描述
直播平台,需要处理高并发 HTTP-FLV/HLS 流媒体分发。
解决方案
# 需要安装 nginx-rtmp-module
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 65535;
use epoll;
multi_accept on;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
# 访问日志
log_format main ‘$remote_addr - [$time_local] “$request” ‘
‘$status $bytes_sent “$http_referer” ‘
‘“$http_user_agent” $request_time’;
# 限流
limit_req_zone $binary_remote_addr zone=stream_limit:10m rate=10r/s;
server {
listen 80;
server_name live.example.com;
access_log /var/log/nginx/live.access.log main;
error_log /var/log/nginx/live.error.log warn;
# HLS 分发
location /hls/ {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www/stream;
# 防止盗链
valid_referers none blocked server_names *.example.com example.com;
if ($invalid_referer) {
return 403;
}
# 缓存配置
add_header Cache-Control “max-age=60”;
expires 1m;
}
# FLV 流
location /live/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Connection “”;
proxy_buffering off;
proxy_cache off;
proxy_redirect off;
# 超时设置(长连接)
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
# 统计信息
location /stats {
stub_status on;
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
}
}
}
# RTMP 配置
rtmp {
server {
listen 1935;
chunk_size 4096;
# 直播应用
application live {
live on;
record off;
# HLS
hls on;
hls_path /var/www/stream/hls;
hls_fragment 5s;
hls_playlist_length 15s;
# 限制
max_connections 1000;
# 推流认证
on_publish http://127.0.0.1:8080/auth/publish;
on_play http://127.0.0.1:8080/auth/play;
}
# 录制应用
application record {
live on;
record all;
record_path /var/www/stream/record;
record_unique on;
}
}
}
附录:常用命令速查
# 配置测试
nginx -t
nginx -T
# 启动/停止/重启
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
systemctl reload nginx # 平滑重载
# 查看状态
systemctl status nginx
ps aux | grep nginx
# 查看监听端口
netstat -tlnp | grep nginx
ss -tlnp | grep nginx
# 日志操作
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
grep “404” /var/log/nginx/access.log
# 平滑升级
nginx -s upgrade
# 查看编译参数
nginx -V
结语
Nginx 作为高性能的 Web 服务器和反向代理,在生产环境中扮演着重要角色。掌握常见问题的排查方法和解决方案,能够帮助我们:
- 快速定位问题:通过日志和状态码快速找到问题根源
- 合理配置优化:根据业务场景调整配置参数,进行有效的性能优化
- 保障系统稳定:通过限流、超时等机制保护后端服务
- 提升访问体验:通过缓存、压缩等手段加速页面加载
希望这份指南能帮助你在实际工作中更好地使用 Nginx,遇到问题时能够快速找到解决方案。如果你有更多的 Nginx 使用心得或问题,欢迎在云栈社区与更多开发者交流讨论。
参考资料
- Nginx 官方文档
- Nginx 配置最佳实践
- Mozilla SSL 配置生成器
- Nginx 性能优化指南