跳到主要内容
奇点CMS v0.4.70 · 官方网站 登录 / 注册 在线激活

奇点CMS Windows 部署与适配说明

powershell -ExecutionPolicy Bypass -File .\qdcms-ffmpeg-win.ps1 -DryRun

WindowsщГич╜▓шп┤цШО.md 文档版本 v0.4.70 16 KB 更新于 2026-10-14

奇点CMS Windows 部署与适配说明

适用于 Windows Server / 宝塔 Windows 面板 / IIS+PHP 等无 systemd 的环境。 Linux 部署见 docs/安装配置说明.md;Agent+ Go 服务的编译细节见 go-service/README.md 第六节。 本文由真实 Windows 服务器实测总结(站点 D:\wwwroot\qdcms + 宝塔 Windows + nginx + PHP 8.0)。


一、与 Linux 的形态差异

主题LinuxWindows
进程守护systemd 单元计划任务 + 启动器脚本(run-xdream-go.ps1,守护/崩溃自愈/心跳)
Agent+ Go 服务/opt/xdream-go/x-dream-go<站点>\go-service\x-dream-go.exe(必须在站点目录内,见坑 5)
开机自启systemctl enable计划任务 x-dream-go(SYSTEM / At system start up)
FFmpeg 探测which ffmpeg / [ -x ]ffmpeg.exe 候选路径 + cmd if exist 探测(qdcms-ffmpeg-win.ps1)
视频后台压缩nohup sh -c ... &生成 .bat 并用 start /B 分离执行
运行时状态journalddata\.go_service_heartbeat(心跳)/ data\.go_service.log(日志)/ .go_service.pid

二、随包的两个一键适配脚本(位于站点根目录)

脚本作用
qdcms-ffmpeg-win.ps1FFmpeg Windows 支持:改写 includes/fn-upload.php(检测 + 后台压缩)、admin/server-status.php、includes/SystemRequirements.php;并把 ffmpeg.exe/ffprobe.exe 复制到 C:\ffmpeg\bin(可用 -SkipFfmpegCopy 关闭)
qdcms-go-win.ps1Agent+ Go 服务 Windows 支持:检测项平台化 + 写启动器 + 生成 GO_API_KEY + 追加 nginx 拒绝规则;可选 -Build(自动编译)、-Start、-RegisterTask
qdcms-deploy.ps1多站点部署与批量巡检(见第八节):默认只预演,-Apply 写盘
qdcms-selfcheck.ps1部署后一键自检(签收自证,见第七节)
# 预览(不写任何文件)
powershell -ExecutionPolicy Bypass -File .\qdcms-ffmpeg-win.ps1 -DryRun
powershell -ExecutionPolicy Bypass -File .\qdcms-go-win.ps1     -DryRun

# 执行
powershell -ExecutionPolicy Bypass -File .\qdcms-ffmpeg-win.ps1
powershell -ExecutionPolicy Bypass -File .\qdcms-go-win.ps1 -Build -Start

# 管理员执行一次:注册开机自启
powershell -ExecutionPolicy Bypass -File .\go-service\register-task.ps1

两个脚本的共同保证:锚点未命中即跳过(绝不盲写)、改动前备份、php -n -l 失败自动回滚、可重复执行(幂等)。 备份命名:<文件>.bak-ffmpegwin-<时间戳> / <文件>.bak-gowin-<时间戳>(= 本轮开始前的原始文件), 补丁过程中的临时中间态 <...>.last 会在成功或收尾时自动清理。


三、八个必须知道的坑(均为实测踩过)

  1. **.ps1 必须 UTF-8 *带 BOM***:Windows PowerShell 5.1 会按系统 ANSI 代码页(中文系统为 GBK)解码无 BOM 的 UTF-8, 中文注释的尾字节会"吃掉"后面的引号或 #>,导致脚本语法错误甚至无法解析。包内脚本都已带 BOM; 自行修改时请在编辑器中选择 "UTF-8 with BOM"。
  2. 写 JSON 不要用 Set-Content -Encoding UTF8:PS 5.1 会写入 BOM,PHP json_decode 直接失败 (表现为检测页"无心跳")。正确写法: [System.IO.File]::WriteAllText($path, $json, (New-Object System.Text.UTF8Encoding($false)))。 检测代码对 BOM 已做容错,但写入端仍应保持无 BOM。
  3. 计划任务的 72 小时上限:任务计划默认 ExecutionTimeLimit=PT72H,满 3 天会停止任务并杀掉守护进程。 必须改为无限制(命令见第六节)。这是最容易漏、且三天后才爆的坑。
  4. SYSTEM 任务对非管理员不可见:非管理员会话下 schtasks /query、Get-ScheduledTask、 Get-CimInstance 的 CommandLine 会报 Access denied 或返回空 —— 那是权限限制,不代表任务没注册或没运行。 判断运行状态请看 data\.go_service_heartbeat 与 http://127.0.0.1:8080/health。
  5. open_basedir 限制:宝塔 Windows 默认把 PHP 文件操作限制在站点目录内,因此 Go 产物必须放在 <站点>\go-service\x-dream-go.exe 才会被"部署检测"识别;放到 C:\ 或其他目录只会显示"无法探测"。 FFmpeg 探测与压缩则通过子进程(shell_exec/exec)绕开该限制。
  6. 必须自行补 nginx 拒绝规则(另:若启用 IM 实时推送,还需 /im-stream 的 SSE 反代且 proxy_buffering off,见 docs/聊天即时通信说明.md 第六节):nginx 不读取 .htaccess。至少要封堵 /config/ /includes/ /data/ /docs/ /reports/、 可执行与备份后缀(.exe .go .ps1 .py .sh .bat .bak .last .md .dat .log ...)以及隐藏文件(保留 .well-known)。 nginx.conf.example 已内置这些规则,qdcms-go-win.ps1 也会自动追加;改完必须重载 nginx 才生效。 实测未配置时 /data/.pool_key、/data/number_pool_*.dat、/docs/*.md 均可被公网直接下载。
  7. 杀软误报:Windows Defender 可能把含 Deny from all 的 .htaccess 判为可疑并拦截读写。 纯 nginx 部署不依赖该文件;若影响工具运行可加单文件排除: Add-MpPreference -ExclusionPath '<站点>\.htaccess'。
  8. nginx 拒绝规则的"位置"与"重载方式"(两条都实测踩过):
  • **规则必须写在 PHP location 之前。否则形如 admin/xxx.php.bak-<时间戳> 的备份会先被 location ~ \.php(.*)$ 命中并交给 PHP 处理器执行(实测返回 302,等于给后台页面又开了一个入口)。 宝塔环境下把规则放到 nginx/conf/proxy/<站点>/*.conf(include 顺序:proxy/*.conf → php/80.conf → rewrite/*.conf), 或直接写在 vhost 中 PHP include 之前。nginx.conf.example 里规则已位于 PHP location 之前,请勿挪动顺序**。
  • nginx -s reload 在 Windows 上可能失败:报 OpenEvent("Global\ngx_reload_<pid>") failed (5: Access is denied), 管理员身份也一样(具名事件 ACL 的已知怪癖)。请改用宝塔面板的「重载/重启 nginx」按钮或 Restart-Service nginx; 改完务必用 qdcms-selfcheck.ps1 或手工探测确认规则真的生效(404)。

四、部署后验证清单

#检查期望
1curl.exe -s http://127.0.0.1:8080/health{"cache":true,"database":true,"status":"healthy"}
2后台 → 系统 → 部署检测 → Agent+ 组9 项无警告;FFmpeg 项显示实际 ffmpeg.exe 路径
3data\.go_service_heartbeatstate=running,pid 与 x-dream-go.exe 进程号一致
4curl.exe -I http://127.0.0.1/go-service/x-dream-go.exe404(产物不可下载)
5curl.exe -I http://127.0.0.1/data/.pool_key404(敏感文件不可下载)
6重启服务器后再查 1~3 项服务自动拉起(验证开机自启)

五、Agent+ Go 服务:编译与部署(Windows)

# ① Go 1.21+(可用官方 zip 解压到任意目录当便携工具链,无需写注册表)
# ② 编译
cd <站点>\go-service
$env:GOPROXY = 'https://goproxy.cn,direct'
go build -trimpath -ldflags "-s -w" -o x-dream-go.exe .

# ③ 共享密钥:在 config/generated.php 定义 define('GO_API_KEY', '<48位随机串>')
#    启动器会自动读取同名值,保证 PHP↔Go 两侧一致(qdcms-go-win.ps1 可自动生成)

# ④ 启动(守护 + 心跳)
powershell -ExecutionPolicy Bypass -File .\go-service\run-xdream-go.ps1

# ⑤ 开机自启(管理员执行一次)
powershell -ExecutionPolicy Bypass -File .\go-service\register-task.ps1

六、修正计划任务设置(管理员,消除 72 小时上限)

$t = Get-ScheduledTask -TaskName 'x-dream-go'
$t.Settings.ExecutionTimeLimit = 'PT0S'      # 无限制(守护进程必须常驻)
$t.Settings.RestartCount       = 3           # 失败后重试
$t.Settings.RestartInterval    = 'PT1M'
Set-ScheduledTask -InputObject $t
(Get-ScheduledTask -TaskName 'x-dream-go').Settings.ExecutionTimeLimit   # 应输出 PT0S

等价做法:Export-ScheduledTask -TaskName x-dream-go 导出 XML, 把 <ExecutionTimeLimit>PT72H</ExecutionTimeLimit> 改成 PT0S(若无该节点则在 <Settings> 内补一行), 再用 Register-ScheduledTask -TaskName x-dream-go -Xml $xml -Force 原样重注册(触发器/动作/身份保持不变)。


七、部署后一键自检(客户签收自证)

包内提供只读自检脚本 qdcms-selfcheck.ps1,覆盖上文第四节的验证清单并输出 PASS/WARN/FAIL 汇总(退出码 0/1,可用于自动化):

# 最简(自动探测站点、自动读取 data/.license_domain 作为 Host 头)
powershell -ExecutionPolicy Bypass -File .\qdcms-selfcheck.ps1

# 指定站点/域名/输出日志
powershell -ExecutionPolicy Bypass -File .\qdcms-selfcheck.ps1 -SiteRoot "D:\wwwroot\qdcms" `
           -BaseUrl "http://127.0.0.1" -HostHeader "your-domain.com" -LogPath .\selfcheck.txt
检查组内容
站点与版本站点根目录、CMS_VERSION、config/generated.php、install.lock、PHP CLI
环境与依赖复用后台「部署检测」注册表(site/server/agent 三组,列出所有非 OK 项与修复建议)
Agent+ 服务/health、守护心跳(state/pid/新鲜度)、x-dream-go.exe 进程、计划任务是否注册且无 72 小时上限
前台可用性首页 / 短视频 / 登录页 / 静态资源(403 会提示多为授权域名不匹配)
安全规则敏感路径必须 404:/data/、/config/、/includes/、/docs/、/go-service/、/install/、适配脚本,以及站点内实际存在的 *.bak-* 备份文件

自检脚本只读、不修改站点;唯一的落盘是临时 PHP 辅助文件(执行后删除)与 -LogPath 指定的日志。

已知语境差异:自检以 PHP CLI 运行「部署检测」注册表,因此「视频加载加速器」「Web 服务器」两项 会因缺少 HTTP_HOST / SERVER_SOFTWARE 而显示为 INFO(脚本会附提示);这两项请以后台「系统 → 部署检测」页的浏览器结果为准。


八、多站点部署 / 批量巡检(qdcms-deploy.ps1)

同一台服务器上批量部署与巡检多个 QDCMS 站点。

8.1 批量巡检(只读,默认模式)

# 扫描宝塔 nginx vhost 目录,逐个站点输出:目录 / CMS 版本 / 安装状态 / 数据库连通(users 数) / 自检结论
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Discover
# 也可用清单文件指定要巡检的站点
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Sites .\sites.json

自动跳过宝塔全局 include(0.*、proxy_site.conf 等)、相对 root 的默认站点,以及不含 config/config.php 的非 QDCMS 站点。

8.2 新建站点

# ① 复制包内 sites.example.json 为 sites.json 并填写
#    db_pass 留空 = 自动生成随机口令(执行报告里打印一次,请立即保存)
#    name 决定默认目录 <WebRoot>\<name> 与默认库名 cms_<name>
# ② 预演(不写盘)
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Mode Deploy -Sites .\sites.json
# ③ 实际执行
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Mode Deploy -Sites .\sites.json -Apply
# ④ 需要同时生成 nginx vhost(生成后需重载 nginx)
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Mode Deploy -Sites .\sites.json -Apply -CreateVhost

MySQL 管理员凭据默认自动从已有站点的 config/generated.php 读取(-DbCredSource 可指定,或 -DbRootUser/-DbRootPass 显式传入)。

每个站点的处理步骤:

步骤说明
程序文件robocopy 从交付包复制(默认排除 install/;-KeepInstaller 保留安装向导)
数据库建库(utf8mb4)+ 建号(同名,@127.0.0.1 与 @localhost)+ 授权 + 导入 database.sql
配置写 config/generated.php(库凭据 + 随机 GO_API_KEY)、install.lock、data/.license_domain
Windows 适配依次运行 qdcms-ffmpeg-win.ps1、qdcms-go-win.ps1(-SkipAdapt 可关闭)
管理员创建 user_number=10000、role=9 的站长账号,并回读校验口令哈希
nginx vhost可选 -CreateVhost;生成的 conf 已内置全部 deny 规则与 /accel-media/ 加速 location(-FcgiPass 可改 PHP-FPM 地址,宝塔默认 127.0.0.1:20080)
自检每个站点运行一次 qdcms-selfcheck.ps1

8.3 一键巡检日报(-Report)

# 生成日报文件(默认 <脚本目录>\reports\qdcms-report-<时间戳>.txt + 同名 .csv)
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Discover -Report

# 同时邮件发送(复用【站点自身】的 SMTP 配置,无需另填凭据)
powershell -ExecutionPolicy Bypass -File .\qdcms-deploy.ps1 -Discover -Report -ReportTo "ops@example.com,admin@example.com"

# 可选:-ReportDir <目录>  -ReportTitle <标题>  -MailSite <站点目录>(指定用哪个站点的 SMTP 发信)

日报内容:生成时间 / 主机 / 模式 → 站点数 + PASS/WARN/FAIL 统计 → 结论 → 按站点分组列出每一步结果 (含自检的非 OK 项:SMTP 未配置、计划任务未注册或存在 72 小时上限、CLI 语境提示等)→ 需处理的问题清单; CSV 为逐行明细(Site/Step/Status/Detail),便于归档与二次分析。

每天自动生成(管理员执行一次):脚本会打印现成的 schtasks 命令,例如

schtasks /create /tn "QDCMS巡检日报" /sc daily /st 08:00 /ru SYSTEM /tr "powershell -NoProfile -ExecutionPolicy Bypass -File \"D:\wwwroot\qdcms\qdcms-deploy.ps1\" -Discover -Report -ReportTo ops@example.com"

日报默认写到 C:\ProgramData\QDCMS\reports(Web 之外);若用 -ReportDir 指到站点目录内, 脚本会给出 WARN,且此时必须保证 nginx 拒绝 /reports/(样例与自检均已覆盖)。 邮件依赖站点后台「系统设置 → 邮件 SMTP 配置」;未配置时日报仍会生成,邮件项标记为 WARN 并给出指引。 退出码:无 FAIL 为 0、存在 FAIL 为 1 —— 计划任务/CI 可据此告警。

8.4 安全约定

  • 默认只预演,必须 -Apply 才写盘;目标目录已存在时拒绝部署(需 -Force,且只覆盖同名文件、不删除多余文件)
  • 从不删除任何文件或数据库;各站点的库/用户/口令/授权域名/GO_API_KEY 完全独立
  • 重跑幂等:库已存在则复用并 ALTER USER 同步口令(否则旧口令会与新配置不一致)
  • 全部动作写入 -LogPath,输出 PASS/WARN/FAIL 汇总,退出码 0/1 便于 CI 判定
  • 由本脚本 -CreateVhost 生成的站点不会出现在宝塔面板的站点列表里(面板只管理自己创建的站点)。 若希望面板可见:先在面板「网站」中建站(目录指向同一路径),再用 -Mode Deploy -Force 写入程序, 并把 deny 规则放进 nginx/conf/proxy/<域名>/*.conf

九、停止与回滚

# 停止 Agent+ 服务(同时会结束守护循环)
powershell -ExecutionPolicy Bypass -File .\go-service\run-xdream-go.ps1 -Stop
Get-CimInstance Win32_Process -Filter "Name='powershell.exe'" |
    Where-Object { $_.CommandLine -match 'run-xdream-go\.ps1\s*$' } |
    ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
schtasks /delete /tn x-dream-go /f          # 取消开机自启(管理员)

# 回滚适配补丁:把 *.bak-ffmpegwin-<时间戳> / *.bak-gowin-<时间戳> 覆盖回原文件即可

原始文件:docs/WindowsщГич╜▓шп┤цШО.md · 出于安全考虑,站点不直接暴露 docs/ 目录下的原始文件(其中含内部资料),请在交付包内查看全文。

全部文档
站点公告 官网试运行中,如需购买或试用请通过「联系我们」留言。