Featured image of post Nginx 反向代理实战:WebSocket、HTTPS、静态站点与 MinIO 网关

Nginx 反向代理实战:WebSocket、HTTPS、静态站点与 MinIO 网关

Nginx 容器化部署、反向代理 + WebSocket 配置、HTTPS 证书、自动跳转、性能优化(gzip/buffer)、MinIO 网关示例

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_upgradeWebSocket 反代必须,否则 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 反代必须UpgradeConnection: 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 头动态返回 upgradeclose。如果忘了配 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

六、踩坑清单

  1. WebSocket 426/断开——忘了 map $connection_upgrade,或者 location 段漏 Upgrade
  2. 上传 413——client_max_body_size 默认 1M,调成业务需要的最大值
  3. Header 400——client_header_buffer_size 默认 1k,Cookie 巨长的请求会超
  4. 代理慢/卡顿——proxy_buffer_size 太小,后端响应被频繁写入临时文件
  5. gzip 没生效——gzip_types 漏了类型,或者 gzip_min_length 设太大(小文件不压缩)
  6. 配置改完没生效——nginx -s reload 失败(语法错),需要 docker logs nginx 查原因
  7. HTTPS 跳不过来——return 301 写在 location / 里而不是 server 顶层
  8. 跨域 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/

下一步

使用 Hugo 构建
主题 StackJimmy 设计