DJM CMS 的在线升级分成两段:更新器负责下载、校验、切换 current 并做健康检查;新进程由谁来拉起,取决于站点是怎么启动的。
新安装的站点默认不会自动重启:install.sh 只负责铺目录和启动器,进程通常由宝塔 Go 项目或手工命令启动,既没有 systemd 单元,也没有重启命令,所以升级后会停在“请重启站点服务”。
下面按部署方式给出两种配置,配一次之后升级会自动完成。前提是当前运行的版本不低于 1.0.157:更新器在“当前正在运行的版本”里判断部署方式,所以 1.0.157 这一次升级仍然需要人工重启一次。
1. systemd 托管(推荐)
按安装文档创建单元,使用默认的 Restart=on-failure 和 KillMode=process,不需要额外配置,升级会自动完成。用 Restart=always 也可以,1.0.157 起同样能自动完成。
[Unit]
Description=DJM CMS
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=www
Group=www
WorkingDirectory=/www/wwwroot/djm-cms
Environment=DJM_CONFIG=/www/wwwroot/djm-cms/shared/configs/app.yaml
ExecStart=/www/wwwroot/djm-cms/current/bin/cms serve
Restart=on-failure
RestartSec=3
KillMode=process
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now djm-cms
systemctl status djm-cms
升级时更新器先切换 current 并写好结果,旧进程随后退出,systemd 拉起的就是新版本,不需要手工执行 systemctl restart。
2. 宝塔 Go 项目、supervisor 或自建脚本
在 shared/configs/app.yaml 增加重启命令。新安装生成的配置里已经有空的 deploy: 注释段,照着填即可:
deploy:
restart_command: "/www/wwwroot/djm-cms/restart.sh"
更新器切换完成后会在独立会话里执行这条命令,所以脚本要自己完成“停旧进程 + 起新进程”:
#!/bin/sh
INSTALL_ROOT="/www/wwwroot/djm-cms"
# 先停掉本安装目录下的 CMS 进程
for pid in $(pgrep -f "bin/cms serve"); do
if [ "$(readlink "/proc/$pid/cwd")" = "$INSTALL_ROOT" ]; then
kill "$pid"
fi
done
sleep 3
# 确认没有残留进程再启动,避免端口被占用
if ! pgrep -f "$INSTALL_ROOT/.*serve$" >/dev/null 2>&1; then
cd "$INSTALL_ROOT" || exit 1
DJM_CONFIG="$INSTALL_ROOT/shared/configs/app.yaml" \
nohup "$INSTALL_ROOT/current/bin/cms" serve >> shared/logs/cms.log 2>&1 &
fi
chown www:www /www/wwwroot/djm-cms/restart.sh
chmod +x /www/wwwroot/djm-cms/restart.sh
注意脚本里按进程的工作目录匹配,而不是只写一个绝对路径。pkill -f 匹配的是完整命令行:如果旧进程是用相对路径 ./current/bin/cms serve 启动的,绝对路径模式匹配不到,旧进程会继续占用端口,新进程启动时报 address already in use。按 /proc/<pid>/cwd 判断还能避免误伤同机其它站点。
3. 确认配置生效
后台「系统更新」在升级完成后不会再停在“请重启站点服务”。也可以直接查状态接口:
curl -s https://cms.example.com/api/admin/v1/core-updates/status
返回里的 deployment 字段会说明当前识别到的托管方式:
kind:systemd,或者external(面板、supervisor、自建脚本)。auto_restart_command:配置了deploy.restart_command时显示实际执行的命令。exit_restart:为true表示由 systemd 在旧进程退出后拉起新版本。
4. 失败时看哪里
update-state/updater.log:更新器与重启命令的执行记录,重启命令失败的原因也会写在这里。update-state/result.json:本次升级的最终状态。shared/logs/:重启脚本重定向的进程日志。- systemd 托管时用
journalctl -u djm-cms -n 100查看。
后台「系统更新」页面会保留兜底命令,不会静默失败。
5. 常见问题
- 升级一直停在“等待重启”:既没有 systemd 单元,也没有配置
deploy.restart_command。 - 重启后版本没变:新进程没有起来,先看
updater.log和端口占用。 - 日志里出现
bind: address already in use:旧进程没停掉,检查脚本里的匹配条件。 restart.sh执行了但没效果:确认脚本有执行权限、路径正确,并且用运行 CMS 的同一用户执行。
升级前的备份与回滚操作,见《版本升级、回滚与备份》。
讨论