Files
k8s-docs/k8s/xiongxiao.me/docs/08-nginx-proxy-modes.md
2025-11-26 17:02:14 +08:00

271 lines
6.4 KiB
Markdown
Raw Permalink 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.
---
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/)