18 KiB
18 KiB
反向代理配置
**本文档引用的文件** - [src/server.ts](file://src/server.ts) - [src/index.ts](file://src/index.ts) - [src/websocket.ts](file://src/websocket.ts) - [src/class/websockethandler.ts](file://src/class/websockethandler.ts) - [src/signaling.ts](file://src/signaling.ts) - [src/服务端接口与WebSocket消息类型.md](file://src/服务端接口与WebSocket消息类型.md) - [package.json](file://package.json) - [run.bat](file://run.bat) - [client/public/onebyone/README.md](file://client/public/onebyone/README.md) - [client/public/onebyone/code-structure.md](file://client/public/onebyone/code-structure.md)目录
简介
本指南针对视频流服务器项目提供完整的反向代理配置方案。该项目是一个基于 WebRTC 和 WebSocket 的视频通话应用,支持 HTTP 轮询和 WebSocket 两种信令协议,以及公共模式和私有模式两种通信方式。
项目采用 Node.js + Express 构建,支持 HTTPS 和 WebSocket 升级,具备完整的 WebRTC 信令交换能力。反向代理配置对于部署此类实时通信应用至关重要,需要特别关注 WebSocket 升级、长连接保持、头部转发和压缩配置等方面。
项目架构概览
graph TB
subgraph "客户端应用"
A[WebRTC 客户端]
B[浏览器应用]
end
subgraph "反向代理层"
C[Nginx/Apache]
D[负载均衡器]
end
subgraph "应用服务器"
E[Express 服务器]
F[WebSocket 服务器]
G[HTTP 轮询服务器]
end
subgraph "数据库/存储"
H[会话存储]
I[文件上传存储]
end
A --> C
B --> C
C --> E
C --> F
C --> G
E --> H
E --> I
F --> H
G --> H
图表来源
核心组件分析
项目包含以下关键组件:
- Express 服务器:处理 HTTP 请求、静态文件服务和 API 路由
- WebSocket 服务器:处理实时信令消息和 WebRTC 信令交换
- HTTP 轮询服务器:提供 HTTP 轮询模式的信令服务
- 会话管理系统:管理用户会话和连接状态
- 静态资源服务:提供前端应用和媒体文件
章节来源
WebRTC 场景特殊考虑
WebSocket 升级要求
WebRTC 应用对 WebSocket 升级有严格要求:
sequenceDiagram
participant Client as 客户端
participant Proxy as 反向代理
participant Server as 应用服务器
participant WS as WebSocket服务器
Client->>Proxy : HTTP Upgrade 请求
Proxy->>Proxy : 检查 Upgrade 头部
Proxy->>Server : 转发升级请求
Server->>WS : 创建 WebSocket 连接
WS->>Server : 连接建立成功
Server->>Proxy : 返回 101 Switching Protocols
Proxy->>Client : 完成协议升级
Client->>WS : 开始实时通信
图表来源
长连接保持机制
项目实现了心跳检测机制来维持长连接:
- 心跳间隔:30秒发送一次 ping 消息
- 超时检测:60秒无活动自动断开连接
- 活动跟踪:记录最后活动时间戳
通信模式支持
项目支持两种通信模式:
- 公共模式:所有客户端都可以直接通信
- 私有模式:1对多房间通信(1个host + 多个participants)
章节来源
Nginx 反向代理配置
基础配置模板
以下提供完整的 Nginx 配置示例:
# HTTP 到 HTTPS 重定向
server {
listen 80;
server_name your-domain.com www.your-domain.com;
# 强制 HTTPS 重定向
return 301 https://$server_name$request_uri;
}
# HTTPS 服务器配置
server {
listen 443 ssl http2;
server_name your-domain.com www.your-domain.com;
# SSL 证书配置
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 安全头部
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 静态资源缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# WebSocket 升级配置
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# WebSocket 超时设置
proxy_read_timeout 86400;
proxy_send_timeout 86400;
# 代理缓冲区
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
# API 端点配置
location /api/ {
proxy_pass http://localhost:8080/api/;
proxy_http_version 1.1;
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 /uploads/ {
alias /path/to/your/uploads/;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
负载均衡配置
# 负载均衡配置
upstream websocket_backend {
server 127.0.0.1:8080 weight=3 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 weight=2 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8082 backup;
}
upstream http_backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# WebSocket 负载均衡
location / {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# WebSocket 超时设置
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
# HTTP 负载均衡
location /api/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
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 ~* \.(css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable, stale-while-revalidate=31536000";
add_header Vary Accept-Encoding;
gzip_static on;
}
location ~* \.(png|jpg|jpeg|gif|ico|svg|webp)$ {
expires 30d;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
}
location ~* \.(woff|woff2|ttf|otf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 压缩配置
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript application/xml+rss image/svg+xml;
gzip_comp_level 6;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";
章节来源
Apache 反向代理配置
基础 Apache 配置
# 启用必要的模块
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule headers_module modules/mod_headers.so
<VirtualHost *:80>
ServerName your-domain.com
ServerAlias www.your-domain.com
# HTTP 到 HTTPS 重定向
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=310,L]
</VirtualHost>
<VirtualHost *:443>
ServerName your-domain.com
ServerAlias www.your-domain.com
# SSL 配置
SSLEngine on
SSLCertificateFile /path/to/your/certificate.crt
SSLCertificateKeyFile /path/to/your/private.key
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384
# 安全头部
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
# 反向代理配置
ProxyPreserveHost On
ProxyRequests Off
# WebSocket 升级
ProxyPass /ws/ ws://127.0.0.1:8080/
ProxyPassReverse /ws/ ws://127.0.0.1:8080/
# HTTP 轮询
ProxyPass /api/ http://127.0.0.1:8080/api/
ProxyPassReverse /api/ http://127.0.0.1:8080/api/
# 静态资源
ProxyPass /uploads/ http://127.0.0.1:8080/uploads/
ProxyPassReverse /uploads/ http://127.0.0.1:8080/uploads/
# 代理超时设置
ProxyTimeout 86400
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
mod_proxy_wstunnel 模块启用
确保启用 WebSocket 支持:
# 启用 WebSocket 隧道
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
# WebSocket 升级配置
<LocationMatch "^/">
ProxyPass ws://127.0.0.1:8080/
ProxyPassReverse ws://127.0.0.1:8080/
ProxySet match=Upgrade
ProxySet force-proxy-request-1.0 1
</LocationMatch>
虚拟主机配置
# 主虚拟主机配置
<VirtualHost *:443>
ServerName your-domain.com
DocumentRoot /var/www/html
# SSL 证书
SSLEngine on
SSLCertificateFile /etc/ssl/certs/your-domain.crt
SSLCertificateKeyFile /etc/ssl/private/your-domain.key
# 安全配置
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCompression off
SSLSessionTickets off
# 头部安全
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# 反向代理设置
ProxyPreserveHost On
ProxyRequests Off
# WebSocket 支持
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:8080/$1" [P,L]
# 一般 HTTP 请求
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
章节来源
性能优化建议
连接池配置
# 连接池优化
upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
keepalive 32;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
超时设置优化
# 超时配置优化
proxy_connect_timeout 10s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# WebSocket 超时
location / {
proxy_read_timeout 86400;
proxy_send_timeout 86400;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
错误处理配置
# 错误处理
error_page 502 503 504 /50x.html;
location = /50x.html {
internal;
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 缓存策略
location ~* \.(css|js|png|jpg|jpeg|gif|ico)$ {
add_header Cache-Control "public, immutable, stale-while-revalidate=31536000";
expires 1y;
}
章节来源
安全配置
CORS 设置
项目默认启用了 CORS 支持,但建议在生产环境中进行更严格的配置:
# CORS 配置
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With, X-Real-IP" always;
add_header Access-Control-Max-Age 86400 always;
# 预检请求处理
location OPTIONS {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With, X-Real-IP";
add_header Access-Control-Max-Age 86400;
return 204;
}
HSTS 配置
# HSTS 配置
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=()" always;
安全头部
# 安全头部配置
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Feature-Policy "geolocation=(), microphone=()"
Header always set Expect-CT "enforce, max-age=86400"
SSL/TLS 优化
# SSL 优化配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_dhparam /path/to/dhparam.pem;
ssl_ecdh_curve prime256v1;
章节来源
故障排除指南
WebSocket 连接问题
常见 WebSocket 连接问题及解决方案:
-
升级失败
- 检查
Upgrade和Connection头部是否正确传递 - 确认代理服务器版本支持 WebSocket 升级
- 检查
-
连接超时
- 增加
proxy_read_timeout和proxy_send_timeout - 检查防火墙设置允许 WebSocket 端口
- 增加
-
心跳检测失败
- 确认客户端和服务端的心跳配置一致
- 检查网络中间设备是否丢弃长连接
性能问题诊断
# 启用详细日志
error_log /var/log/nginx/error.log debug;
access_log /var/log/nginx/access.log combined;
# 监控连接状态
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
负载均衡问题
# 健康检查配置
upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8082 backup;
}
# 会话粘性(可选)
ip_hash;
章节来源
总结
本指南提供了针对视频流服务器项目的完整反向代理配置方案。关键要点包括:
- WebSocket 升级:必须正确配置 Upgrade 头部和 Connection 字段
- 长连接保持:合理设置超时参数和心跳检测
- 负载均衡:支持多实例部署和故障转移
- 性能优化:连接池、缓存策略和压缩配置
- 安全配置:CORS、HSTS 和安全头部设置
部署时建议:
- 先在测试环境验证配置
- 逐步增加流量监控
- 定期检查日志和性能指标
- 制定回滚和应急响应计划
通过正确的反向代理配置,可以确保 WebRTC 应用的稳定运行和良好用户体验。