本文档说明如何配置 Nginx 来托管 H5 应用,并代理 API 和 MQTT WebSocket 请求。
server {
listen 80;
server_name your-domain.com; # 替换为你的域名
# H5 应用静态资源
location / {
root /var/www/html/web-releases/latest; # 替换为你的 WEB_DEPLOY_PATH
index index.html;
try_files $uri $uri/ /index.html; # SPA 路由支持
# 缓存控制
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML 文件不缓存
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
}
# API 代理配置
location /api/ {
# 转发到后端 API 服务
proxy_pass http://localhost:6001/; # 替换为你的后端 API 地址
# 或者使用 upstream 配置负载均衡
# proxy_pass http://api_backend/;
# 代理头设置
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 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲设置(可选,根据需求调整)
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
如果你有多个后端服务器,可以使用 upstream 配置负载均衡:
upstream api_backend {
# 负载均衡策略
least_conn; # 或 ip_hash
# 后端服务器列表
server localhost:6001 weight=1 max_fails=3 fail_timeout=30s;
# server localhost:6002 weight=1 max_fails=3 fail_timeout=30s;
# 健康检查(需要 nginx plus 或第三方模块)
# check interval=3000 rise=2 fall=3 timeout=1000;
}
location /api/ {
proxy_pass http://api_backend/;
# ... 其他配置
}
MQTT over WebSocket 需要特殊的 nginx 配置来支持 WebSocket 协议升级和长连接。
# MQTT WebSocket 代理
location /mqtt {
# 转发到 MQTT broker 的 WebSocket 端口
proxy_pass http://localhost:8083; # 替换为你的 MQTT broker 地址
# ===== WebSocket 升级必需配置 =====
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;
# ===== 长连接超时设置(非常重要!)=====
# MQTT 是长连接协议,需要设置较长的超时时间
proxy_connect_timeout 60s; # 初始连接超时
proxy_send_timeout 3600s; # 发送超时(1小时)
proxy_read_timeout 3600s; # 读取超时(1小时)
# ===== 缓冲设置 =====
# 关闭缓冲,实现实时通信
proxy_buffering off;
# ===== 可选:日志记录 =====
access_log /var/log/nginx/mqtt_access.log;
error_log /var/log/nginx/mqtt_error.log;
}
WebSocket 升级:
proxy_http_version 1.1 - WebSocket 需要 HTTP/1.1Upgrade 和 Connection 头 - 实现协议升级超时配置:
proxy_read_timeout 和 proxy_send_timeout 建议设置为 3600s(1小时)或更长缓冲控制:
proxy_buffering off - 关闭缓冲以实现实时通信server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL 证书配置
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# SSL 协议和加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# SSL 会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS(可选,强制 HTTPS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# ... 其他配置(静态资源、API、MQTT)
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
当使用 HTTPS 时,MQTT WebSocket 也会自动使用 wss:// 协议:
// 前端代码自动适配
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const mqttUrl = `${protocol}//${window.location.host}/mqtt`;
server {
listen 80;
server_name dev.your-domain.com;
# 访问日志
access_log /var/log/nginx/zsis_access.log;
error_log /var/log/nginx/zsis_error.log;
# H5 应用静态资源
location / {
root /var/www/html/web-releases/latest;
index index.html;
try_files $uri $uri/ /index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
# API 代理
location /api/ {
proxy_pass http://localhost:6001/;
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 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# MQTT WebSocket 代理
location /mqtt {
proxy_pass http://localhost:8083;
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_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
proxy_buffering off;
}
}
# HTTPS 服务器
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL 证书
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
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 "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 访问日志
access_log /var/log/nginx/zsis_access.log;
error_log /var/log/nginx/zsis_error.log;
# H5 应用静态资源
location / {
root /var/www/html/web-releases/latest;
index index.html;
try_files $uri $uri/ /index.html;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
# API 代理
location /api/ {
proxy_pass http://localhost:6001/;
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 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# MQTT WebSocket 代理(wss://)
location /mqtt {
proxy_pass http://localhost:8083;
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;
proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
proxy_buffering off;
}
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
症状:前端无法连接到 MQTT broker
检查步骤:
# 1. 检查 MQTT broker 是否运行
netstat -tlnp | grep 8083
# 2. 测试 WebSocket 连接(使用 websocat 工具)
websocat ws://localhost/mqtt
# 3. 查看 nginx 错误日志
tail -f /var/log/nginx/mqtt_error.log
# 4. 检查 nginx 配置
nginx -t
常见原因:
proxy_http_version 1.1 未设置Upgrade 和 Connection 头配置错误症状:API 请求返回 502 错误
检查步骤:
# 1. 检查后端 API 服务是否运行
netstat -tlnp | grep 6001
# 2. 测试后端 API
curl http://localhost:6001/health
# 3. 查看 nginx 错误日志
tail -f /var/log/nginx/error.log
常见原因:
proxy_pass 地址配置错误症状:页面加载失败,静态资源找不到
检查步骤:
# 1. 检查文件路径是否正确
ls -la /var/www/html/web-releases/latest/
# 2. 检查文件权限
ls -la /var/www/html/web-releases/
# 3. 检查符号链接
readlink /var/www/html/web-releases/latest
常见原因:
如果你的后端 API 和前端不在同一域名下,需要配置 CORS:
# 方式 1:在 nginx 配置 CORS
location /api/ {
# ... 其他配置
# CORS 头
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header Access-Control-Allow-Headers 'Authorization, Content-Type' always;
add_header Access-Control-Max-Age 86400 always;
# OPTIONS 预检请求处理
if ($request_method = 'OPTIONS') {
return 204;
}
}
# 使用 websocat(推荐)
websocat ws://your-domain.com/mqtt
# 使用 wscat
wscat -c ws://your-domain.com/mqtt
# 浏览器控制台测试
const ws = new WebSocket('ws://your-domain.com/mqtt');
ws.onopen = () => console.log('Connected');
ws.onerror = (e) => console.error('Error:', e);
# 测试 API 端点
curl -v http://your-domain.com/api/health
# 测试带认证的 API
curl -v -H "Authorization: Bearer token" http://your-domain.com/api/data
# 实时查看 nginx 访问日志
tail -f /var/log/nginx/access.log
# 实时查看 nginx 错误日志
tail -f /var/log/nginx/error.log
# 实时查看 MQTT 日志
tail -f /var/log/nginx/mqtt_access.log
sudo nano /etc/nginx/sites-available/zsis
# 创建符号链接
sudo ln -s /etc/nginx/sites-available/zsis /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重载配置
sudo nginx -s reload
访问以下 URL 验证:
http://your-domain.com/http://your-domain.com/api/health需要在 GitHub 仓库中配置以下 secrets:
| Secret 名称 | 说明 | 示例 |
|---|---|---|
WEB_DEPLOY_PATH |
Web 部署目标路径 | /var/www/html/web-releases |
DEPLOY_KEY |
SSH 私钥 | -----BEGIN RSA PRIVATE KEY-----... |
DEPLOY_HOST |
服务器地址 | your-server.com |
DEPLOY_USER |
SSH 用户名 | deploy |