Nginx-Web部署代理配置.md 14 KB

Nginx Web 部署代理配置指南

本文档说明如何配置 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 代理

HTTP API 转发

# 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 配置负载均衡:

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 协议升级和长连接。

# 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
    • UpgradeConnection 头 - 实现协议升级
  2. 超时配置

    • proxy_read_timeoutproxy_send_timeout 建议设置为 3600s(1小时)或更长
    • MQTT 客户端通常使用心跳机制保持连接,如果心跳间隔是 30 秒,超时应该至少是心跳间隔的 2-3 倍
  3. 缓冲控制

    • proxy_buffering off - 关闭缓冲以实现实时通信

HTTPS 配置

SSL/TLS 配置

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:// 协议:

// 前端代码自动适配
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const mqttUrl = `${protocol}//${window.location.host}/mqtt`;

完整配置示例

HTTP 版本(开发/测试环境)

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 版本(生产环境)

# 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

检查步骤

# 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 未设置
  • UpgradeConnection 头配置错误
  • 超时时间设置过短
  • MQTT broker 未启动或端口错误

2. API 请求 502 Bad Gateway

症状: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 地址配置错误
  • 防火墙阻止连接

3. 静态资源 404

症状:页面加载失败,静态资源找不到

检查步骤

# 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:

# 方式 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 连接

# 使用 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

# 测试 API 端点
curl -v http://your-domain.com/api/health

# 测试带认证的 API
curl -v -H "Authorization: Bearer token" http://your-domain.com/api/data

3. 查看实时日志

# 实时查看 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. 创建配置文件

sudo nano /etc/nginx/sites-available/zsis

2. 启用配置

# 创建符号链接
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 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 代理配置
  • 添加故障排查指南