Nginx 几乎是后端服务的标配——静态站点、反向代理、负载均衡、WebSocket 网关、HTTPS 终结,每个开发者都用过。但真正"线上跑得稳"需要把几个坑都踩过:WebSocket 反代不写 Upgrade 头、gzip 配错类型反向变慢、HTTPS 证书路径不对、buffer 不够大上传大文件 502。这篇文章把零散在多个笔记里的 Nginx 实战经验整理成一篇。
阅读对象:需要在容器化环境部署 Nginx 做反向代理/静态服务/WebSocket 网关的同学
覆盖范围:Nginx 容器化部署、反向代理基础、HTTPS 终结、WebSocket 反代、gzip/buffer 优化、MinIO 反代示例
一、容器化部署
1.1 最简启动
1
| docker run -d --restart=always --name nginx -p 80:80 nginx:stable
|
推荐用 nginx:stable 而不是 nginx:latest:stable 标签跟小版本号(1.22、1.24 等),latest 偶尔会跳大版本。
1.2 配置持久化
生产环境必须挂载配置和静态文件:
1
2
3
4
5
6
7
| docker run -d --name nginx --restart=always -p 80:80 \
-v /home/nginx/logs:/var/log/nginx \
-v /home/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /home/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /home/nginx/dist:/usr/share/nginx/html \
-v /etc/localtime:/etc/localtime:ro \
nginx:stable
|
或者 host 网络模式(适合内网用 80 端口):
1
2
3
4
5
6
| docker run -d --name nginx --restart=always --net=host \
-v /home/docker/nginx/log:/var/log/nginx \
-v /home/docker/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /home/docker/nginx/conf/stream:/etc/nginx/stream \
-v /home/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx:stable
|
1.3 Alpine 版(更小)
1
2
3
4
5
6
7
| docker run -d --name nginx --restart=always -p 80:80 \
-v /home/nginx/logs:/var/log/nginx \
-v /home/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /home/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /home/nginx/dist:/usr/share/nginx/html \
-v /etc/localtime:/etc/localtime:ro \
nginx:1.25-alpine
|
Alpine 版镜像只有 40MB 左右,但没有预装 shell 和常用工具(wget/curl/vi),排查问题时进容器会比较痛苦。
二、生产级 nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| user root;
worker_processes 1; # 推荐设为 CPU 核心数
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
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"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
autoindex on;
# ===== gzip 优化 =====
gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 1k;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]\.";
gzip_http_version 1.1;
gzip_vary on;
# ===== 客户端 body/header buffer(上传大文件必须调)=====
client_body_buffer_size 1024k;
client_max_body_size 2048m;
client_header_buffer_size 128k;
large_client_header_buffers 4 128k;
# ===== 代理 buffer =====
proxy_buffer_size 256k;
proxy_buffering on;
proxy_buffers 64 128k;
proxy_busy_buffers_size 512k;
# ===== FastCGI buffer =====
fastcgi_buffers 6 512k;
fastcgi_buffer_size 512k;
fastcgi_busy_buffers_size 512k;
fastcgi_temp_file_write_size 512k;
fastcgi_intercept_errors on;
# ===== WebSocket 关键配置(http 段顶层)=====
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/nginx/conf.d/*.conf;
}
# ===== TCP/UDP 4 层转发(可选)=====
stream {
log_format proxy '[$time_local] $protocol status:$status, bytes client:$bytes_sent/$bytes_received $session_time, '
'client: $remote_addr, upstream:"$upstream_addr", '
'bytes upstream:$upstream_bytes_sent $upstream_bytes_received $upstream_connect_time';
include /etc/nginx/stream/*.conf;
}
|
关键参数解读:
client_max_body_size 2048m:上传文件超过默认 1M 会 413,调大client_header_buffer_size 128k:HTTP header 单行超过 1k 会 400,调大proxy_buffer_size / proxy_buffers:调大避免后端响应一次性写入临时文件map $http_upgrade $connection_upgrade:WebSocket 反代必须,否则 426 错误
三、HTTPS + 自动跳转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| server {
listen 443 ssl;
server_name example.com;
ssl_certificate /www/server/panel/vhost/cert/example.com/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/example.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
charset utf-8;
location / {
proxy_pass http://localhost:9000;
proxy_redirect http:// https://;
proxy_set_header Host $http_host;
}
}
server {
listen 80;
server_name example.com;
# HTTP 自动跳 HTTPS
if ($scheme = http) {
return 301 https://$host:443$request_uri;
}
}
|
证书路径:生产环境用 certbot / acme.sh 自动签发 Let’s Encrypt 证书,定时续期。
四、反向代理 + WebSocket
WebSocket 反代必须带 Upgrade 和 Connection: upgrade 头:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| location ^~ /ws/ {
proxy_pass http://{{BACKEND_HOST}}/ws/;
proxy_http_version 1.1;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_set_header Host $http_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;
# WebSocket 关键
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
|
$connection_upgrade 由前面 map 指令定义,根据客户端 Upgrade 头动态返回 upgrade 或 close。如果忘了配 map,WebSocket 连接会被 nginx 关闭。
五、MinIO 网关示例
MinIO 经常用 Nginx 做反代,重点是 WebSocket(控制台实时通知)+ 大文件上传:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| location ^~ /minio/ {
proxy_pass http://localhost:9090/;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_set_header Host $http_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_http_version 1.1;
# WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
|
MINIO_BROWSER_REDIRECT_URL 必须配成 Nginx 转发后的地址,否则 MinIO 控制台会 404:
1
2
| environment:
- MINIO_BROWSER_REDIRECT_URL=http://{{NGINX_HOST}}/minio
|
六、踩坑清单
- WebSocket 426/断开——忘了 map
$connection_upgrade,或者 location 段漏 Upgrade 头 - 上传 413——
client_max_body_size 默认 1M,调成业务需要的最大值 - Header 400——
client_header_buffer_size 默认 1k,Cookie 巨长的请求会超 - 代理慢/卡顿——
proxy_buffer_size 太小,后端响应被频繁写入临时文件 - gzip 没生效——
gzip_types 漏了类型,或者 gzip_min_length 设太大(小文件不压缩) - 配置改完没生效——
nginx -s reload 失败(语法错),需要 docker logs nginx 查原因 - HTTPS 跳不过来——
return 301 写在 location / 里而不是 server 顶层 - 跨域 CORS——后端没设 CORS 头,Nginx 要么
add_header 加,要么在 if 段处理 OPTIONS 预检
七、2024+ 视角补充
本文写于 2022-04,2024-2026 期间 Nginx 关键演进:
- Nginx 1.25+(2023-06 起):HTTP/3 (QUIC) 实验性支持;gRPC 代理原生;动态 SSL 证书加载(不用 reload)
- Nginx 1.27 LTS(2024-11):HTTP/3 默认开;OpenSSL 3.x 兼容;更精细的限流(limit_req_dry_run 等)
- Nginx Ingress 1.10+(K8s):Gateway API 全面支持(vs 老 Ingress API);IPV6 双栈
- Nginx Unit 1.32+:应用服务器模式(跑 Go / Node / Python / Java / PHP / Perl)——Web 服务器 + 应用服务器一体
- OpenResty 1.25+:Lua 生态成熟,WAF / API Gateway 场景仍是首选
- 替代品(2024+ 视角):
- Caddy 2.x:自动 HTTPS / Caddyfile 简洁 / Go 跨平台——新项目首选
- Traefik 3.x:K8s 原生 / 自动服务发现 / Let’s Encrypt 自动化
- HAProxy 3.0+:四层代理性能优于 Nginx,数据库 / TCP 代理首选
- Envoy 1.32+:Service Mesh 标配(Istio / Consul / Linkerd)
实战建议(2025-2026 视角):
- 传统 Web 反代 / 静态站 → Nginx 1.27 LTS 仍是生产首选
- K8s 入口 → Nginx Ingress 1.10+ / Traefik 3.x / Gateway API
- 数据库 / TCP 代理 → HAProxy 3.0+(性能与功能强于 Nginx stream)
- 新项目想要最少配置 → Caddy 2.x(HTTPS 配置从 30 行降到 3 行)
八、参考资料
- Nginx 官方文档:http://nginx.org/en/docs/
- Nginx 反向代理 WebSocket:https://nginx.org/en/docs/http/websocket.html
- Mozilla SSL 配置生成器:https://ssl-config.mozilla.org/
下一步