# Nginx Web 部署代理配置指南 本文档说明如何配置 Nginx 来托管 H5 应用,并代理 API 和 MQTT WebSocket 请求。 ## 目录 - [基本配置](#基本配置) - [MQTT WebSocket 代理](#mqtt-websocket-代理) - [API 代理](#api-代理) - [HTTPS 配置](#https-配置) - [完整配置示例](#完整配置示例) - [故障排查](#故障排查) ## 基本配置 ### 静态资源托管 ```nginx 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 代理 ### HTTP API 转发 ```nginx # 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 配置负载均衡: ```nginx 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 WebSocket 代理 ### 关键配置说明 MQTT over WebSocket 需要特殊的 nginx 配置来支持 WebSocket 协议升级和长连接。 ```nginx # 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; } ``` ### 配置说明 1. **WebSocket 升级**: - `proxy_http_version 1.1` - WebSocket 需要 HTTP/1.1 - `Upgrade` 和 `Connection` 头 - 实现协议升级 2. **超时配置**: - `proxy_read_timeout` 和 `proxy_send_timeout` 建议设置为 3600s(1小时)或更长 - MQTT 客户端通常使用心跳机制保持连接,如果心跳间隔是 30 秒,超时应该至少是心跳间隔的 2-3 倍 3. **缓冲控制**: - `proxy_buffering off` - 关闭缓冲以实现实时通信 ## HTTPS 配置 ### SSL/TLS 配置 ```nginx 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; } ``` ### WebSocket over SSL (wss://) 当使用 HTTPS 时,MQTT WebSocket 也会自动使用 wss:// 协议: ```javascript // 前端代码自动适配 const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const mqttUrl = `${protocol}//${window.location.host}/mqtt`; ``` ## 完整配置示例 ### HTTP 版本(开发/测试环境) ```nginx 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 版本(生产环境) ```nginx # 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; } ``` ## 故障排查 ### 常见问题 #### 1. MQTT WebSocket 连接失败 **症状**:前端无法连接到 MQTT broker **检查步骤**: ```bash # 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` 头配置错误 - 超时时间设置过短 - MQTT broker 未启动或端口错误 #### 2. API 请求 502 Bad Gateway **症状**:API 请求返回 502 错误 **检查步骤**: ```bash # 1. 检查后端 API 服务是否运行 netstat -tlnp | grep 6001 # 2. 测试后端 API curl http://localhost:6001/health # 3. 查看 nginx 错误日志 tail -f /var/log/nginx/error.log ``` **常见原因**: - 后端服务未启动 - `proxy_pass` 地址配置错误 - 防火墙阻止连接 #### 3. 静态资源 404 **症状**:页面加载失败,静态资源找不到 **检查步骤**: ```bash # 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 ``` **常见原因**: - 部署路径配置错误 - 文件权限问题(nginx 用户无法读取) - 符号链接指向错误 #### 4. CORS 错误 如果你的后端 API 和前端不在同一域名下,需要配置 CORS: ```nginx # 方式 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; } } ``` ### 测试工具 #### 1. 测试 WebSocket 连接 ```bash # 使用 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); ``` #### 2. 测试 API ```bash # 测试 API 端点 curl -v http://your-domain.com/api/health # 测试带认证的 API curl -v -H "Authorization: Bearer token" http://your-domain.com/api/data ``` #### 3. 查看实时日志 ```bash # 实时查看 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 ``` ## 配置应用 ### 1. 创建配置文件 ```bash sudo nano /etc/nginx/sites-available/zsis ``` ### 2. 启用配置 ```bash # 创建符号链接 sudo ln -s /etc/nginx/sites-available/zsis /etc/nginx/sites-enabled/ # 测试配置 sudo nginx -t # 重载配置 sudo nginx -s reload ``` ### 3. 验证部署 访问以下 URL 验证: - 静态资源:`http://your-domain.com/` - API:`http://your-domain.com/api/health` - MQTT:使用浏览器开发者工具查看 WebSocket 连接 ## 相关文档 - [GitHub Actions Workflow](.github/workflows/build-web-deployment.yml) - [部署脚本](.build/deploy-to-server.js) - [Nginx 官方文档](https://nginx.org/en/docs/) - [MQTT over WebSocket](https://www.emqx.io/docs/en/latest/advanced/mqtt-over-websocket.html) ## GitHub Secrets 配置 需要在 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` | ## 部署流程 1. **配置 GitHub Secrets**:在仓库设置中添加上述 secrets 2. **配置 Nginx**:使用本文档中的配置模板 3. **触发部署**: - 推送代码到 master 分支 - 或手动触发 workflow 4. **验证部署**:访问域名检查应用是否正常运行 ## 注意事项 1. **超时配置**:MQTT WebSocket 需要较长的超时时间(至少 1 小时) 2. **缓冲设置**:关闭 MQTT 的缓冲以实现实时通信 3. **安全性**:生产环境建议使用 HTTPS(wss://) 4. **监控**:配置日志记录和监控告警 5. **备份**:定期备份 nginx 配置文件 ## 更新日志 - 2025-01-03:创建初始版本 - 包含 HTTP 和 HTTPS 配置示例 - 添加 MQTT WebSocket 代理配置 - 添加故障排查指南