feat: Phase 1 - PocketBase 迁移文件、种子数据、部署脚本
- apps/pb_migrations/1710000001_init_collections.js: 9个集合完整定义 - apps/pb_migrations/1710000002_seed_data.js: 默认管理员、分类、标签、页面、示例文章 - scripts/install.sh: Linux 一键部署脚本 (systemd, Nginx, SSL, 防火墙, Fail2Ban) - scripts/install.ps1: Windows 一键部署脚本 (NSSM服务, 计划任务, Certbot) - scripts/start.sh: 服务启动脚本 - scripts/backup.sh: 数据备份脚本 - scripts/update.sh: 代码更新部署脚本 - docs/DEPLOY.md: 详细部署教程文档
This commit is contained in:
@@ -0,0 +1,592 @@
|
||||
<#>
|
||||
.SYNOPSIS
|
||||
云升数码 - Windows 一键部署脚本
|
||||
|
||||
.DESCRIPTION
|
||||
在 Windows Server / Windows 10/11 上部署云升数码展示页面
|
||||
包含 PocketBase 后端、Nginx 反向代理、SSL 证书配置
|
||||
|
||||
.NOTES
|
||||
需要管理员权限运行
|
||||
支持 Windows 10/11, Windows Server 2019/2022
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Domain = "",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Email = "",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$SkipNginx = $false,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$SkipSSL = $false
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
# 颜色输出函数
|
||||
function Write-Log {
|
||||
param([string]$Message, [string]$Level = "INFO")
|
||||
$colors = @{
|
||||
INFO = "Cyan"
|
||||
SUCCESS = "Green"
|
||||
WARN = "Yellow"
|
||||
ERROR = "Red"
|
||||
}
|
||||
$color = $colors[$Level]
|
||||
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" -ForegroundColor $color
|
||||
}
|
||||
|
||||
# 检查管理员权限
|
||||
function Check-Admin {
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
Write-Log "请以管理员身份运行 PowerShell" "ERROR"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# 检测架构
|
||||
function Get-Architecture {
|
||||
$arch = [Environment]::Is64BitOperatingSystem
|
||||
if ($arch) { return "amd64" } else { return "386" }
|
||||
}
|
||||
|
||||
# 下载文件
|
||||
function Download-File {
|
||||
param([string]$Url, [string]$OutputPath)
|
||||
Write-Log "下载: $Url"
|
||||
try {
|
||||
Invoke-WebRequest -Uri $Url -OutFile $OutputPath -UseBasicParsing
|
||||
Write-Log "下载完成: $OutputPath" "SUCCESS"
|
||||
} catch {
|
||||
Write-Log "下载失败: $_" "ERROR"
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
# 安装 PocketBase
|
||||
function Install-PocketBase {
|
||||
$version = "0.22.0"
|
||||
$arch = Get-Architecture
|
||||
$url = "https://github.com/pocketbase/pocketbase/releases/download/v${version}/pocketbase_${version}_windows_${arch}.zip"
|
||||
$installDir = "C:\pocketbase"
|
||||
$dataDir = "$installDir\pb_data"
|
||||
$migrationsDir = "$installDir\pb_migrations"
|
||||
$publicDir = "$installDir\pb_public"
|
||||
|
||||
Write-Log "安装 PocketBase v$version ($arch)..."
|
||||
|
||||
# 创建目录
|
||||
New-Item -ItemType Directory -Force -Path $installDir, $dataDir, $migrationsDir, $publicDir | Out-Null
|
||||
|
||||
# 下载
|
||||
$zipPath = "$env:TEMP\pocketbase.zip"
|
||||
Download-File $url $zipPath
|
||||
|
||||
# 解压
|
||||
Write-Log "解压..."
|
||||
Expand-Archive -Path $zipPath -DestinationPath $installDir -Force
|
||||
Remove-Item $zipPath -Force
|
||||
|
||||
# 复制迁移文件
|
||||
$projectMigrations = "$PSScriptRoot\..\apps\pb_migrations"
|
||||
if (Test-Path $projectMigrations) {
|
||||
Copy-Item -Path "$projectMigrations\*" -Destination $migrationsDir -Recurse -Force
|
||||
Write-Log "迁移文件已复制" "SUCCESS"
|
||||
}
|
||||
|
||||
# 生成加密密钥
|
||||
$encryptionKey = [Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
|
||||
Write-Log "加密密钥: $encryptionKey" "WARN"
|
||||
Write-Log "请妥善保存加密密钥!" "WARN"
|
||||
|
||||
# 创建启动脚本
|
||||
$startScript = @"
|
||||
@echo off
|
||||
cd /d "$installDir"
|
||||
set PB_ENCRYPTION_KEY=$encryptionKey
|
||||
pocketbase.exe serve --http=127.0.0.1:8090 --dir="$dataDir" --publicDir="$publicDir" --migrationsDir="$migrationsDir"
|
||||
"@
|
||||
Set-Content -Path "$installDir\start.bat" -Value $startScript -Encoding UTF8
|
||||
|
||||
# 创建系统服务
|
||||
Write-Log "创建 Windows 服务..."
|
||||
$serviceName = "PocketBase"
|
||||
$serviceDisplayName = "云升数码 PocketBase 服务"
|
||||
$serviceDescription = "PocketBase 后端服务 for 云升数码"
|
||||
|
||||
# 使用 NSSM (Non-Sucking Service Manager) 创建服务
|
||||
# 这里使用 sc.exe 创建简单服务
|
||||
$servicePath = "C:\Windows\System32\cmd.exe"
|
||||
$serviceArgs = "/c `"$installDir\start.bat`""
|
||||
|
||||
# 检查是否已安装 NSSM
|
||||
$nssmPath = "C:\pocketbase\nssm.exe"
|
||||
if (-not (Test-Path $nssmPath)) {
|
||||
Write-Log "下载 NSSM..."
|
||||
$nssmUrl = "https://github.com/nssm/nssm/releases/download/v2.24/nssm-2.24.zip"
|
||||
$nssmZip = "$env:TEMP\nssm.zip"
|
||||
Download-File $nssmUrl $nssmZip
|
||||
Expand-Archive -Path $nssmZip -DestinationPath "$env:TEMP\nssm" -Force
|
||||
Copy-Item "$env:TEMP\nssm\win64\nssm.exe" -Destination $nssmPath -Force
|
||||
Remove-Item $nssmZip -Force
|
||||
Remove-Item "$env:TEMP\nssm" -Recurse -Force
|
||||
}
|
||||
|
||||
# 安装服务
|
||||
& $nssmPath install $serviceName $servicePath $serviceArgs
|
||||
& $nssmPath set $serviceName DisplayName $serviceDisplayName
|
||||
& $nssmPath set $serviceName Description $serviceDescription
|
||||
& $nssmPath set $serviceName AppDirectory $installDir
|
||||
& $nssmPath set $serviceName AppEnvironmentExtra "PB_ENCRYPTION_KEY=$encryptionKey"
|
||||
& $nssmPath set $serviceName Start SERVICE_AUTO_START
|
||||
& $nssmPath set $serviceName AppStdout "$installDir\logs\stdout.log"
|
||||
& $nssmPath set $serviceName AppStderr "$installDir\logs\stderr.log"
|
||||
& $nssmPath set $serviceName AppRotateFiles 1
|
||||
& $nssmPath set $serviceName AppRotateBytes 10485760
|
||||
|
||||
New-Item -ItemType Directory -Force -Path "$installDir\logs" | Out-Null
|
||||
|
||||
Write-Log "PocketBase 服务创建完成" "SUCCESS"
|
||||
|
||||
return @{
|
||||
InstallDir = $installDir
|
||||
DataDir = $dataDir
|
||||
PublicDir = $publicDir
|
||||
EncryptionKey = $encryptionKey
|
||||
}
|
||||
}
|
||||
|
||||
# 安装 Nginx
|
||||
function Install-Nginx {
|
||||
param([string]$Domain)
|
||||
|
||||
if ($SkipNginx) {
|
||||
Write-Log "跳过 Nginx 安装" "WARN"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Log "安装 Nginx..."
|
||||
|
||||
$nginxVersion = "1.25.3"
|
||||
$url = "https://nginx.org/download/nginx-$nginxVersion.zip"
|
||||
$installDir = "C:\nginx"
|
||||
$zipPath = "$env:TEMP\nginx.zip"
|
||||
|
||||
Download-File $url $zipPath
|
||||
Expand-Archive -Path $zipPath -DestinationPath $installDir -Force
|
||||
Remove-Item $zipPath -Force
|
||||
|
||||
# 找到解压后的实际目录
|
||||
$extractedDir = Get-ChildItem "$installDir" -Directory | Select-Object -First 1
|
||||
if ($extractedDir.FullName -ne $installDir) {
|
||||
Move-Item -Path "$extractedDir\*" -Destination $installDir -Force
|
||||
Remove-Item $extractedDir.FullName -Recurse -Force
|
||||
}
|
||||
|
||||
# 配置 Nginx
|
||||
$nginxConf = @"
|
||||
# 云升数码 - Nginx 配置
|
||||
worker_processes auto;
|
||||
error_log logs/error.log warn;
|
||||
pid logs/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use iocp;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
|
||||
'\$status \$body_bytes_sent "\$http_referer" '
|
||||
'"\$http_user_agent" "\$http_x_forwarded_for"';
|
||||
|
||||
access_log logs/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 100M;
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
|
||||
|
||||
# HTTP 重定向到 HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name $Domain www.$Domain;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root C:\nginx\acme;
|
||||
try_files \$uri =404;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://\$host\$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS 主站点
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name $Domain www.$Domain;
|
||||
|
||||
# SSL 证书路径 (Certbot 会自动配置)
|
||||
# ssl_certificate C:/Certbot/live/$Domain/fullchain.pem;
|
||||
# ssl_certificate_key C:/Certbot/live/$Domain/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# 安全头
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
root $env:USERPROFILE\yunsheng-digital\apps\web\dist;
|
||||
index index.html;
|
||||
|
||||
# 静态文件缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|webp|avif|mp4|webm|ogg|mp3|wav|pdf)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
try_files \$uri =404;
|
||||
}
|
||||
|
||||
# SPA 路由
|
||||
location / {
|
||||
try_files \$uri \$uri/ /index.html;
|
||||
}
|
||||
|
||||
# API 代理
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8090;
|
||||
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_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
client_max_body_size 100M;
|
||||
}
|
||||
|
||||
# WebSocket
|
||||
location /api/realtime {
|
||||
proxy_pass http://127.0.0.1:8090;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host \$host;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# Admin UI
|
||||
location /_/ {
|
||||
proxy_pass http://127.0.0.1:8090;
|
||||
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;
|
||||
}
|
||||
|
||||
# 禁止隐藏文件
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
Set-Content -Path "$installDir\conf\nginx.conf" -Value $nginxConf -Encoding UTF8
|
||||
|
||||
# 创建 ACME 目录
|
||||
New-Item -ItemType Directory -Force -Path "C:\nginx\acme" | Out-Null
|
||||
|
||||
# 测试配置
|
||||
& "$installDir\nginx.exe" -t
|
||||
Write-Log "Nginx 配置测试通过" "SUCCESS"
|
||||
|
||||
# 创建服务
|
||||
$serviceName = "nginx"
|
||||
$nssmPath = "C:\pocketbase\nssm.exe"
|
||||
& $nssmPath install $serviceName "$installDir\nginx.exe" ""
|
||||
& $nssmPath set $serviceName DisplayName "Nginx Web Server"
|
||||
& $nssmPath set $serviceName Description "Nginx 反向代理 for 云升数码"
|
||||
& $nssmPath set $serviceName AppDirectory $installDir
|
||||
& $nssmPath set $serviceName Start SERVICE_AUTO_START
|
||||
|
||||
Write-Log "Nginx 安装完成" "SUCCESS"
|
||||
}
|
||||
|
||||
# 安装 Certbot (Windows)
|
||||
function Install-Certbot {
|
||||
param([string]$Domain, [string]$Email)
|
||||
|
||||
if ($SkipSSL) {
|
||||
Write-Log "跳过 SSL 证书申请" "WARN"
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $Domain -or -not $Email) {
|
||||
Write-Log "域名或邮箱为空,跳过 SSL 证书申请" "WARN"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Log "安装 Certbot..."
|
||||
|
||||
# 使用 Chocolatey 安装
|
||||
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
|
||||
Write-Log "安装 Chocolatey..."
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
||||
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
||||
}
|
||||
|
||||
choco install certbot -y --no-progress
|
||||
|
||||
# 申请证书
|
||||
Write-Log "申请 SSL 证书..."
|
||||
certbot certonly --standalone -d $Domain -d "www.$Domain" `
|
||||
--non-interactive --agree-tos --email $Email `
|
||||
--preferred-challenges http
|
||||
|
||||
Write-Log "SSL 证书申请完成" "SUCCESS"
|
||||
}
|
||||
|
||||
# 创建维护脚本
|
||||
function Create-MaintenanceScripts {
|
||||
$scriptsDir = "C:\pocketbase\scripts"
|
||||
New-Item -ItemType Directory -Force -Path $scriptsDir | Out-Null
|
||||
|
||||
# 备份脚本
|
||||
$backupScript = @"
|
||||
@echo off
|
||||
set BACKUP_DIR=C:\backup\yunsheng-digital
|
||||
set DATE=%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2%
|
||||
set DATE=%DATE: =0%
|
||||
mkdir "%BACKUP_DIR%" 2>nul
|
||||
|
||||
echo [INFO] 开始备份...
|
||||
|
||||
REM 备份 PocketBase 数据
|
||||
C:\pocketbase\pocketbase.exe dump --dir=C:\pocketbase\pb_data --output="%BACKUP_DIR%\pocketbase_%DATE%.zip"
|
||||
|
||||
REM 备份 Nginx 配置
|
||||
copy C:\nginx\conf\nginx.conf "%BACKUP_DIR%\nginx_%DATE%.conf"
|
||||
|
||||
REM 清理 30 天前的备份
|
||||
forfiles /p "%BACKUP_DIR%" /s /m *.* /d -30 /c "cmd /c del @path"
|
||||
|
||||
echo [SUCCESS] 备份完成
|
||||
"@
|
||||
Set-Content -Path "$scriptsDir\backup.bat" -Value $backupScript -Encoding UTF8
|
||||
|
||||
# 更新脚本
|
||||
$updateScript = @"
|
||||
@echo off
|
||||
cd /d "%USERPROFILE%\yunsheng-digital"
|
||||
echo [INFO] 拉取最新代码...
|
||||
git pull origin master
|
||||
|
||||
echo [INFO] 安装依赖...
|
||||
cd apps\web
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
echo [INFO] 构建前端...
|
||||
pnpm build
|
||||
|
||||
echo [INFO] 部署构建产物...
|
||||
xcopy /E /Y /I dist\* C:\pocketbase\pb_public\
|
||||
|
||||
echo [INFO] 重启服务...
|
||||
net stop nginx
|
||||
net stop PocketBase
|
||||
timeout /t 3
|
||||
net start PocketBase
|
||||
timeout /t 3
|
||||
net start nginx
|
||||
|
||||
echo [SUCCESS] 更新完成
|
||||
"@
|
||||
Set-Content -Path "$scriptsDir\update.bat" -Value $updateScript -Encoding UTF8
|
||||
|
||||
# 状态脚本
|
||||
$statusScript = @"
|
||||
@echo off
|
||||
echo === 云升数码 服务状态 ===
|
||||
echo.
|
||||
echo --- PocketBase ---
|
||||
sc query PocketBase
|
||||
echo.
|
||||
echo --- Nginx ---
|
||||
sc query nginx
|
||||
echo.
|
||||
echo --- 磁盘使用 ---
|
||||
wmic logicaldisk get size,freespace,caption
|
||||
echo.
|
||||
echo --- 网络连接 ---
|
||||
netstat -an | findstr "80 443 8090"
|
||||
"@
|
||||
Set-Content -Path "$scriptsDir\status.bat" -Value $statusScript -Encoding UTF8
|
||||
|
||||
Write-Log "维护脚本创建完成" "SUCCESS"
|
||||
}
|
||||
|
||||
# 配置防火墙
|
||||
function Configure-Firewall {
|
||||
Write-Log "配置 Windows 防火墙..."
|
||||
|
||||
# 允许 HTTP/HTTPS
|
||||
New-NetFirewallRule -DisplayName "云升数码 HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow -ErrorAction SilentlyContinue
|
||||
New-NetFirewallRule -DisplayName "云升数码 HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow -ErrorAction SilentlyContinue
|
||||
New-NetFirewallRule -DisplayName "云升数码 PocketBase" -Direction Inbound -Protocol TCP -LocalPort 8090 -Action Allow -Profile Private -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Log "防火墙配置完成" "SUCCESS"
|
||||
}
|
||||
|
||||
# 创建计划任务
|
||||
function Create-ScheduledTasks {
|
||||
Write-Log "创建计划任务..."
|
||||
|
||||
# 每天备份
|
||||
$action = New-ScheduledTaskAction -Execute "C:\pocketbase\scripts\backup.bat"
|
||||
$trigger = New-ScheduledTaskTrigger -Daily -At 3am
|
||||
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -DontStopOnIdleEnd
|
||||
Register-ScheduledTask -TaskName "云升数码-每日备份" -Action $action -Trigger $trigger -Settings $settings -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# 每周清理日志
|
||||
$action2 = New-ScheduledTaskAction -Execute "wevtutil.exe" -Argument "cl System /bu:C:\backup\system_logs\system_%date%.evtx"
|
||||
$trigger2 = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 4am
|
||||
Register-ScheduledTask -TaskName "云升数码-周日志清理" -Action $action2 -Trigger $trigger2 -Settings $settings -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Log "计划任务创建完成" "SUCCESS"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
function Main {
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host " 云升数码 - Windows 一键部署脚本 v1.0" -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Check-Admin
|
||||
|
||||
# 获取参数
|
||||
if (-not $Domain) {
|
||||
$Domain = Read-Host "请输入域名 (例: yunsheng.digital)"
|
||||
}
|
||||
|
||||
if (-not $Email) {
|
||||
$Email = Read-Host "请输入邮箱 (用于 SSL 证书)"
|
||||
}
|
||||
|
||||
Write-Log "开始部署..."
|
||||
Write-Log "域名: $Domain"
|
||||
Write-Log "邮箱: $Email"
|
||||
|
||||
# 克隆/更新代码
|
||||
$projectDir = "$env:USERPROFILE\yunsheng-digital"
|
||||
if (Test-Path $projectDir) {
|
||||
Write-Log "更新现有代码..."
|
||||
cd $projectDir
|
||||
git pull origin master
|
||||
} else {
|
||||
Write-Log "克隆仓库..."
|
||||
git clone https://git.grxiao.cn/yuns/plerr-open.git $projectDir
|
||||
}
|
||||
|
||||
# 安装 Node.js (如果需要)
|
||||
if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
|
||||
Write-Log "安装 Node.js..."
|
||||
choco install nodejs-lts -y --no-progress
|
||||
refreshenv
|
||||
}
|
||||
|
||||
# 安装 pnpm
|
||||
if (-not (Get-Command pnpm -ErrorAction SilentlyContinue)) {
|
||||
Write-Log "安装 pnpm..."
|
||||
npm install -g pnpm
|
||||
}
|
||||
|
||||
# 构建前端
|
||||
Write-Log "构建前端..."
|
||||
cd "$projectDir\apps\web"
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build
|
||||
|
||||
# 复制构建产物到 PocketBase public 目录
|
||||
$pbPublic = "C:\pocketbase\pb_public"
|
||||
New-Item -ItemType Directory -Force -Path $pbPublic | Out-Null
|
||||
Copy-Item -Path "dist\*" -Destination $pbPublic -Recurse -Force
|
||||
Write-Log "前端构建产物已部署" "SUCCESS"
|
||||
|
||||
# 安装后端服务
|
||||
$pbInfo = Install-PocketBase
|
||||
|
||||
# 安装 Nginx
|
||||
Install-Nginx -Domain $Domain
|
||||
|
||||
# 配置防火墙
|
||||
Configure-Firewall
|
||||
|
||||
# 创建维护脚本
|
||||
Create-MaintenanceScripts
|
||||
|
||||
# 创建计划任务
|
||||
Create-ScheduledTasks
|
||||
|
||||
# SSL 证书
|
||||
Install-Certbot -Domain $Domain -Email $Email
|
||||
|
||||
# 启动服务
|
||||
Write-Log "启动服务..."
|
||||
net start PocketBase
|
||||
Start-Sleep -Seconds 3
|
||||
net start nginx
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host " 部署完成!" -ForegroundColor Green
|
||||
Write-Host "==========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "📋 重要信息:" -ForegroundColor Cyan
|
||||
Write-Host " - 网站地址: https://$Domain"
|
||||
Write-Host " - 后台管理: https://$Domain/_/"
|
||||
Write-Host " - 管理员账号: admin@yunsheng.digital"
|
||||
Write-Host " - 管理员密码: YunSheng@2024!Admin"
|
||||
Write-Host " - PocketBase 目录: C:\pocketbase"
|
||||
Write-Host " - 前端构建目录: C:\pocketbase\pb_public"
|
||||
Write-Host ""
|
||||
Write-Host "🔐 安全提醒:" -ForegroundColor Yellow
|
||||
Write-Host " 1. 请立即登录后台修改默认管理员密码"
|
||||
Write-Host " 2. 加密密钥已保存在服务配置中"
|
||||
Write-Host " 3. 建议配置 RDP 限制、启用 BitLocker"
|
||||
Write-Host ""
|
||||
Write-Host "🛠️ 常用命令:" -ForegroundColor Cyan
|
||||
Write-Host " - 查看状态: C:\pocketbase\scripts\status.bat"
|
||||
Write-Host " - 备份数据: C:\pocketbase\scripts\backup.bat"
|
||||
Write-Host " - 更新代码: C:\pocketbase\scripts\update.bat"
|
||||
Write-Host " - 查看日志: C:\pocketbase\logs\"
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Main
|
||||
Reference in New Issue
Block a user