update
This commit is contained in:
270
k8s/xiongxiao.me/docs/08-nginx-proxy-modes.md
Normal file
270
k8s/xiongxiao.me/docs/08-nginx-proxy-modes.md
Normal 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/)
|
||||
Reference in New Issue
Block a user