为什么你的 Nginx 配置总是不够快?
很多开发者第一次接触 Nginx 时,往往是复制一段“万能配置”就上线了。结果流量一上来,502、504 频繁出现,或者静态资源加载缓慢。其实 Nginx 的默认配置是为通用场景设计的,要发挥它的威力,必须根据业务特点进行针对性调优。
本文将以一个典型的前后端分离项目为例:前端是 Vue 打包的静态文件,后端是运行在 8080 端口的 Spring Boot 应用。我们将从零开始配置 Nginx,实现反向代理、负载均衡、HTTPS、缓存和性能优化,并分享一些踩坑经验。
环境准备
假设你有一台 Linux 服务器(Ubuntu 20.04 或 CentOS 7+),已经安装了 Nginx。如果没有,可以用以下命令安装:
# Ubuntu/Debian
sudo apt update && sudo apt install nginx -y
# CentOS/RHEL
sudo yum install epel-release -y && sudo yum install nginx -y
检查版本:nginx -v,建议使用 1.18+ 以支持 HTTP/2 和更优的 TLS 配置。
第一步:基础反向代理配置
Nginx 的核心功能之一就是反向代理。我们先配置一个最简单的代理,将 /api/ 请求转发到后端服务。
创建配置文件 /etc/nginx/conf.d/myapp.conf:
server {
listen 80;
server_name example.com;
# 前端静态文件
location / {
root /var/www/myapp/dist;
index index.html;
try_files $uri $uri/ /index.html; # 支持 Vue/React 的 history 路由
}
# 后端 API 代理
location /api/ {
proxy_pass http://127.0.0.1:8080/; # 注意末尾的斜杠
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;
}
}
关键点解析:
proxypass末尾的斜杠:如果location是/api/,而proxypass是http://127.0.0.1:8080/,那么请求/api/user会被转发为/user。如果proxy_pass没有末尾斜杠,则会转发为/api/user。这个细节极易出错,务必根据后端路由设计选择。try_files:对于单页应用,任何找不到的路径都返回index.html,由前端路由处理。- 转发头信息:让后端能获取真实客户端 IP 和协议,对日志和重定向很重要。
测试配置并重载:
sudo nginx -t
sudo nginx -s reload
第二步:负载均衡与健康检查
当后端有多台实例时,可以用 upstream 做负载均衡。假设有两台后端服务器:
upstream backend {
least_conn; # 最少连接数算法,适合长连接场景
server 192.168.1.10:8080 weight=3 max_fails=2 fail_timeout=30s;
server 192.168.1.11:8080 weight=1 max_fails=2 fail_timeout=30s;
keepalive 32; # 保持与后端的长连接,减少握手开销
}
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass http://backend/;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 配合 keepalive 使用
# ... 其他头信息
}
}
注意:
least_conn比默认的轮询更适合请求处理时间不均的场景。weight可以根据服务器性能调整权重。maxfails和failtimeout实现被动健康检查:30 秒内失败 2 次则暂时剔除该节点。keepalive需要配合proxyhttpversion 1.1和proxysetheader Connection ""才能生效,否则可能适得其反。
💡 进阶: 如果需要主动健康检查,可以考虑 Nginx Plus 或使用 OpenResty 的 lua-resty-healthcheck。
第三步:HTTPS 与 HTTP/2 配置
安全是现代 Web 的标配。使用 Let’s Encrypt 免费证书:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com -d www.example.com
Certbot 会自动修改 Nginx 配置,但我们可以手动优化 TLS 参数:
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 配置
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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# 会话复用,提升性能
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS (谨慎开启,确保所有子域名都支持 HTTPS)
add_header Strict-Transport-Security "max-age=63072000" always;
# ... 其他 location 配置
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
注意:
sslpreferserver_ciphers off让客户端选择加密套件,通常更快,因为客户端更了解自己的硬件。sslsessiontickets off提升前向安全性,但会稍微增加握手开销。如果追求性能,可以开启。- HSTS 头一旦被浏览器记录,在 max-age 内无法回退,测试时先用小 max-age。
第四步:性能优化参数
Nginx 的性能很大程度上取决于 nginx.conf 中的全局配置。以下是一个针对高并发的优化模板:
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto; # 自动匹配 CPU 核心数
worker_rlimit_nofile 65535; # 每个 worker 能打开的最大文件数
events {
worker_connections 65535; # 每个 worker 的最大连接数
multi_accept on; # 一次接受所有新连接
use epoll; # Linux 下高性能事件模型
}
http {
# 基础优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off; # 隐藏版本号
# 客户端缓存
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
# 缓冲区
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;
# 超时
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
# 代理缓冲区
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
参数解释:
worker_processes auto:通常设置为 CPU 核心数,但若磁盘 I/O 密集,可以适当增加。workerconnections:理论最大连接数 = workerprocesses * worker_connections。但受限于系统文件描述符,需同步调整ulimit -n。multi_accept on:让 worker 一次尽可能多地接受连接,高并发下有效。openfilecache:缓存文件描述符,减少磁盘 I/O,对静态文件服务提升明显。gzipcomplevel 6:压缩级别 6 是性能与压缩比的平衡点,再高收益递减。
💡 系统层面优化: 修改 /etc/security/limits.conf 增加 nofile,调整内核参数如 net.core.somaxconn、net.ipv4.tcptwreuse 等。
第五步:静态资源缓存与 CDN 配合
对于前端静态资源,利用浏览器缓存能大幅减少请求。在 location 中为带哈希的文件设置长期缓存:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
root /var/www/myapp/dist;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location = /index.html {
root /var/www/myapp/dist;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
注意:
- 只有文件名包含哈希(如
app.abc123.js)才能设置长期缓存,否则更新后客户端无法获取新版本。 index.html必须禁用缓存,否则用户可能一直使用旧版本。- 如果使用 CDN,可以在 CDN 回源时设置缓存规则,Nginx 层可以简化。
常见坑与排查技巧
- 502 Bad Gateway:通常是后端服务未启动或端口不对。检查
proxy_pass地址,查看后端日志。 - 504 Gateway Timeout:后端处理超时。调整
proxyreadtimeout(默认 60s),但更应优化后端性能。 - 413 Request Entity Too Large:上传文件大小限制。调整
clientmaxbody_size。 - 静态资源 404:检查
root路径是否正确,权限是否足够(Nginx 用户需有读权限)。 - WebSocket 代理失败:需要额外配置:
“nginx proxysetheader Upgrade $httpupgrade; proxyset_header Connection "upgrade"; “
- 跨域问题:可以在 Nginx 层添加 CORS 头,但注意不要与后端重复。
调试利器:
nginx -t测试配置语法。tail -f /var/log/nginx/error.log实时查看错误。curl -I -H "Host: example.com" http://127.0.0.1模拟请求。- 使用
nginx -T输出最终生效的完整配置,排查 include 冲突。
总结与下一步
通过以上五步,你已经拥有了一个支持反向代理、负载均衡、HTTPS、缓存和高并发优化的 Nginx 配置。记住,没有“万能配置”,一定要根据实际业务压测后调整参数。
延伸方向:
- 使用 OpenResty 和 Lua 实现动态限流、鉴权。
- 配置 Nginx 作为 API 网关,集成 JWT 验证。
- 结合 Prometheus + Grafana 监控 Nginx 指标(需
nginx-module-vts)。 - 学习
map指令实现更灵活的条件判断。
希望本文能帮你少走弯路,构建更稳定的 Web 服务。如果有问题,欢迎在评论区交流。