Nginx 配置与反向代理规范
2026/3/20大约 5 分钟
Nginx 配置与反向代理规范
提示
Nginx 是现代 Web 部署的核心组件,承担反向代理、负载均衡、静态资源服务、SSL 终止等关键职责。
核心原则
- 统一入口:所有 HTTP 流量通过 Nginx 入口
- SSL 终止:HTTPS 在 Nginx 层处理,后端用 HTTP
- 配置分离:每个站点独立配置文件
- 安全优先:隐藏版本、限制请求、防注入
目录结构规范
/etc/nginx/
├── nginx.conf # 主配置文件(通常不改)
├── sites-available/ # 所有站点配置
│ ├── default # 默认站点
│ ├── blog.example.com # 博客站点
│ └── api.example.com # API 站点
├── sites-enabled/ # 已启用站点(软链接)
│ ├── default -> ../sites-available/default
│ └── blog.example.com -> ../sites-available/blog.example.com
├── conf.d/ # 全局配置片段
│ ├── gzip.conf # Gzip 压缩配置
│ ├── security.conf # 安全配置
│ └── ssl.conf # SSL 通用配置
├── snippets/ # 可复用配置片段
│ ├── ssl-params.conf
│ └── proxy-params.conf
└── ssl/ # SSL 证书目录
├── blog.example.com.crt
└── blog.example.com.key
主配置文件
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
# 基础设置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# 隐藏版本号
server_tokens off;
# MIME 类型
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
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"';
access_log /var/log/nginx/access.log main;
# 加载配置片段
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
通用配置片段
Gzip 压缩配置
# /etc/nginx/conf.d/gzip.conf
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss
application/x-javascript
image/svg+xml;
安全配置
# /etc/nginx/conf.d/security.conf
# 防止点击劫持
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;
# 限制请求体大小
client_max_body_size 10M;
# 限制请求头大小
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
# 限制请求频率(需要在 server 块中引用)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
SSL 通用配置
# /etc/nginx/snippets/ssl-params.conf
# 协议版本
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;
# SSL 会话缓存
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets 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;
反向代理参数
# /etc/nginx/snippets/proxy-params.conf
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_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
站点配置模板
静态网站
# /etc/nginx/sites-available/blog.example.com
server {
listen 80;
listen [::]:80;
server_name blog.example.com;
# HTTP 重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name blog.example.com;
# SSL 证书
ssl_certificate /etc/nginx/ssl/blog.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/blog.example.com.key;
include snippets/ssl-params.conf;
# 网站根目录
root /opt/apps/blog/current/dist;
index index.html;
# 访问日志
access_log /var/log/nginx/blog.access.log main;
error_log /var/log/nginx/blog.error.log;
# 静态文件缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA 路由支持
location / {
try_files $uri $uri/ /index.html;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}
Node.js/API 反向代理
# /etc/nginx/sites-available/api.example.com
upstream api_backend {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
include snippets/ssl-params.conf;
access_log /var/log/nginx/api.access.log main;
error_log /var/log/nginx/api.error.log;
# API 请求频率限制
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
location / {
include snippets/proxy-params.conf;
proxy_pass http://api_backend;
}
# 健康检查端点(不记录日志)
location /health {
access_log off;
proxy_pass http://api_backend;
}
# WebSocket 支持
location /ws {
include snippets/proxy-params.conf;
proxy_pass http://api_backend;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
负载均衡
# /etc/nginx/sites-available/app.example.com
upstream app_servers {
# 负载均衡策略
# 默认轮询
# least_conn; # 最少连接
# ip_hash; # IP 哈希(会话保持)
server 10.0.0.10:3000 weight=3;
server 10.0.0.11:3000 weight=2;
server 10.0.0.12:3000 backup; # 备份服务器
keepalive 32;
}
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/nginx/ssl/app.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/app.example.com.key;
include snippets/ssl-params.conf;
location / {
include snippets/proxy-params.conf;
proxy_pass http://app_servers;
# 故障转移
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_next_upstream_tries 3;
}
}
多应用单域名
# /etc/nginx/sites-available/example.com
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;
include snippets/ssl-params.conf;
# 前端静态文件
location / {
root /opt/apps/frontend/current/dist;
try_files $uri $uri/ /index.html;
}
# API 接口
location /api/ {
include snippets/proxy-params.conf;
proxy_pass http://127.0.0.1:3000/;
}
# 管理后台
location /admin/ {
include snippets/proxy-params.conf;
proxy_pass http://127.0.0.1:3001/;
}
# 静态资源
location /uploads/ {
alias /opt/apps/shared/uploads/;
expires 30d;
}
}
常用操作
站点管理
# 启用站点(创建软链接)
sudo ln -s /etc/nginx/sites-available/blog.example.com /etc/nginx/sites-enabled/
# 禁用站点(删除软链接)
sudo rm /etc/nginx/sites-enabled/blog.example.com
# 测试配置语法
sudo nginx -t
# 重新加载配置(不中断服务)
sudo systemctl reload nginx
# 重启服务
sudo systemctl restart nginx
日志管理
# 查看访问日志
tail -f /var/log/nginx/access.log
# 查看错误日志
tail -f /var/log/nginx/error.log
# 按状态码统计
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 按 IP 统计访问量
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 查看慢请求
awk '$NF > 1' /var/log/nginx/access.log
日志轮转
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
SSL 证书配置
Let's Encrypt 证书(推荐)
# 安装 Certbot
sudo apt install certbot python3-certbot-nginx
# 获取证书(自动配置 Nginx)
sudo certbot --nginx -d blog.example.com
# 仅获取证书(手动配置)
sudo certbot certonly --webroot -w /opt/apps/blog/current/dist -d blog.example.com
# 测试自动续期
sudo certbot renew --dry-run
# 证书位置
# /etc/letsencrypt/live/blog.example.com/fullchain.pem
# /etc/letsencrypt/live/blog.example.com/privkey.pem
手动配置证书
server {
listen 443 ssl http2;
server_name blog.example.com;
# Let's Encrypt 证书
ssl_certificate /etc/letsencrypt/live/blog.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog.example.com/privkey.pem;
# 或自购证书
# ssl_certificate /etc/nginx/ssl/blog.example.com.crt;
# ssl_certificate_key /etc/nginx/ssl/blog.example.com.key;
include snippets/ssl-params.conf;
# ... 其他配置
}
常见错误
❌ 错误做法
# 1. 直接修改主配置文件
# /etc/nginx/nginx.conf 中添加站点配置
# 2. 证书权限太松
chmod 777 /etc/nginx/ssl/
# 3. 暴露后端端口
# 应用监听 0.0.0.0:3000 而不是 127.0.0.1:3000
# 4. 没有配置 HTTPS 重定向
server {
listen 80;
listen 443 ssl; # 同时监听 HTTP 和 HTTPS
}
# 5. 缺少安全头
# 没有 X-Frame-Options, X-Content-Type-Options 等
✅ 正确做法
# 1. 使用 sites-available/enabled 管理站点
# 2. 证书权限正确
chmod 600 /etc/nginx/ssl/*.key
chmod 644 /etc/nginx/ssl/*.crt
# 3. 应用只监听本地
# node: app.listen(3000, '127.0.0.1')
# 4. HTTP 单独重定向
server {
listen 80;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
# ...
}
# 5. 包含安全配置
include /etc/nginx/conf.d/security.conf;