Nginx 进阶配置
大约 9 分钟约 2813 字
Nginx 进阶配置
简介
Nginx 不仅是高性能 Web 服务器,还是强大的反向代理、负载均衡器和 API 网关。进阶配置包括 upstream 负载均衡、HTTPS 配置、缓存策略、限流、WebSocket 代理等,是 .NET 应用部署的关键基础设施。
特点
反向代理 .NET 应用
基本配置
# /etc/nginx/conf.d/myapp.conf
# 上游服务 — .NET 应用集群
upstream dotnet_backend {
# 负载均衡策略
least_conn; # 最少连接数
server 127.0.0.1:5000 weight=3; # 权重 3
server 127.0.0.1:5001 weight=2; # 权重 2
server 127.0.0.1:5002 backup; # 备用服务器
keepalive 32; # 保持 32 个长连接
}
server {
listen 80;
server_name api.example.com;
# HTTP 重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.example.com;
# SSL 证书
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
# 日志
access_log /var/log/nginx/api_access.log;
error_log /var/log/nginx/api_error.log;
# API 代理
location /api/ {
proxy_pass http://dotnet_backend;
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_set_header Upgrade $http_upgrade;
# 超时
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 120s;
# 缓冲
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# Swagger(仅开发/测试环境)
location /swagger/ {
proxy_pass http://dotnet_backend;
proxy_set_header Host $host;
}
# 健康检查
location /health {
proxy_pass http://dotnet_backend;
access_log off; # 不记录健康检查日志
}
}负载均衡策略
策略对比
# 1. 轮询(默认)
upstream round_robin {
server 10.0.0.1:5000;
server 10.0.0.2:5000;
server 10.0.0.3:5000;
}
# 2. 加权轮询
upstream weighted {
server 10.0.0.1:5000 weight=5; # 5/8 流量
server 10.0.0.2:5000 weight=2; # 2/8 流量
server 10.0.0.3:5000 weight=1; # 1/8 流量
}
# 3. 最少连接
upstream least_conn {
least_conn;
server 10.0.0.1:5000;
server 10.0.0.2:5000;
}
# 4. IP 哈希(会话保持)
upstream ip_hash {
ip_hash;
server 10.0.0.1:5000;
server 10.0.0.2:5000;
}
# 5. 一致性哈希
upstream consistent {
hash $request_uri consistent;
server 10.0.0.1:5000;
server 10.0.0.2:5000;
}健康检查
upstream backend {
server 10.0.0.1:5000 max_fails=3 fail_timeout=30s;
server 10.0.0.2:5000 max_fails=3 fail_timeout=30s;
server 10.0.0.3:5000 backup;
}
# max_fails=3 — 失败3次标记不可用
# fail_timeout=30s — 30秒后重试
# backup — 只在其他服务器不可用时启用HTTPS 与证书管理
Let's Encrypt 免费证书
# 安装 certbot
yum install -y certbot python3-certbot-nginx
# 自动申请并配置证书
certbot --nginx -d api.example.com -d www.example.com
# 仅申请证书(手动配置)
certbot certonly --webroot -w /var/www/html -d api.example.com
# 自动续期(certbot 自动添加 cron)
certbot renew --dry-run
# 查看已安装的证书
certbot certificates
# 证书文件路径
# /etc/letsencrypt/live/api.example.com/fullchain.pem
# /etc/letsencrypt/live/api.example.com/privkey.pemSSL 优化配置
# /etc/nginx/conf.d/ssl.conf
# SSL 会话缓存(减少握手开销)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling(减少客户端验证延迟)
ssl_stapling on;
ssl_stapling_verify on;
resolver 223.5.5.5 8.8.8.8 valid=300s;
resolver_timeout 5s;
# 现代加密套件
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
# DH 参数(增强前向安全性)
# openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
ssl_dhparam /etc/nginx/ssl/dhparam.pem;多域名 HTTPS 配置
# 一个 IP 多个 HTTPS 站点(SNI)
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
# ...其余配置
}
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
# ...其余配置
}
# HTTP 自动跳转 HTTPS(server_name 使用 _ 进行默认匹配)
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}限流配置
请求限流
# http 块中定义限流区域
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=upload_limit:10m rate=10r/s;
server {
# API 限流 — 100 请求/秒,突发 50
location /api/ {
limit_req zone=api_limit burst=50 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
# 登录限流 — 5 请求/秒
location /api/auth/login {
limit_req zone=auth_limit burst=10 nodelay;
proxy_pass http://backend;
}
# 上传限流 — 10 请求/秒
location /api/upload {
limit_req zone=upload_limit burst=20 nodelay;
client_max_body_size 100m;
proxy_pass http://backend;
}
}静态文件缓存
前端资源缓存
server {
listen 80;
server_name www.example.com;
root /var/www/frontend;
# SPA 路由回退
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源 — 长期缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# HTML — 不缓存
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
}WebSocket 代理
SignalR 支持
server {
listen 80;
server_name ws.example.com;
location /hubs/ {
proxy_pass http://dotnet_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket 超时
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}连接与带宽限制
# 并发连接限制
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# 按服务器级别限制
limit_conn_zone $server_name zone=server_conn:10m;
server {
# 每个 IP 最多 20 个并发连接
limit_conn conn_limit 20;
# 限制上传带宽(用于防止大文件下载耗尽带宽)
limit_rate 512k;
# 客户端下载超过 5MB 后开始限速(小文件不限速)
limit_rate_after 5m;
}
# 白名单不限流
geo $limit_key {
default $binary_remote_addr;
10.0.0.0/8 "";
192.168.0.0/16 "";
}
limit_req_zone $limit_key zone=api_limit:10m rate=100r/s;访问控制与安全
IP 黑白名单
# 基于 IP 的访问控制
location /admin/ {
allow 10.0.0.0/8;
allow 192.168.1.0/24;
deny all;
proxy_pass http://backend;
}
# 基于地理位置的访问控制(需要 GeoIP 模块)
# 禁止特定国家访问
location /api/ {
if ($geoip_country_code = CN) {
# 允许中国访问
}
if ($geoip_country_code != CN) {
return 403;
}
proxy_pass http://backend;
}防盗链配置
# 图片防盗链
location ~* \.(jpg|jpeg|png|gif|bmp|webp)$ {
valid_referers none blocked server_names *.example.com example.com;
if ($invalid_referer) {
return 403;
# 或返回水印图片
# rewrite ^(.*)$ /static/watermark.png break;
}
root /var/www/static;
expires 30d;
}
# 资源防盗链(referer 检查)
location /downloads/ {
valid_referers none blocked *.example.com;
if ($invalid_referer) {
return 403;
}
alias /data/downloads/;
}阻止恶意请求
# 阻止特定 User-Agent
if ($http_user_agent ~* (bot|crawler|spider|scraper)) {
return 403;
}
# 阻止扫描器常见路径
location ~* /(wp-admin|wp-login|xmlrpc|phpmyadmin|admin) {
return 444; # 444 = Nginx 特殊状态码,直接断开连接
}
# 阻止特定请求方法
if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|OPTIONS)$) {
return 405;
}
# 请求体大小限制
client_max_body_size 20m; # 上传文件最大 20MB
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;日志管理
日志格式化
# 自定义日志格式(在 http 块中)
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time $upstream_response_time';
log_format json_log escape=json '{'
'"time": "$time_iso8601", '
'"remote_addr": "$remote_addr", '
'"request": "$request", '
'"status": $status, '
'"body_bytes_sent": $body_bytes_sent, '
'"request_time": $request_time, '
'"upstream_response_time": "$upstream_response_time", '
'"upstream_addr": "$upstream_addr", '
'"http_referrer": "$http_referer", '
'"http_user_agent": "$http_user_agent"'
'}';
# 使用 JSON 格式日志(方便 ELK 分析)
access_log /var/log/nginx/access_json.log json_log;
# 按域名分日志
access_log /var/log/nginx/api.example.com.access.log main;日志切割与归档
# 手动切割日志
mv /var/log/nginx/access.log /var/log/nginx/access_$(date +%Y%m%d).log
nginx -s reopen
# 使用 logrotate 自动切割
cat > /etc/logrotate.d/nginx << 'EOF'
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endpostrotate
}
EOF
# 验证 logrotate 配置
logrotate -d -f /etc/logrotate.d/nginx不记录特定请求的日志
# 不记录健康检查日志
location /health {
access_log off;
return 200 "OK";
}
# 不记录静态资源日志
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|ttf|eot)$ {
access_log off;
expires 30d;
}
# 不记录特定 IP 的日志
map $remote_addr $loggable {
10.0.0.0/8 0;
192.168.0.0/16 0;
default 1;
}
access_log /var/log/nginx/access.log main if=$loggable;Nginx 代理缓存
# 在 http 块中配置缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:100m
max_size=10g inactive=60m use_temp_path=off;
server {
# 缓存 API 响应
location /api/public/ {
proxy_cache api_cache;
proxy_cache_valid 200 5m; # 200 响应缓存 5 分钟
proxy_cache_valid 404 1m; # 404 缓存 1 分钟
proxy_cache_key $scheme$host$request_uri;
proxy_cache_bypass $http_cache_control; # 客户端可跳过缓存
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://backend;
}
# 清除缓存(需要安装 ngx_cache_purge 模块)
location /purge/ {
allow 127.0.0.1;
deny all;
proxy_cache_purge api_cache $scheme$host$request_uri;
}
}Nginx 故障排查
常见错误及解决
# 502 Bad Gateway
# 原因:后端服务未启动或端口不对
curl http://127.0.0.1:5000 # 检查后端是否正常
netstat -tlnp | grep 5000 # 检查端口监听
# 504 Gateway Timeout
# 原因:后端响应太慢
# 解决:增大超时时间或优化后端
proxy_read_timeout 300s;
# 413 Request Entity Too Large
# 原因:上传文件超过 client_max_body_size
client_max_body_size 50m;
# 499 Client Closed Request
# 原因:客户端在 Nginx 还没返回前断开连接
# 可能原因:Nginx 处理太慢或客户端超时
# 查看错误日志
tail -100 /var/log/nginx/error.log
# 调试模式(仅用于排查,不要在生产环境长期开启)
error_log /var/log/nginx/debug.log debug;
# 查看当前连接状态
curl http://127.0.0.1/nginx_status
# 需要在 server 中配置:
# location /nginx_status {
# stub_status on;
# access_log off;
# allow 127.0.0.1;
# deny all;
# }gRPC 代理
HTTP/2 代理
server {
listen 443 ssl http2;
server_name grpc.example.com;
ssl_certificate /etc/nginx/ssl/grpc.crt;
ssl_certificate_key /etc/nginx/ssl/grpc.key;
location / {
grpc_pass grpc://127.0.0.1:5001;
# gRPC 超时
grpc_connect_timeout 60s;
grpc_read_timeout 300s;
grpc_send_timeout 60s;
# 缓冲
grpc_buffer_size 4k;
}
}常用命令
# 配置检查
nginx -t
# 重载配置(不中断服务)
nginx -s reload
# 启动/停止
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
# 查看状态
systemctl status nginx
nginx -V # 查看编译参数和模块
# 日志
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log优点
缺点
总结
Nginx 是 .NET 应用部署的标准反向代理。核心配置:反向代理 + 负载均衡 + HTTPS + 限流。生产环境务必开启 HTTPS、配置安全头、设置合理的超时和限流。掌握 upstream、proxy_pass、limit_req 三大核心指令即可应对大部分场景。
关键知识点
- 部署类主题的核心不是“装成功”,而是“稳定运行、可排障、可回滚”。
- 同一个服务通常至少要关注版本、目录、端口、权限、数据、日志和备份。
- Linux 问题经常跨越系统层、网络层、服务层和应用层。
项目落地视角
- 把安装步骤补成可重复执行的清单,必要时写成脚本或配置文件。
- 把配置目录、数据目录、日志目录和挂载点明确拆开。
- 上线前检查防火墙、SELinux、时区、磁盘、系统服务和健康检查。
常见误区
- 使用 latest 或未固定版本,导致环境不可复现。
- 只验证启动成功,不验证持久化、开机自启和故障恢复。
- 遇到问题先改配置而不是先看日志和依赖链路。
进阶路线
- 继续补齐 systemd、性能监控、安全加固和备份恢复。
- 把单机操作升级成 Docker、Kubernetes 或 IaC 方案。
- 建立标准化运维手册,包括巡检、扩容、回滚和灾备演练。
适用场景
- 当你准备把《Nginx 进阶配置》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合单机环境初始化、中间件快速搭建、测试环境验证和生产部署前准备。
- 当服务稳定性依赖端口、权限、目录、网络和系统参数时,这类主题会直接影响成败。
落地建议
- 固定版本号与镜像标签,避免“latest”带来的不可预期变化。
- 把配置、数据、日志目录拆开管理,并记录恢复步骤。
- 上线前确认端口、防火墙、SELinux、时区和磁盘空间。
排错清单
- 先查 systemctl、容器日志和应用日志,确认失败发生在哪一层。
- 检查端口占用、目录权限、挂载路径和网络连通性。
- 如果是新环境问题,优先对比与已知正常环境的差异。
复盘问题
- 如果把《Nginx 进阶配置》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《Nginx 进阶配置》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《Nginx 进阶配置》最大的收益和代价分别是什么?
