lolly/docs/28-nginx-api-gateway.md
xfy ae8ea1ce0c docs: 添加 nginx 高级主题文档 (Lua/安全/API网关/动态配置)
新增 5 篇深度文档:
- Lua 模块深度指南:OpenResty、ngx_lua、cosocket
- 安全深度指南:WAF、DDoS 防护、OWASP Top 10
- API 网关配置:路由设计、JWT 验证、限流配额
- 动态配置与服务发现:etcd/Consul、nginx-unit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-03 16:57:22 +08:00

1528 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NGINX API 网关配置指南
## 1. API 网关概述
### 什么是 API 网关
API 网关是微服务架构中的关键组件作为单一入口点统一管理和暴露后端服务。NGINX 作为高性能反向代理,非常适合构建功能完善的 API 网关。
### API 网关核心功能
| 功能 | 说明 |
|------|------|
| **请求路由** | 根据路径、方法、Header 路由到不同后端服务 |
| **负载均衡** | 在多个服务实例间分发请求 |
| **认证授权** | JWT、OAuth2、API Key 验证 |
| **限流熔断** | 防止过载和服务雪崩 |
| **协议转换** | HTTP/HTTPS、WebSocket、gRPC 转换 |
| **请求/响应转换** | 修改请求头、响应体、路径重写 |
| **缓存加速** | 缓存常用 API 响应 |
| **日志监控** | 统一收集 API 调用日志和指标 |
### API 网关架构图
```
┌─────────────────┐
│ API Gateway │
│ (NGINX) │
└────────┬────────┘
┌─────────┬───────┴───────┬─────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ User Svc │ │ Order Svc│ │PaymentSvc│ │ SearchSvc│
└──────────┘ └──────────┘ └──────────┘ └──────────┘
```
---
## 2. API 路由设计模式
### 2.1 基于路径的路由
最常见的路由方式,根据 URL 路径前缀路由到不同服务。
```nginx
http {
upstream user_service {
server user-svc:8080;
}
upstream order_service {
server order-svc:8081;
}
upstream payment_service {
server payment-svc:8082;
}
server {
listen 80;
server_name api.example.com;
# 用户服务路由
location /api/v1/users/ {
proxy_pass http://user_service/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 订单服务路由
location /api/v1/orders/ {
proxy_pass http://order_service/;
proxy_set_header Host $host;
}
# 支付服务路由
location /api/v1/payments/ {
proxy_pass http://payment_service/;
proxy_set_header Host $host;
}
}
}
```
### 2.2 基于请求方法的路由
同一路径根据 HTTP 方法路由到不同服务。
```nginx
server {
listen 80;
server_name api.example.com;
# 查询操作路由到只读服务
location /api/v1/data/ {
if ($request_method ~ ^(GET|HEAD)$) {
proxy_pass http://readonly_backend;
break;
}
# 写入操作路由到主服务
if ($request_method ~ ^(POST|PUT|PATCH|DELETE)$) {
proxy_pass http://write_backend;
break;
}
return 405; # Method Not Allowed
}
}
```
### 2.3 基于 Header 的路由
根据请求头内容路由,常用于 A/B 测试、金丝雀发布。
```nginx
http {
map $http_x_api_version $backend_pool {
default "stable_backend";
"v2" "beta_backend";
"v2-beta" "beta_backend";
}
upstream stable_backend {
server api-v1:8080;
}
upstream beta_backend {
server api-v2:8080;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://$backend_pool;
proxy_set_header Host $host;
}
}
}
```
### 2.4 基于 Cookie 的路由
```nginx
http {
map $cookie_app_version $backend_node {
default "stable";
"beta" "canary";
}
upstream stable {
server api-stable:8080;
}
upstream canary {
server api-canary:8080;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://$backend_node;
}
}
}
```
### 2.5 流量分流路由(百分比)
```nginx
http {
# 使用 split_clients 进行百分比分流
split_clients "${remote_addr}${http_user_agent}" $variant {
10% canary; # 10% 流量到新版本
* stable; # 90% 流量到稳定版
}
upstream stable {
server api-v1:8080;
}
upstream canary {
server api-v2:8080;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://$variant;
proxy_set_header X-Variant $variant;
}
}
}
```
### 2.6 组合路由策略
```nginx
http {
# 定义映射变量
map $http_x_env $target_backend {
default prod;
"staging" staging;
"dev" dev;
}
map $http_x_tenant_id $tenant_shard {
default shard1;
~^1[0-5] shard1; # 租户 10-15
~^1[6-9]|^2[0] shard2; # 租户 16-20
}
upstream prod {
server api-prod-1:8080;
server api-prod-2:8080;
}
upstream staging {
server api-staging:8080;
}
upstream dev {
server api-dev:8080;
}
upstream shard1 {
server db-shard1:8080;
}
upstream shard2 {
server db-shard2:8080;
}
server {
listen 80;
server_name api.example.com;
# 环境路由
location /api/ {
proxy_pass http://$target_backend;
proxy_set_header X-Tenant-Shard $tenant_shard;
# 记录路由决策
access_log /var/log/nginx/api-access.log detailed;
}
# 租户数据路由
location /api/tenant-data/ {
proxy_pass http://$tenant_shard;
}
}
}
```
---
## 3. 请求/响应转换
### 3.1 请求头转换
#### 添加请求头
```nginx
server {
listen 80;
server_name api.example.com;
location /api/ {
# 传递客户端信息
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;
proxy_set_header X-Forwarded-Port $server_port;
# 添加网关标识
proxy_set_header X-API-Gateway "nginx";
proxy_set_header X-Request-ID $request_id;
# 添加时间戳
proxy_set_header X-Request-Time $msec;
proxy_pass http://backend;
}
}
```
#### 删除请求头
```nginx
server {
location /api/ {
# 删除敏感请求头,防止信息泄露
proxy_set_header Authorization "";
proxy_set_header Cookie "";
proxy_set_header X-Internal-Token "";
proxy_pass http://backend;
}
}
```
#### 修改请求头
```nginx
server {
location /api/ {
# 重写 Host 头
proxy_set_header Host backend.internal.com;
# 基于条件设置
if ($http_x_client_type = "mobile") {
proxy_set_header X-Device-Type "mobile";
}
proxy_pass http://backend;
}
}
```
### 3.2 响应头转换
#### 添加安全响应头
```nginx
server {
listen 80;
server_name api.example.com;
# 添加 API 响应头
add_header X-API-Version "v1" always;
add_header X-RateLimit-Limit "1000" 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;
# CORS 头
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Request-ID" always;
location /api/ {
proxy_pass http://backend;
# 暴露额外响应头给前端
expose_headers X-Request-ID X-RateLimit-Remaining;
}
}
```
#### 隐藏响应头
```nginx
server {
location /api/ {
proxy_pass http://backend;
# 隐藏后端服务器信息
proxy_hide_header X-Powered-By;
proxy_hide_header X-Runtime;
proxy_hide_header X-Version;
proxy_hide_header Server;
}
}
```
### 3.3 请求体转换
#### 请求体大小限制
```nginx
http {
# 全局请求体限制
client_max_body_size 10m;
client_body_buffer_size 128k;
server {
listen 80;
server_name api.example.com;
# 上传接口允许更大请求体
location /api/v1/upload/ {
client_max_body_size 100m;
proxy_pass http://upload_backend;
}
# Webhook 接口限制较小
location /api/v1/webhooks/ {
client_max_body_size 1m;
proxy_pass http://webhook_backend;
}
# 普通 API
location /api/ {
client_max_body_size 5m;
proxy_pass http://api_backend;
}
}
}
```
### 3.4 响应体转换sub_filter
#### 修改响应内容
```nginx
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://backend;
# 替换响应中的内部 URL 为外部 URL
sub_filter_once off;
sub_filter_types application/json;
# 替换后端地址为网关地址
sub_filter 'http://backend-internal:8080' 'https://api.example.com';
# 替换版本标识
sub_filter '"version": "internal"' '"version": "public"';
}
}
```
#### JSON 字段脱敏
```nginx
server {
location /api/users/ {
proxy_pass http://user_backend;
# 脱敏手机号示例隐藏中间4位
sub_filter_once off;
sub_filter_types application/json;
sub_filter '([0-9]{3})[0-9]{4}([0-9]{4})' '$1****$2';
}
}
```
### 3.5 URL 重写与转换
#### 路径重写
```nginx
server {
listen 80;
server_name api.example.com;
# 旧版本路径兼容
location /api/v0/ {
rewrite ^/api/v0/(.*)$ /api/v1/$1 permanent;
}
# 内部路径映射
location /api/public/ {
rewrite ^/api/public/(.*)$ /internal/api/$1 break;
proxy_pass http://backend;
}
# 带参数重写
location /api/search/ {
rewrite ^/api/search/(.*)$ /search?q=$1 break;
proxy_pass http://search_backend;
}
}
```
#### 查询参数处理
```nginx
server {
location /api/ {
# 添加默认参数
if ($arg_version = "") {
set $args $args&version=v1;
}
# 移除敏感参数
if ($arg_api_key) {
set $args '';
# 或者保留其他参数
set $args $arg_foo=$arg_foo;
}
proxy_pass http://backend;
}
}
```
---
## 4. JWT 验证
### 4.1 通过 auth_request 进行 JWT 验证
使用外部认证服务验证 JWT Token。
```nginx
http {
upstream api_backend {
server api:8080;
}
upstream auth_service {
server auth:8080;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
# JWT 验证
auth_request /auth_verify;
# 从认证响应中提取用户信息
auth_request_set $auth_user $upstream_http_x_user_id;
auth_request_set $auth_role $upstream_http_x_user_role;
auth_request_set $auth_tenant $upstream_http_x_tenant_id;
# 传递给后端
proxy_set_header X-User-ID $auth_user;
proxy_set_header X-User-Role $auth_role;
proxy_set_header X-Tenant-ID $auth_tenant;
proxy_pass http://api_backend;
}
# JWT 验证子请求
location = /auth_verify {
internal;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
# 传递 Authorization 头
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Client-IP $remote_addr;
proxy_connect_timeout 3s;
proxy_read_timeout 3s;
}
# 认证失败处理
error_page 401 = @unauthorized;
location @unauthorized {
default_type application/json;
return 401 '{"error":"Unauthorized","code":"INVALID_TOKEN"}';
}
error_page 403 = @forbidden;
location @forbidden {
default_type application/json;
return 403 '{"error":"Forbidden","code":"INSUFFICIENT_PERMISSIONS"}';
}
}
}
```
### 4.2 使用 Lua 进行 JWT 验证OpenResty
```nginx
http {
lua_package_path "/usr/local/lib/lua/?.lua;;";
server {
listen 80;
server_name api.example.com;
location /api/ {
access_by_lua_block {
local jwt = require "resty.jwt"
local validators = require "resty.jwt-validators"
-- 获取 token
local auth_header = ngx.var.http_authorization
if not auth_header then
ngx.status = 401
ngx.say('{"error":"Missing Authorization header"}')
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
local token = string.gsub(auth_header, "Bearer ", "")
-- 验证 JWT
local jwt_obj = jwt:verify(
ngx.var.jwt_secret, -- JWT 密钥
token,
{
iss = "https://auth.example.com",
validators = {
exp = validators.opt_is_not_expired(),
iat = validators.opt_is_not_before_now(),
}
}
)
if not jwt_obj.verified then
ngx.status = 401
ngx.say('{"error":"Invalid token","details":"' .. jwt_obj.reason .. '"}')
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
-- 设置变量供后续使用
ngx.var.jwt_sub = jwt_obj.payload.sub
ngx.var.jwt_role = jwt_obj.payload.role or "user"
}
proxy_set_header X-User-ID $jwt_sub;
proxy_set_header X-User-Role $jwt_role;
proxy_pass http://api_backend;
}
}
}
```
### 4.3 使用 NJSNGINX JavaScript进行 JWT 验证
```nginx
load_module modules/ngx_http_js_module.so;
http {
js_import /etc/nginx/jwt_verify.js;
server {
listen 80;
server_name api.example.com;
location /api/ {
# 调用 NJS 验证
js_set $jwt_payload jwt_verify.verify;
# 验证失败时拒绝
if ($jwt_payload = "") {
return 401 '{"error":"Unauthorized"}';
}
proxy_set_header X-JWT-Payload $jwt_payload;
proxy_pass http://api_backend;
}
}
}
```
**jwt_verify.js**:
```javascript
function verify(r) {
var auth = r.headersIn['Authorization'];
if (!auth || !auth.startsWith('Bearer ')) {
return '';
}
var token = auth.substring(7);
try {
// 简单 JWT 解析base64 解码 payload
var parts = token.split('.');
if (parts.length !== 3) {
return '';
}
// 解码 payload
var payload = parts[1];
// base64url 解码
var decoded = Buffer.from(payload, 'base64url').toString();
var claims = JSON.parse(decoded);
// 验证过期时间
if (claims.exp && claims.exp < Math.floor(Date.now() / 1000)) {
return '';
}
return JSON.stringify(claims);
} catch (e) {
return '';
}
}
export default {verify};
```
### 4.4 JWT 验证配置参考表
| 验证方式 | 优点 | 缺点 | 适用场景 |
|----------|------|------|----------|
| **auth_request** | 灵活、业务逻辑外置、支持复杂验证 | 额外网络请求、延迟增加 | 需要与认证中心实时交互 |
| **Lua (OpenResty)** | 高性能、功能丰富、社区成熟 | 需要 OpenResty 或 lua-nginx-module | 复杂验证逻辑、本地处理 |
| **NJS** | NGINX 官方支持、无需额外模块 | 功能相对简单、性能略低 | 简单验证、官方生态优先 |
---
## 5. 限流与配额管理
### 5.1 基础限流配置
```nginx
http {
# 按 IP 限流区域
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;
# 按用户限流区域
limit_req_zone $http_x_user_id zone=user_limit:10m rate=100r/m;
# 全局 API 限流
limit_req_zone $server_name zone=api_global:10m rate=1000r/s;
server {
listen 80;
server_name api.example.com;
# 全局限流
limit_req zone=api_global burst=200 nodelay;
location /api/ {
# IP 级限流
limit_req zone=ip_limit burst=20 nodelay;
proxy_pass http://api_backend;
}
location /api/v1/users/ {
# 用户级限流
limit_req zone=user_limit burst=10 nodelay;
proxy_pass http://user_backend;
}
}
}
```
### 5.2 分层限流策略
```nginx
http {
# 不同层级的限流区域
limit_req_zone $binary_remote_addr zone=ip:10m rate=30r/s;
limit_req_zone $http_x_api_key zone=api_key:10m rate=100r/s;
limit_req_zone $http_x_user_id zone=user:10m rate=60r/m;
limit_req_zone $server_name zone=global:10m rate=5000r/s;
server {
listen 80;
server_name api.example.com;
# 全局保护
limit_req zone=global burst=1000 nodelay;
# 健康检查端点不限流
location /health {
limit_req off;
access_log off;
return 200 '{"status":"ok"}';
}
# 公开 API - 仅 IP 限流
location /api/public/ {
limit_req zone=ip burst=50 nodelay;
proxy_pass http://public_backend;
}
# 认证 API - IP + API Key 双重限流
location /api/v1/ {
limit_req zone=ip burst=30 nodelay;
limit_req zone=api_key burst=100 nodelay;
proxy_pass http://api_backend;
}
# 用户级 API - 三层限流
location /api/v1/user/ {
limit_req zone=ip burst=20 nodelay;
limit_req zone=api_key burst=50 nodelay;
limit_req zone=user burst=10 nodelay;
proxy_pass http://user_backend;
}
}
}
```
### 5.3 配额管理(基于连接数)
```nginx
http {
# 按 API Key 限制并发连接
limit_conn_zone $http_x_api_key zone=conn_by_key:10m;
# 按用户限制并发连接
limit_conn_zone $http_x_user_id zone=conn_by_user:10m;
server {
listen 80;
server_name api.example.com;
location /api/v1/stream/ {
# 每个 API Key 最多 10 个并发连接
limit_conn conn_by_key 10;
# 每个用户最多 5 个并发连接
limit_conn conn_by_user 5;
proxy_pass http://streaming_backend;
proxy_buffering off;
}
}
}
```
### 5.4 限流响应自定义
```nginx
http {
limit_req_zone $binary_remote_addr zone=limit:10m rate=10r/s;
server {
listen 80;
server_name api.example.com;
location /api/ {
limit_req zone=limit burst=20 nodelay;
# 自定义限流响应
limit_req_status 429; # Too Many Requests
proxy_pass http://api_backend;
}
# 自定义 429 响应
error_page 429 @rate_limited;
location @rate_limited {
default_type application/json;
add_header Retry-After 60 always;
return 429 '{"error":"Rate limit exceeded","retry_after":60,"limit":10}';
}
}
}
```
### 5.5 基于路径的差异化限流
```nginx
http {
# 不同限流区域
limit_req_zone $binary_remote_addr zone=light:10m rate=100r/m;
limit_req_zone $binary_remote_addr zone=medium:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=heavy:10m rate=1r/s;
map $uri $rate_limit_zone {
default "";
~*^/api/health "none";
~*^/api/search "heavy";
~*^/api/reports "heavy";
~*^/api/export "heavy";
~*^/api/webhooks "light";
}
server {
listen 80;
server_name api.example.com;
location /api/ {
# 根据路径应用不同限流
if ($rate_limit_zone = "none") {
limit_req off;
}
if ($rate_limit_zone = "light") {
limit_req zone=light burst=5 nodelay;
}
if ($rate_limit_zone = "heavy") {
limit_req zone=heavy burst=3 nodelay;
}
proxy_pass http://api_backend;
}
}
}
```
### 5.6 限流指标暴露
```nginx
http {
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
server {
listen 80;
server_name api.example.com;
location /api/ {
limit_req zone=api burst=200 nodelay;
# 添加限流相关响应头
add_header X-RateLimit-Limit 100 always;
add_header X-RateLimit-Window 1s always;
proxy_pass http://api_backend;
}
# 限流状态端点
location /api/status/ratelimit {
limit_req off;
stub_status on;
access_log off;
}
}
}
```
---
## 6. API 版本控制策略
### 6.1 URL 路径版本控制
```nginx
http {
upstream api_v1 {
server api-v1:8080;
}
upstream api_v2 {
server api-v2:8080;
}
server {
listen 80;
server_name api.example.com;
# v1 路由
location /api/v1/ {
proxy_pass http://api_v1/;
proxy_set_header X-API-Version "v1";
}
# v2 路由
location /api/v2/ {
proxy_pass http://api_v2/;
proxy_set_header X-API-Version "v2";
}
# 默认版本(向后兼容)
location /api/ {
rewrite ^/api/(.*)$ /api/v2/$1 break;
proxy_pass http://api_v2;
}
}
}
```
### 6.2 Header 版本控制
```nginx
http {
upstream api_v1 {
server api-v1:8080;
}
upstream api_v2 {
server api-v2:8080;
}
# 根据 Accept-Version 头路由
map $http_accept_version $api_version {
default "v2";
"1" "v1";
"2" "v2";
"v1" "v1";
"v2" "v2";
}
server {
listen 80;
server_name api.example.com;
location /api/ {
# 版本不存在时返回 400
if ($api_version = "") {
return 400 '{"error":"Unsupported API version"}';
}
proxy_pass http://api_$api_version;
proxy_set_header X-API-Version $api_version;
}
}
}
```
### 6.3 内容协商版本控制
```nginx
http {
upstream api_v1 {
server api-v1:8080;
}
upstream api_v2 {
server api-v2:8080;
}
server {
listen 80;
server_name api.example.com;
location /api/users {
# 检查 Accept 头中的版本媒体类型
if ($http_accept ~ "application/vnd\.api\.v2\+json") {
proxy_pass http://api_v2;
break;
}
if ($http_accept ~ "application/vnd\.api\.v1\+json") {
proxy_pass http://api_v1;
break;
}
# 默认版本
proxy_pass http://api_v2;
}
}
}
```
### 6.4 版本弃用与 Sunset
```nginx
http {
server {
listen 80;
server_name api.example.com;
location /api/v1/ {
# 添加弃用警告头
add_header Deprecation "true" always;
add_header Sunset "Sun, 31 Dec 2024 23:59:59 GMT" always;
add_header Link '</api/v2/>; rel="successor-version"' always;
proxy_pass http://api_v1;
}
}
}
```
---
## 7. OpenAPI/Swagger 集成
### 7.1 Swagger UI 托管
```nginx
http {
server {
listen 80;
server_name api.example.com;
# Swagger UI 静态文件
location /docs/ {
alias /var/www/swagger-ui/;
try_files $uri $uri/ /docs/index.html;
}
# OpenAPI 规范文件
location /api-docs/ {
alias /etc/nginx/api-docs/;
default_type application/json;
# CORS
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
}
# 特定服务文档
location /api-docs/users.yaml {
alias /etc/nginx/api-docs/users.yaml;
default_type text/yaml;
}
location /api-docs/orders.yaml {
alias /etc/nginx/api-docs/orders.yaml;
default_type text/yaml;
}
}
}
```
### 7.2 多服务 API 文档聚合
```nginx
http {
server {
listen 80;
server_name api.example.com;
# 聚合文档入口
location /api-docs {
default_type application/json;
return 200 '{
"openapi": "3.0.0",
"info": {
"title": "API Gateway",
"version": "1.0.0"
},
"servers": [
{"url": "https://api.example.com"}
],
"paths": {
"/api/v1/users": {"$ref": "/api-docs/users.yaml#/paths/~1users"},
"/api/v1/orders": {"$ref": "/api-docs/orders.yaml#/paths/~1orders"}
}
}';
}
# 代理到各服务文档
location /api-docs/users/ {
proxy_pass http://user_service/docs/;
}
location /api-docs/orders/ {
proxy_pass http://order_service/docs/;
}
}
}
```
### 7.3 API 文档访问控制
```nginx
http {
server {
listen 80;
server_name api.example.com;
# 公开文档
location /docs/public/ {
alias /var/www/docs/public/;
}
# 内部文档(需认证)
location /docs/internal/ {
auth_basic "Internal API Docs";
auth_basic_user_file /etc/nginx/.htpasswd-docs;
alias /var/www/docs/internal/;
}
# API 定义文件保护
location ~ ^/api-docs/.*\.(yaml|json)$ {
# 只允许特定 referer
valid_referers server_names *.example.com;
if ($invalid_referer) {
return 403;
}
alias /etc/nginx/api-docs/;
}
}
}
```
---
## 8. 完整 API 网关配置示例
### 8.1 生产级 API 网关配置
```nginx
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/json;
# 日志格式
log_format api_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time" '
'req_id="$request_id" api_key="$http_x_api_key" '
'user_id="$jwt_sub" tenant="$jwt_tenant"';
access_log /var/log/nginx/access.log api_log;
# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# 客户端限制
client_max_body_size 10m;
client_body_buffer_size 128k;
client_header_buffer_size 4k;
large_client_header_buffers 4 8k;
# 限流区域
limit_req_zone $binary_remote_addr zone=ip:10m rate=30r/s;
limit_req_zone $http_x_api_key zone=api_key:10m rate=100r/s;
limit_req_zone $server_name zone=global:10m rate=10000r/s;
# 连接限制
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_zone $http_x_api_key zone=api_conn:10m;
# 上游服务定义
upstream user_service {
zone user_service 64k;
least_conn;
server user-svc-1:8080 weight=5;
server user-svc-2:8080 weight=5;
server user-svc-3:8080 backup;
keepalive 32;
}
upstream order_service {
zone order_service 64k;
least_conn;
server order-svc-1:8080;
server order-svc-2:8080;
keepalive 32;
}
upstream payment_service {
zone payment_service 64k;
server payment-svc-1:8080 max_fails=3 fail_timeout=30s;
server payment-svc-2:8080 max_fails=3 fail_timeout=30s;
keepalive 16;
}
upstream auth_service {
zone auth_service 64k;
server auth-svc:8080;
keepalive 16;
}
# 变量映射
map $http_x_api_version $api_version {
default "v1";
"v1" "v1";
"v2" "v2";
}
map $uri $rate_limit_tier {
default "medium";
~*^/api/health "none";
~*^/api/metrics "none";
~*^/api/export "strict";
~*^/api/search "strict";
~*^/api/webhooks "relaxed";
}
# API Gateway 服务器
server {
listen 80;
listen [::]:80;
server_name api.example.com;
# 返回 444 关闭非指定域名访问
location / {
return 444;
}
# 健康检查(无认证、无限流)
location = /health {
access_log off;
limit_req off;
return 200 '{"status":"healthy","gateway":"nginx"}';
}
# Prometheus 指标端点
location = /metrics {
access_log off;
limit_req off;
stub_status on;
}
# API 文档
location /docs/ {
alias /var/www/api-docs/;
try_files $uri $uri/ =404;
# 缓存文档
expires 1h;
add_header Cache-Control "public, immutable";
}
# 主 API 入口
location /api/ {
# 请求 ID 生成
add_header X-Request-ID $request_id always;
# 全局限流
limit_req zone=global burst=2000 nodelay;
# 分层限流
limit_req zone=ip burst=50 nodelay;
limit_req zone=api_key burst=100 nodelay;
# 连接限制
limit_conn addr 50;
limit_conn api_conn 100;
# JWT 验证(可选,根据路径)
location ~ ^/api/(v1|v2)/(users|orders|payments)/ {
auth_request /auth/verify;
auth_request_set $jwt_sub $upstream_http_x_user_id;
auth_request_set $jwt_role $upstream_http_x_user_role;
auth_request_set $jwt_tenant $upstream_http_x_tenant_id;
# 认证失败处理
error_page 401 = @auth_error;
error_page 403 = @forbidden_error;
# 子路径路由
location ~ ^/api/(v1|v2)/users/ {
rewrite ^/api/(v1|v2)/(.*)$ /$2 break;
proxy_pass http://user_service;
}
location ~ ^/api/(v1|v2)/orders/ {
rewrite ^/api/(v1|v2)/(.*)$ /$2 break;
proxy_pass http://order_service;
}
location ~ ^/api/(v1|v2)/payments/ {
rewrite ^/api/(v1|v2)/(.*)$ /$2 break;
proxy_pass http://payment_service;
}
}
# 公开 API无需认证
location ~ ^/api/(v1|v2)/public/ {
rewrite ^/api/(v1|v2)/(.*)$ /$2 break;
proxy_pass http://public_service;
}
}
# 认证子请求
location = /auth/verify {
internal;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_connect_timeout 3s;
proxy_read_timeout 3s;
}
# WebSocket 支持
location /ws/ {
proxy_pass http://websocket_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;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
# 错误处理
error_page 500 502 503 504 @api_error;
location @api_error {
internal;
default_type application/json;
add_header X-Error-Source "gateway" always;
return 500 '{"error":"Internal Server Error","code":"GATEWAY_ERROR"}';
}
location @auth_error {
internal;
default_type application/json;
return 401 '{"error":"Unauthorized","code":"AUTH_REQUIRED"}';
}
location @forbidden_error {
internal;
default_type application/json;
return 403 '{"error":"Forbidden","code":"ACCESS_DENIED"}';
}
location @rate_limited {
internal;
default_type application/json;
add_header Retry-After 60 always;
return 429 '{"error":"Rate limit exceeded","code":"RATE_LIMITED","retry_after":60}';
}
}
# HTTPS 服务器
server {
listen 443 ssl http2;
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 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_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全头部
add_header X-Frame-Options "DENY" 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 配置
include /etc/nginx/api-locations.conf;
}
}
```
### 8.2 配置结构建议
```
/etc/nginx/
├── nginx.conf # 主配置
├── conf.d/
│ ├── 00-upstreams.conf # 上游服务定义
│ ├── 10-limits.conf # 限流配置
│ ├── 20-maps.conf # 变量映射
│ └── 30-ssl.conf # SSL 通用配置
├── sites-enabled/
│ └── api-gateway.conf # API 网关服务器配置
├── api-docs/ # API 文档
│ ├── openapi.yaml
│ ├── users.yaml
│ └── orders.yaml
└── ssl/
├── api.example.com.crt
└── api.example.com.key
```
### 8.3 常用指令速查表
| 类别 | 指令 | 说明 |
|------|------|------|
| **路由** | `proxy_pass` | 代理到后端 |
| | `rewrite` | URL 重写 |
| | `map` | 变量映射 |
| **请求头** | `proxy_set_header` | 设置代理请求头 |
| | `proxy_hide_header` | 隐藏响应头 |
| | `add_header` | 添加响应头 |
| **认证** | `auth_request` | 外部认证 |
| | `auth_request_set` | 提取认证变量 |
| **限流** | `limit_req_zone` | 定义限流区域 |
| | `limit_req` | 应用限流 |
| | `limit_conn_zone` | 定义连接限制区域 |
| | `limit_conn` | 应用连接限制 |
| **转换** | `sub_filter` | 响应内容替换 |
| | `client_max_body_size` | 请求体大小限制 |
---
## 9. 最佳实践
### 9.1 安全最佳实践
1. **始终使用 HTTPS**:生产环境强制 TLSv1.2+
2. **隐藏后端信息**:移除 Server、X-Powered-By 等响应头
3. **启用 HSTS**:防止降级攻击
4. **实施认证**:敏感接口必须认证
5. **输入验证**:限制请求体大小和方法
### 9.2 性能最佳实践
1. **启用 keepalive**:减少连接建立开销
2. **合理配置缓冲区**:平衡内存使用和响应速度
3. **使用缓存**:对读多写少的 API 启用缓存
4. **连接池**:配置上游 keepalive 连接
5. **启用 gzip**:压缩 JSON 响应
### 9.3 可观测性最佳实践
1. **结构化日志**:包含请求 ID、用户 ID、耗时等
2. **健康检查端点**:便于负载均衡器探测
3. **指标暴露**:使用 stub_status 或 nginx-module-vts
4. **分布式追踪**:传递 Trace ID 到后端
5. **告警配置**:对错误率和延迟设置告警
### 9.4 部署检查清单
- [ ] 配置文件语法验证 (`nginx -t`)
- [ ] 限流阈值合理性验证
- [ ] SSL 证书有效性检查
- [ ] 后端服务连通性测试
- [ ] 认证流程端到端测试
- [ ] 错误响应格式验证
- [ ] 性能基准测试
- [ ] 安全扫描端口、Header 等)