Merge pull request #16 from qinfendebingshuo/copilot/ym-backend-20260307-001-check-server-env

feat(backend): production WebSocket URL, Nginx reverse proxy, pm2 boot persistence
This commit is contained in:
冰朔 2026-03-07 19:38:24 +08:00 committed by GitHub
commit 1f4224e4d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 89 additions and 25 deletions

View File

@ -209,22 +209,32 @@ jobs:
exit 0
fi
# 部署 backend 服务
# 部署 backend 服务Express API端口 3000
if [ -f '${{ secrets.DEPLOY_PATH }}/backend/server.js' ]; then
echo '📦 安装 backend 依赖...'
cd '${{ secrets.DEPLOY_PATH }}/backend'
npm install --production || echo '⚠️ backend npm install 失败'
npm install --production 2>/dev/null || echo '⚠️ backend npm install 失败'
echo '🔄 重启 backend 服务...'
pm2 restart guanghulab-backend 2>/dev/null || \
pm2 start server.js --name guanghulab-backend 2>/dev/null || \
echo '⚠️ backend pm2 启动失败'
fi
# 部署 status-board WebSocket 服务(端口 8080
if [ -f '${{ secrets.DEPLOY_PATH }}/status-board/mock-ws-server.js' ]; then
echo '🔄 重启 WebSocket 服务...'
cd '${{ secrets.DEPLOY_PATH }}/status-board'
npm install --production 2>/dev/null || true
pm2 restart guanghulab-ws 2>/dev/null || \
pm2 start mock-ws-server.js --name guanghulab-ws 2>/dev/null || \
echo '⚠️ WebSocket pm2 启动失败'
fi
# 部署 src HLI 中间层
if [ -f '${{ secrets.DEPLOY_PATH }}/src/index.js' ]; then
echo '📦 安装 src 依赖...'
cd '${{ secrets.DEPLOY_PATH }}'
npm install --production || echo '⚠️ src npm install 失败'
npm install --production 2>/dev/null || echo '⚠️ src npm install 失败'
echo '🔄 重启 HLI 服务...'
pm2 restart guanghulab 2>/dev/null || \
pm2 start src/index.js --name guanghulab 2>/dev/null || \
@ -232,6 +242,10 @@ jobs:
fi
pm2 save || echo '⚠️ pm2 save 失败,重启后进程可能不会自动启动'
# 设置开机自启(仅首次需要,后续无操作)
pm2 startup 2>/dev/null | grep -o 'sudo.*' | bash 2>/dev/null || true
echo '✅ 后端服务部署完成'
"
@ -247,8 +261,9 @@ jobs:
exit 0
fi
NGINX_CHANGED=false
# 一次性迁移:更新 root 路径(从旧的 status-board 子目录改为站点根目录)
# 迁移完成后此检查自动无操作
if grep -q 'root.*guanghulab/status-board' /etc/nginx/sites-available/default 2>/dev/null || \
grep -q 'root.*guanghulab/status-board' /etc/nginx/conf.d/*.conf 2>/dev/null; then
echo '🔄 更新 Nginx root 路径...'
@ -256,11 +271,64 @@ jobs:
/etc/nginx/sites-available/default 2>/dev/null || true
sudo sed -i 's|root.*guanghulab/status-board[^;]*|root ${{ secrets.DEPLOY_PATH }}|g' \
/etc/nginx/conf.d/*.conf 2>/dev/null || true
sudo nginx -t && sudo systemctl reload nginx
echo '✅ Nginx 配置已更新'
NGINX_CHANGED=true
echo '✅ Nginx root 路径已更新'
else
echo '✅ Nginx root 路径正确,无需修改'
fi
# 配置 API + WebSocket 反向代理
if ! grep -rq 'location /api/' /etc/nginx/sites-available/ /etc/nginx/conf.d/ /etc/nginx/snippets/ 2>/dev/null; then
echo '🔄 添加 API + WebSocket 反向代理...'
sudo mkdir -p /etc/nginx/snippets
# 注意:\$ 在本地 shell 中转义为 $,远程 shell 的单引号保护不再展开,
# 最终写入文件的 Nginx 变量为 $host、$http_upgrade 等
printf '%s\n' \
'# guanghulab 反向代理(由 CD 工作流自动生成)' \
'' \
'# API 反向代理 → Express 后端端口 3000' \
'location /api/ {' \
' proxy_pass http://127.0.0.1:3000/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;' \
' proxy_cache_bypass \$http_upgrade;' \
'}' \
'' \
'# WebSocket 反向代理 → 看板实时推送端口 8080' \
'location /ws {' \
' proxy_pass http://127.0.0.1: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_read_timeout 86400;' \
'}' \
| sudo tee /etc/nginx/snippets/guanghulab-proxy.conf > /dev/null
# 在 server 块中加入 include 指令(仅搜索 sites-available 避免 symlink 重复)
NGINX_MAIN=\$(grep -rl 'server_name' /etc/nginx/sites-available/ 2>/dev/null | head -1)
if [ -z \"\$NGINX_MAIN\" ]; then
NGINX_MAIN='/etc/nginx/sites-available/default'
fi
if [ -f \"\$NGINX_MAIN\" ] && ! grep -q 'guanghulab-proxy' \"\$NGINX_MAIN\" 2>/dev/null; then
sudo sed -i '/server_name/a\\ include /etc/nginx/snippets/guanghulab-proxy.conf;' \"\$NGINX_MAIN\" 2>/dev/null && \
NGINX_CHANGED=true && echo '✅ 反向代理已自动配置' || \
echo '⚠️ 自动配置失败,请手动在 Nginx server 块中加入: include /etc/nginx/snippets/guanghulab-proxy.conf;'
fi
else
echo '✅ API 反向代理已存在,无需修改'
fi
# 如果有变更,验证并重新加载 Nginx
if [ \"\$NGINX_CHANGED\" = true ]; then
sudo nginx -t && sudo systemctl reload nginx && echo '✅ Nginx 配置已重新加载' || \
echo '⚠️ Nginx 配置验证失败,请手动检查'
fi
"
- name: 🔍 验证部署

View File

@ -177,13 +177,7 @@
</footer>
</div>
<!-- 环节2新增三个核心脚本 -->
<script src="api-config.js"></script>
<script src="api.js"></script>
<script src="render.js"></script>
<!-- 原有的交互脚本 -->
<script src="script.js"></script>
<!-- 环节2新增三个核心脚本 -->
<!-- 核心脚本 -->
<script src="api-config.js"></script>
<script src="api.js"></script>
<script src="render.js"></script>
@ -191,23 +185,27 @@
<!-- 原有的交互脚本 -->
<script src="script.js"></script>
<!-- ===== 新加的初始化脚本 ===== -->
<!-- ===== WebSocket 实时推送初始化 ===== -->
<script>
// ===== WebSocket 实时推送初始化 =====
(function() {
const wsUrl = 'ws://localhost:8080';
const wsClient = new WebSocketClient(wsUrl, {
onMessage: (data) => {
// 自动检测 WebSocket 地址:生产环境走 Nginx 反向代理,本地开发直连 8080
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
var wsUrl = (location.hostname === 'localhost' || location.hostname === '127.0.0.1')
? 'ws://localhost:8080'
: wsProtocol + '//' + location.host + '/ws';
var wsClient = new WebSocketClient(wsUrl, {
onMessage: function(data) {
if (data.type === 'dashboard_update' && data.data) {
if (data.data.system) renderSystemStatus(data.data.system);
if (data.data.developers) renderDevelopers(data.data.developers);
if (data.data.broadcasts) renderBroadcasts(data.data.broadcasts);
}
},
onStatusChange: (status) => {
const el = document.getElementById('conn-status');
onStatusChange: function(status) {
var el = document.getElementById('conn-status');
if (!el) return;
let text = '', className = '';
var text = '', className = '';
switch(status) {
case 'connected':
text = '🔵 实时连接 (WebSocket)';
@ -229,14 +227,12 @@
if (typeof refreshDashboard === 'function') refreshDashboard();
break;
}
el.innerHTML = `<span class="${className}"></span> ${text}`;
el.innerHTML = '<span class="' + className + '"></span> ' + text;
}
});
wsClient.connect();
window.addEventListener('beforeunload', () => wsClient.disconnect());
window.addEventListener('beforeunload', function() { wsClient.disconnect(); });
})();
</script>
</body>
</html>
</body>
</html>