This commit is contained in:
2025-11-26 17:02:14 +08:00
parent 2418891634
commit ba1f52996f
33 changed files with 415 additions and 1216 deletions

View File

@@ -0,0 +1,270 @@
---
title: Nginx 代理模式选择指南
description: 详细说明 Nginx Stream 模式和 HTTP 反向代理模式的区别、适用场景及常见问题解决方案
tags:
- nginx
- proxy
- traefik
- stream
- reverse-proxy
- mime-type
createdAt: 2025-11-26
---
# Nginx 代理模式选择指南
## 问题现象
当使用 Stream 模式转发时,浏览器会报错:
```
Refused to execute script from 'https://npm.xiongxiao.me/-/static/Home.854787d3346e44ccc262.js'
because its MIME type ('') is not executable, and strict MIME type checking is enabled.
```
## 原因分析
Nginx Stream 模式工作在 **TCP/UDP 层**OSI 第 4 层),只做字节流转发,**不解析 HTTP 协议**,因此:
- ❌ 不会处理 HTTP 头信息(包括 Content-Type
- ❌ 不会设置 X-Forwarded-* 头
- ❌ 不支持 WebSocket 协议升级
- ❌ MIME 类型信息丢失
- ✅ 转发效率更高(无需解析 HTTP
## 两种模式对比
### 1. Stream 模式 (nginx-stream-proxy.conf)
**工作层级**: OSI 第 4 层 (TCP/UDP)
**特点**:
- ✅ 性能最优CPU 占用低
- ✅ 适合纯 TCP/UDP 转发
- ❌ 不处理 HTTP 头
- ❌ 不支持基于 HTTP 的负载均衡
- ❌ 无法查看 HTTP 请求细节
**适用场景**:
- MySQL/PostgreSQL 数据库转发
- Redis/MongoDB 等数据库代理
- SSH/SFTP 端口转发
- 纯 TCP 协议转发
- 不需要 HTTP 头信息的场景
**配置示例**:
```nginx
# /etc/nginx/nginx.conf 的 stream {} 块中
stream {
upstream traefik_http {
server 127.0.0.1:30080;
}
server {
listen 80;
proxy_pass traefik_http;
}
}
```
### 2. HTTP 反向代理模式 (nginx-traefik-proxy.conf) ⭐ 推荐
**工作层级**: OSI 第 7 层 (HTTP/HTTPS)
**特点**:
- ✅ 完整的 HTTP 协议支持
- ✅ 保留所有 HTTP 头信息(包括 Content-Type
- ✅ 支持 WebSocket
- ✅ 可以设置自定义头
- ✅ 支持 SSL/TLS 终止
- ✅ 可以记录详细访问日志
- ⚠️ 性能略低于 Stream 模式(差异很小)
**适用场景**:
- Web 应用反向代理 ⭐
- API 网关
- 静态资源服务
- WebSocket 应用
- 需要处理 HTTP 头的场景
**配置示例**:
```nginx
# /etc/nginx/conf.d/traefik-proxy.conf
server {
listen 80;
server_name _;
# 关键:保留 HTTP 头信息
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;
location / {
proxy_pass http://127.0.0.1:30080;
}
}
```
## 解决方案
### 当前问题MIME Type 错误
**原因**: 使用了 Stream 模式,导致 Content-Type 头丢失
**解决方法**: 切换到 HTTP 反向代理模式
#### 步骤 1: 停止当前 Nginx 配置
```bash
# 如果使用了 stream 模式配置
sudo rm /etc/nginx/nginx.conf.d/stream/traefik.conf
# 或删除 nginx.conf 中的 stream {} 块
```
#### 步骤 2: 应用 HTTP 反向代理配置
```bash
# 复制配置文件
sudo cp nginx-traefik-proxy.conf /etc/nginx/conf.d/traefik-proxy.conf
# 创建 SSL 证书目录和占位证书(如果需要)
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/placeholder.key \
-out /etc/nginx/ssl/placeholder.crt \
-subj "/CN=placeholder"
# 测试配置
sudo nginx -t
# 重载 Nginx
sudo nginx -s reload
```
#### 步骤 3: 验证
```bash
# 检查 HTTP 响应头
curl -I http://npm.xiongxiao.me
# 应该能看到正确的 Content-Type
# Content-Type: application/javascript; charset=utf-8
```
## 性能对比
### Stream 模式
- **延迟**: ~0.1ms
- **吞吐量**: 接近网卡上限
- **CPU 占用**: 极低
- **内存占用**: 极低
### HTTP 反向代理模式
- **延迟**: ~0.5-1ms
- **吞吐量**: 95%+ 网卡性能
- **CPU 占用**: 低
- **内存占用**: 低
**结论**: 对于 Web 应用性能差异可以忽略不计HTTP 反向代理模式是更好的选择。
## 常见问题
### Q1: 为什么 Traefik 后端应用会收到错误的 IP
**原因**: 没有设置 `X-Real-IP``X-Forwarded-For`
**解决**:
```nginx
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
```
### Q2: WebSocket 连接失败
**原因**: 没有配置协议升级
**解决**:
```nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```
### Q3: HTTPS 证书错误
**原因**:
- HTTP 反向代理模式需要占位证书
- 或者 Traefik 后端使用自签名证书
**解决**:
```nginx
# 创建占位证书
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/placeholder.key \
-out /etc/nginx/ssl/placeholder.crt \
-subj "/CN=placeholder"
# 信任后端自签名证书
proxy_ssl_verify off;
```
### Q4: 什么时候用 Stream 模式?
**答**: 仅在以下场景使用 Stream 模式:
- 转发非 HTTP 协议MySQL、Redis、SSH 等)
- 需要最极致的性能(每毫秒都很重要的场景)
- 纯 TCP/UDP 负载均衡
**对于所有 Web 应用,请使用 HTTP 反向代理模式。**
## 推荐配置
### 生产环境标准配置
```nginx
# /etc/nginx/conf.d/traefik-proxy.conf
server {
listen 80;
listen [::]:80;
server_name _;
# 保留客户端信息
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 X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 缓冲设置(根据实际调整)
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
location / {
proxy_pass http://127.0.0.1:30080;
proxy_redirect off;
}
# 日志
access_log /var/log/nginx/traefik-proxy.access.log;
error_log /var/log/nginx/traefik-proxy.error.log warn;
}
```
## 参考资源
- [Nginx Stream Module 文档](http://nginx.org/en/docs/stream/ngx_stream_core_module.html)
- [Nginx HTTP Proxy Module 文档](http://nginx.org/en/docs/http/ngx_http_proxy_module.html)
- [Traefik 官方文档](https://doc.traefik.io/traefik/)