feat: 添加 1Panel 静态站点部署配置和线上部署指南

新增文件:
- deploy/docker-compose.prod.yml - 配置线上数据库和 Redis 连接
- deploy/nginx-1panel.conf - 1Panel Nginx 完整配置参考
- deploy/deploy-1panel.sh - 适配 1Panel 的自动部署脚本
- deploy/.env.production - 线上环境变量模板
- docs/DEPLOY_ONLINE_GUIDE.md - 详细部署说明文档

线上环境信息:
- 域名: uniservice-mobile.hnxinyouhe.com
- MySQL: 1Panel-mysql-XyxS
- Redis: 1Panel-redis-pxdb
- Docker 网络: 1panel-network

特性:
- 前后端分离部署
- 前端静态文件由 1Panel Nginx 直接托管
- 后端运行在 Docker 容器中
- 1Panel 面板管理 Nginx 配置和 SSL 证书

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-02-27 18:21:22 +08:00
parent c1e54d9457
commit 7bdd0850f5
4 changed files with 589 additions and 9 deletions
+170
View File
@@ -0,0 +1,170 @@
#!/bin/bash
# X-Server Mobile 1Panel 静态站点部署脚本
# 使用方法: ./deploy-1panel.sh [server]
set -e
# ============================================
# 配置
# ============================================
SERVER=${1:-"your-server-ip"}
DEPLOY_USER="root"
FRONTEND_BUILD_DIR="./frontend/dist"
BACKEND_SOURCE_DIR="./backend"
# 1Panel 网站目录
REMOTE_ROOT="/www/sites/uniservice-mobile.hnxinyouhe.com/index"
# 后端部署目录
REMOTE_BACKEND_DIR="/opt/x-server-mobile/backend"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# ============================================
# 检查环境
# ============================================
check_env() {
log_info "检查部署环境..."
if ! command -v rsync &> /dev/null; then
log_error "rsync 未安装,请先安装: apt-get install rsync"
exit 1
fi
if [ ! -d "$FRONTEND_BUILD_DIR" ]; then
log_error "前端构建目录不存在: $FRONTEND_BUILD_DIR"
log_info "请先运行: cd frontend && npm install && npm run build"
exit 1
fi
log_info "✓ 环境检查通过"
}
# ============================================
# 构建前端
# ============================================
build_frontend() {
log_info "构建前端..."
cd frontend
npm run build
cd ..
log_info "✓ 前端构建完成"
}
# ============================================
# 部署前端(上传静态文件)
# ============================================
deploy_frontend() {
log_info "部署前端到 1Panel 静态站点..."
rsync -avz --delete \
--exclude='*.map' \
${FRONTEND_BUILD_DIR}/ \
${DEPLOY_USER}@${SERVER}:${REMOTE_ROOT}/
log_info "✓ 前端部署完成"
}
# ============================================
# 部署后端
# ============================================
deploy_backend() {
log_info "部署后端..."
# 创建后端目录(如果不存在)
ssh ${DEPLOY_USER}@${SERVER} "mkdir -p ${REMOTE_BACKEND_DIR}"
rsync -avz \
--exclude='vendor' \
--exclude='runtime' \
--exclude='.git' \
${BACKEND_SOURCE_DIR}/ \
${DEPLOY_USER}@${SERVER}:${REMOTE_BACKEND_DIR}/
log_info "✓ 后端部署完成"
}
# ============================================
# 重启后端容器
# ============================================
restart_backend() {
log_info "重启后端容器..."
ssh ${DEPLOY_USER}@${SERVER} << 'EOF'
cd /opt/x-server-mobile
# 停止旧容器
docker-compose -f deploy/docker-compose.prod.yml down
# 启动新容器
docker-compose -f deploy/docker-compose.prod.yml up -d
# 查看容器状态
docker ps | grep x-server
echo "✓ 后端容器重启完成"
EOF
}
# ============================================
# 主流程
# ============================================
main() {
echo "=========================================="
echo " X-Server Mobile 1Panel 部署脚本"
echo "=========================================="
echo ""
echo "目标服务器: ${SERVER}"
echo ""
# 检查环境
check_env
# 询问是否构建前端
read -p "是否需要构建前端? (y/N): " build_frontend_choice
if [[ $build_frontend_choice =~ ^[Yy]$ ]]; then
build_frontend
fi
# 部署前端
deploy_frontend
# 询问是否部署后端
read -p "是否需要部署后端? (y/N): " deploy_backend_choice
if [[ $deploy_backend_choice =~ ^[Yy]$ ]]; then
deploy_backend
restart_backend
fi
echo ""
log_info "=========================================="
log_info "部署完成!"
log_info "=========================================="
echo ""
echo "访问地址: https://uniservice-mobile.hnxinyouhe.com"
echo ""
echo "后续步骤:"
echo "1. 在 1Panel 面板中找到网站配置"
echo "2. 将 deploy/nginx-1panel.conf 的内容添加到 Nginx 配置中"
echo "3. 重载 Nginx 配置"
echo ""
}
# 执行主流程
main "$@"
+7 -9
View File
@@ -1,5 +1,5 @@
# X-Server Mobile 生产环境 Docker Compose
# 使用方法: docker-compose -f docker-compose.prod.yml up -d
# 使用方法: docker-compose -f deploy/docker-compose.prod.yml up -d
services:
# PHP 后端服务
@@ -16,19 +16,17 @@ services:
- APP_ENV=production
- APP_DEBUG=false
# 数据库配置(使用 1Panel 的 MySQL)
# 注意:请替换为实际的容器名和密码
- DB_HOST=1Panel-mysql-409s
# 数据库配置(1Panel MySQL)
- DB_HOST=1Panel-mysql-XyxS
- DB_PORT=3306
- DB_DATABASE=xserver
- DB_USERNAME=xserver
- DB_PASSWORD=${DB_PASSWORD:-change_me_in_production}
- DB_PASSWORD=NsNBSQm4b2b7SzhR
# Redis 配置(使用 1Panel 的 Redis)
# 注意:请替换为实际的容器名和密码
- REDIS_HOST=1Panel-redis-xxxx
# Redis 配置(1Panel Redis)
- REDIS_HOST=1Panel-redis-pxdb
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD:-change_me_in_production}
- REDIS_PASSWORD=redis_FTzdM6
# 飞书配置(请替换为实际值)
- FEISHU_APP_ID=${FEISHU_APP_ID}
+150
View File
@@ -0,0 +1,150 @@
# uniservice-mobile.hnxinyouhe.com Nginx 配置
# 1Panel 静态站点配置
# 文件位置: 1Panel 网站设置 -> 配置文件
server {
listen 80;
listen 443 ssl;
server_name uniservice-mobile.hnxinyouhe.com;
index index.php index.html index.htm default.php default.htm default.html;
access_log /www/sites/uniservice-mobile.hnxinyouhe.com/log/access.log main;
error_log /www/sites/uniservice-mobile.hnxinyouhe.com/log/error.log;
# ============================================
# 安全配置
# ============================================
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {
return 404;
}
# Let's Encrypt ACME 挑战
location ^~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}
# 禁止访问敏感文件扩展
if ($uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$") {
return 403;
}
# ============================================
# SSL 证书配置
# ============================================
http2 on;
if ($scheme = http) {
return 301 https://$host$request_uri;
}
ssl_certificate /www/sites/uniservice-mobile.hnxinyouhe.com/ssl/fullchain.pem;
ssl_certificate_key /www/sites/uniservice-mobile.hnxinyouhe.com/ssl/privkey.pem;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA384:DHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
# HSTS 安全头
add_header Strict-Transport-Security "max-age=31536000" always;
proxy_set_header X-Forwarded-Proto https;
# ============================================
# 后端 API 反向代理
# ============================================
location /api/ {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
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_set_header Host $host;
# 超时配置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲配置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
}
# ============================================
# 飞书登录回调(必须在 API 之前匹配)
# ============================================
location /login {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
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_set_header Host $host;
}
location /login/callback {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
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_set_header Host $host;
}
location /login/qrcode {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
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_set_header Host $host;
}
# 飞书卡片回调
location /feishu/card/callback {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
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_set_header Host $host;
}
# ============================================
# 静态资源缓存
# ============================================
location ~* \.(js|css|png|jpg|jpeg|gif|webp|svg|ico|woff|woff2|ttf|eot)$ {
root /www/sites/uniservice-mobile.hnxinyouhe.com/index;
expires 7d;
add_header Cache-Control "public, immutable";
access_log off;
}
# ============================================
# 前端 SPA(所有其他请求)
# ============================================
root /www/sites/uniservice-mobile.hnxinyouhe.com/index;
location / {
try_files $uri $uri/ /index.html;
# SPA HTML 不缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# 404 页面
error_page 404 /404.html;
}