明珠果苑网站运维手册

农艺学堂 · 2026-10-27
mzgarden 网站文档← 全部文档

明珠果苑 · 网站文档

运维手册

重庆明珠果苑农业开发有限公司

重庆明珠果苑农业开发有限公司2026年10月23日8 个章节19 张表格约 7097 字

一、适用范围与约定

1.1关于手册

本手册覆盖内容管理系统与数字平台云主机的应用部署、数据库、站点、调度与备份恢复,是日常运维与故障处理的操作依据。文中命令与界面路径均按服务器当前实际状态编写,可直接照做。

1.2关于敏感信息

本手册不写入任何账号密码、密钥、令牌。凡涉及凭据之处,一律指向实际存放位置:数据库口令在容器环境变量中(docker inspect 可查),应用配置在 /www/data/ruoyi/ruoyi-office/yudao-server/src/main/resources/application-local.yaml,宝塔面板与 SSH 凭据单独保管,不在本手册内。

二、日常巡检

2.1资源水位

项目 数值 说明
内存总量 / 已用 7.7GB / 约 3.9GB(约 47%) 日常稳定在 45%~50%,余量充足
交换分区 1GB,使用 0 尚未触及,说明内存有余量
系统盘 38GB,已用约 19GB,可用约 18GB 系统盘 38GB,长期保持 18GB 以上可用
/www/data 占用 约 1.4GB 前端、后端、备份与容器数据卷都在此目录下
容器 ruoyi-postgres、ruoyi-redis、tdengine 均在运行

2.2重启后检查清单

docker ps 确认三个容器在跑。

ss -tlnp | grep 48080 后端监听(启动约 108 秒,耐心等两分钟)。

ss -tlnp | grep -E '9999|9090' 执行器与调度中心。

curl -s http://127.0.0.1:48080/ -o /dev/null -w '%{http_code}' 返回 401 即正常。

浏览器登录 sys 站,抽查工作台与菜单。

打开内容管理系统首页,确认页面与图片正常。

三、备份与恢复

3.1三层备份体系与现状

备份分三层,一层只管一段,互相不能替代:一层管整台机器,一层管日常误操作,一层管这台机器本身出事。三层缺哪一层,那一段就是完全裸露的。

层级 手段与存放位置 能防什么 防不了什么
第一层云主机镜像 控制台「镜像 / 快照」,存于云平台侧,不占本机目录 整机报废、系统盘损坏、系统文件被误删、被入侵后整机退档 只能整机回滚,不能单独取回某个文件;退档点之后的数据全丢
第二层宝塔界面备份 宝塔计划任务产物:站点与面板配置在 /www/backup,数据库在 /www/data/backup/db(见 3.2、3.3) 站点文件被误删改、单个库损坏、配置改错想回退 与站点同机同盘,主机丢失、磁盘损坏、欠费清空时一并消失
第三层本地备份 H:\系统备份\新网云主机备份\YYYYMMDD\,一个日期一套全量(见 3.6 至 3.9) 主机宕机、数据被删除或篡改、机房侧故障;可离线留存、可另存异地 靠人工执行,不是实时;距最后一次备份之间的数据会丢

三层的分界记一句话就够——镜像管「整机没了」,宝塔管「手滑改坏了」,本地管「这台机器本身出事了」。日常小问题多半靠第二层顶住,主机真出事只能靠第一层和第三层。

频率:镜像在大版本上线前打一次、平时每月一次;宝塔是每日自动,不占人工;本地在每次发版时打一次,月末再补一次全量。

每层都要验过才算数:镜像能在控制台以它启动一台临时机器;宝塔看任务日志有产物、体积正常;本地包 gzip -t 通过,再抽一两个文件与线上比对。只打不验,出事那天才发现是空的。

三层之中,第二层已在运行,各项任务、位置与状态见下表;第一层是否已开启自动快照,需登录云主机控制台确认,确认之前按「没有」对待;第三层的做法见 3.6 至 3.9。

备份 内容 位置 频率与保留 状态
数据库每日备份 pgsql_mzgy、xxl_job /www/data/backup/db/ 每天 02:30,保留 30 天 运行正常,产物可直接恢复
站点每日备份(宝塔) 三个站点目录,其中 yudao-server 那份实际就是 440MB 的 jar /www/backup/site/ 每天 01:30,保留 3 份 运行中,建议把份数改成 1
面板配置备份(宝塔) 宝塔自身配置 /www/backup/panel/ 每天 保留最近 1 至 2 份即可
MySQL 备份(宝塔) wordpress_sql /www/backup/database/mysql/ 每天 01:30,保留 3 份 任务显示成功,但份数为 0,待查
手工全量备份 14 类:代码、库、配置、内容管理系统等 /www/data/backup/mzgy-full-YYYYMMDD-HHMM/ 按需 脚本 mzgy-full-backup.sh 已就绪

3.2PostgreSQL 每日自动备份

3.2.1 为什么不用宝塔的「备份数据库」任务

宝塔的数据库备份任务只认它自己安装或登记过的库。本机 PG16 跑在 Docker 容器里,宝塔「数据库 → Pgsql」页显示的是「当前未安装 PgSql 环境」,只给两个按钮:

〔安装 PgSql 环境〕:会在宿主机再装一套原生 PostgreSQL,与容器抢 5432 端口,数据可能进错库。绝对不能点。

〔远程数据库〕:把容器里的库登记成远程库,面板要校验版本与权限,对容器内数据库支持不可靠,可能登记后仍然备份失败。

结论:因此改用宝塔「计划任务 → Shell脚本」:仍然是面板排期、面板看日志,脚本内部直接进容器跑 pg_dump,不依赖面板的数据库模块,也不受面板升级影响。

3.2.2 任务配置

字段 值
任务类型 Shell脚本(不要选“备份数据库”)
任务名称 备份PostgreSQL数据库
执行周期 每天 02:30(刻意错开 01:30 的网站与 mysql 备份,避免三条任务抢磁盘)
执行用户 root
进程锁 开启(防止上一轮未结束时重复执行)
日志文件 /www/server/cron/<任务哈希>.log,宝塔任务列表点「日志」可看

3.2.3 脚本机制

用 docker exec ruoyi-postgres pg_dump -U "$POSTGRES_USER" -Fc 导出,用户名取自容器环境变量,脚本里不出现任何密码。

先写临时文件 .part,用 pg_restore -l 读一遍目录,确认能读出对象才改成正式文件名,避免半截文件冒充备份。

小于 10KB 一律判定无效,防止空文件显示成功。

任何一项失败即 exit 1,宝塔任务列表会标红,不会再出现“显示成功但没东西”。

保留最近 30 天,自动清理更早的 dump;每次运行追加写入 /www/data/backup/db/backup.log。

3.2.4 验证方法

ls -lh /www/data/backup/db/
# 确认 dump 里确实带数据段(正常应为 8,xxl_job 共 8 张表有数据)
cat /www/data/backup/db/xxl_job_YYYYMMDD.dump | docker exec -i ruoyi-postgres \
    pg_restore -l | grep -c "TABLE DATA"
# 对照库内实际数据量
docker exec ruoyi-postgres psql -U pgsql_mzgy -d xxl_job \
    -tc "select relname||'='||n_live_tup from pg_stat_user_tables order by n_live_tup desc limit 6"

踩坑:pg_restore -l 后面不要写 – 当文件名,某些版本会报 could not open input file "-";省略文件名走管道即可。

实测基准:pgsql_mzgy 约 1.3MB、xxl_job 约 22KB。xxl_job 体积小是因为该库总共只有 8 行数据,主要体积是表结构,属正常。

3.2.5 失败排查

现象 原因 处理
docker: command not found cron 环境 PATH 里没有 docker 脚本已内置 PATH;仍失败则改用 /usr/bin/docker 全路径
permission denied 执行用户非 root 把任务执行用户改为 root
产物只有几十字节 库连接失败或 dump 中途中断 看 /www/data/backup/db/backup.log,并在终端手动跑一次定位
任务列表显示失败 脚本以非 0 退出,通常是校验没过 先看日志,再看磁盘是否写满

3.3宝塔自带备份的现状与调整建议

站点备份把 /www/data/ruoyi/frontend 与 yudao-server 的 jar 目录都当成了“站点”在备,其中 yudao-server 那份每份 440MB,保留 3 份就是 1.3GB。jar 本地随时能重新编译,保留 1 份应急即可,建议把该任务的保留份数由 3 改成 1。

MySQL 那条任务每天显示成功,但备份份数为 0,需要进任务日志确认是否真的产出了文件。内容管理系统数据虽然变动少,但没有备份等于裸奔。

宝塔自带的 /www/backup 与业务备份目录 /www/data/backup 是两回事,清理时不要混,也不要把业务备份放错地方。

3.4恢复演练

备份能读出来不等于能恢复进去。建议找时间做一次演练,全程只碰临时库,生产库只读:

docker exec ruoyi-postgres psql -U pgsql_mzgy -c "create database pgsql_mzgy_verify"
cat /www/data/backup/db/pgsql_mzgy_YYYYMMDD.dump | docker exec -i ruoyi-postgres \
    pg_restore -U pgsql_mzgy -d pgsql_mzgy_verify --no-owner 2>&1 | tail -15
docker exec ruoyi-postgres psql -U pgsql_mzgy -d pgsql_mzgy_verify \
    -tc "select count(*) from information_schema.tables where table_schema='public'"
# 表数对上生产库(327 上下)后清理
docker exec ruoyi-postgres psql -U pgsql_mzgy -c "drop database pgsql_mzgy_verify"

恢复演练只在临时库上进行,生产库全程只读。做完一次,“备份可用”才算从推测变成事实。

3.5备份目录规范

上传文件、备份产物一律放 /www/data/backup/,不散落在业务目录里。

命名带日期:数据库 dump 用 库名_YYYYMMDD.dump;jar 用 yudao-server-YYYYMMDD-HHMM.jar;全量备份用目录 mzgy-full-YYYYMMDD-HHMM。

业务目录 /www/data/ruoyi 下不要长期堆放前端历史版本目录,需要留档就压缩后移入 backup,否则过几个月分不清哪个是线上。

3.6本地归档:一个日期一套,两个系统

服务器上的每日备份只能防误删,防不了主机失联——备份和站点在同一块盘上。因此在服务器之外再建一套本地归档:每次发版或月度盘点,把两个系统各取一份完整包,按日期存放,出事时整套拿走就能还原。

目录结构固定为「日期 → 两个系统 → 固定子目录」,一个日期目录就是一次全量,里面不再按版本细分。每个位置放什么、从哪里取,见下表。

目录 放什么 从哪取
WordPress\整站\ 整站打包,含 wp-config.php 与 wp-content\uploads /www/wwwroot/明珠果苑.com/
WordPress\数据库\ mysqldump 导出的 wp 库 宝塔 MySQL,库名 wordpress_sql
Yudao\后端源码\ 本地工程整体打包,含 .git,排除 target 与 .idea 本地 H:\Ruoyi Office\ruoyi-office
Yudao\后端编译\ yudao-server.jar 与 xxl-job-admin-2.4.0.jar /www/data/ruoyi/backend/、/www/data/xxl-job/
Yudao\前端源码\ 本地工程整体打包,含 .git,排除 node_modules 与 dist 本地 H:\Ruoyi Office\ruoyi-office-vben
Yudao\前端编译\ dist 打包,含手改过的 index.html /www/data/ruoyi/frontend/
Yudao\数据库\ 全量 dump 加建表脚本,含 xxl-job 建表 pg_dump -Fc pgsql_mzgy、xxl_job
Yudao\配置文件\系统\ systemd 单元、crontab、nginx 全量、SSL 证书、xxl-job /etc/systemd/system 等
Yudao\配置文件\系统\security\ iptables 规则、sshd 配置、ufw 状态、加固项 iptables-save、/etc/ssh、/etc/sysctl.d
Yudao\上传文件\ 附件目录 位置待确认

四条规矩。一是源码那两格只能从本地工程打包,服务器上没有源码,取不到;二是统一用 tar.gz,不用 zip,zip 在 Windows 下按 cp936 记文件名,拿到 Linux 解包中文目录会变乱码;三是应用配置(application*.yaml、logback-spring.xml)全部打包在 yudao-server.jar 内,服务器上没有外部配置文件,备份了 jar 就等于备份了配置,不要单独拆出来;四是每个系统都要有一份 MANIFEST.txt,记文件名、大小、MD5、来源路径和构建信息,没有它,半年后没人分得清哪个 jar 对应哪次提交。

旧目录 20261003 是 10 月 3 日发版前的快照,按旧命名存放,不迁移、不再往里加内容,只作回退点保留。

本地误删的编译产物先别急着重编译,去回收站找回来再说——这次发版用的那份 18:11 产物,就是从 H 盘回收站里捞回来的。产物归档一律带时间戳,例如 web-antd-dist_20261025_181101.zip,与 dist.zip 共存,避免新旧两个同名包互相覆盖;也不要为了图省事把归档改回 dist.zip。

3.7一次备份怎么做

顺序不要调:前五步在服务器上取数,第六步在本地,最后两步做核对与归档。

步骤 动作 命令或要点
1 后端产物 把 /www/data/ruoyi/backend/yudao-server.jar 拷出,文件名带日期与构建时间
2 前端产物 tar czf frontend-YYYYMMDD.tar.gz -C /www/data/ruoyi/frontend .
3 平台数据库 docker exec ruoyi-postgres pg_dump -U pgsql_mzgy -Fc pgsql_mzgy > pgsql_mzgy_YYYYMMDD.dump
4 系统与配置 打包 /etc/systemd/system 服务单元、crontab -l、nginx 站点与 extension、证书目录、/www/data/xxl-job 整个目录(含调度 jar)、iptables-save 结果;应用配置在 jar 内不用单独取
5 内容管理系统 tar czf site-YYYYMMDD.tar.gz -C /www/wwwroot/明珠果苑.com . 再用 mysqldump 导出 wp 库
6 源码 本地打两个工程包,排除 node_modules、target、.idea,保留 .git
7 算校验 逐文件算 MD5,填 MANIFEST.txt,附 commit、构建时间、JDK 与 pnpm 版本
8 归档 放进 H:\系统备份\新网云主机备份\YYYYMMDD\,按 3.6 的目录落位

取完先别收工,确认两件事:jar 和 dist 是不是这次真要上的那一版(对 commit 与构建时间);dump 是不是完整的(pg_restore -l 能读出对象目录,体积也不是几 KB)。

3.8恢复怎么做

顺序不能颠倒:先环境、再配置、再产物、最后数据。产物先上而配置后到,服务一定起不来,日志里报的是找不到配置或数据源,很容易误判成代码问题。

顺序 做什么 落点或命令
1 装环境 按 配置文件\系统 里的版本清单对齐 PG 16、MySQL、JDK 17、nginx、Redis
2 放配置 服务单元、nginx、证书、crontab 按 配置文件\系统\还原路径对照.txt 逐项拷回,再 systemctl daemon-reload;防火墙执行 iptables-restore < security\iptables.rules 还原 14 条封堵规则;应用配置在 jar 内,无需单独放
3 放后端 yudao-server.jar 放 /www/data/ruoyi/backend/,宝塔 Java 项目指向它;xxl-job-admin-2.4.0.jar 放 /www/data/xxl-job/,必须是 PG 改造版,不要换成官方原版
4 放前端 清空 /www/data/ruoyi/frontend/ 后再解 dist,不要覆盖式解压
5 导数据库 先建空库,再 pg_restore –no-owner;菜单缺项补跑 数据库\部署脚本\
6 放附件 上传文件回原目录,路径与备份时保持一致
7 起服务 后端走宝塔「Java 项目」启动,不要 systemctl start yudao-server(该系统单元已 disable,两套同开会抢 48080);再 systemctl enable –now xxl-job-admin,看日志无异常
8 内容管理系统 整站解到 /www/wwwroot/明珠果苑.com/,导 wp 库,改 wp-config.php 的库名与域名

验收六条:后端进程在且日志无启动异常;curl 请求 /admin-api 正常返回;前端首页打开不白屏;能登录;左侧菜单树不缺项;内容管理系统首页与后台都能进。缺一条就是没恢复完。

第 4 步必须「先清空再解压」。前端目录里残留旧 hash 文件时,页面会去请求已删除的 chunk,表现是白屏或一直转圈,看着像代码坏了,其实只是没清干净。

3.9保留与异地

只保留最近 3 次全量,加每月末 1 次长期归档,其余删掉。一次约 700MB(其中后端与调度两个 jar 占 590MB),全留一年就是几十 GB,翻找的时间成本比硬盘贵。

H 盘和源机同处一地,至少再放一份到移动硬盘或对象存储。备份与主机同时消失的场景并不罕见,不异地的备份等于没有备份。

四、安全加固

4.1加固内容

层面 措施
端口收敛 后端 48080、PostgreSQL 5432、Redis 6379、MySQL 3306、调度 9090 等敏感服务全部绑 127.0.0.1;公网只露 80(网站)和宝塔面板端口(安全入口加 BasicAuth)
系统层 开宝塔防火墙、禁 ping;SSH 登录宽限和空闲超时、密码策略、移除空密码登录、限制 su、去掉 sudo 免密
内核与应用 开 SYN Cookie 防 SYN 洪水;PHP 关掉错误显示;调度中心用强随机令牌

4.2加固验收

加固完扫了一遍:0 紧急、0 高风险。所有改动都留了 .bak,能逐项回滚。

五、权限与租户维护

完整方案见《明珠果苑权限模型落地方案》。核心原则一句话:上下级关系用部门树加数据权限,平级隔离用租户。租户管隔离,层级归业务树。

5.1六分类租户

编号 租户名 分类
1 明珠果苑 系统(平台方,超管可跨租户查看)
121 伙伴1 伙伴
122 基地1 基地
123 渠道1 渠道
124 单位1 单位
125 备用1 备用

租户编号(tenant_id)不能改,全库几十张表引用它,改动等于级联灾难。

渠道体系(一、二、三级)用系统租户内的部门树加数据权限「本部门及以下」实现,线上、线下用部门命名标识(如「线上·××」「线下·××」)。

基地、伙伴各建一个租户;游客与 C 端用会员体系,不建租户、不进后台。

5.2角色体系

顺序 角色 code(不可改) 类型
1 超级管理员 super_admin 内置
2 技术总监 common 内置
3 人事总监 crm_admin 内置
4 市场总监 test-dp 自定义
5 访客 guest_readonly 自定义

内置角色界面拒绝编辑,需直接改库;只改 name 与 sort,code 一律保留(框架识别用)。

超管账号 yanghsia(昵称杨夏,id=1),日常管理用此号。

5.3跨租户机制

链路为:前端租户切换组件携带 visit-tenant-id 请求头 → 后端 TenantVisitContextInterceptor 校验 → 放行超管跨租户查询。菜单 5010(system:tenant:visit)是入口。

注意:layouts/basic.vue 中的租户切换组件必须保持渲染,不得加 v-if 之类的限制,否则顶栏「请选择租户」下拉会消失。

5.4菜单授权规则与一次越权复盘

先分清:目录(type=1)是子菜单的容器,菜单(type=2)是页面,按钮(type=3)是页面里的操作。三者串起来才是一条可见的授权路径。

规则一:目录节点必须随子菜单一起授予。只给子菜单、不给它上面的目录,前端拿不到父节点,子菜单根本不显示,看起来像授权没生效。要整棵排除用递归条件,例如 m.id <> 1224 即排除「租户管理」及其全部子节点。

规则二:按最小必要给。角色只挂该岗位真用得上的目录与菜单;按钮只给查询类权限码(query、get、list、monitor、preview),增、删、改、导入、导出一律不给;数据权限上,本部门岗位给「本部门及以下」,别图省事给全部。

复盘:渠道账号(system_users id=143,tenant_id=123)曾绑到租户管理员角色 156,该角色挂了 257 个菜单,等于平台全量,渠道登录后因此看得到明珠果苑租户的信息。处置:把角色 156 的「1224 租户管理」及其子树(1138、1139–1143、5010)取消授权,渠道就看不到了。

复查:新增渠道、伙伴账号后,先看它绑的角色有多少条菜单授权,接近全量的立刻警觉。按角色统计条数,第一名最可疑:SELECT role_id, COUNT(*) FROM system_role_menu GROUP BY role_id ORDER BY 2 DESC;

六、内容管理系统运维与安全

6.1安全观察与建议

内容管理系统访问日志每天增长约 20MB,几乎全部是扫描:ThinkPHP、Magento、Symfony 漏洞探测,后门文件探测,AI Agent 协议扫描(/.well-known/*),以及 referrer 为垃圾站点的请求。日志里返回的都是 Primary script unknown 或 not found,说明这些攻击没有成功,我们用的是 PHP + WordPress,与它们打的技术栈不匹配。

建议在宝塔「网站防火墙」里开启 WAF,让扫描在 nginx 之前就被挡掉,既省 CPU 也省日志。不要手写一堆 nginx 拦截规则,升级或换机容易丢。

四个域名打开的是同一份内容。主域为 www.mzgarden.com,www.明珠果苑.com、www.明珠果苑.中国、www.明珠果苑.网址 建议 301 到主域,避免搜索引擎视为重复站点。

注意:主题 functions.php 中同名函数只能定义一次,重复声明会触发 Cannot redeclare 致命错误,改主题后要用无痕窗口验证。现行代码只有一处定义。

6.2内容管理系统改版与素材规范

背景音乐:浏览器一律禁止自动播放,只能由用户点击开启。页面上要留一个明确的开启入口,不要指望进场自动响,否则音乐永远放不出来。

Hero 图:上线前必须压缩,WebP 最佳,单张不超过 300KB。超了首页首屏会明显拖慢,手机端尤其吃亏。

动画性能:水滴类装饰动画控制在 14 个以内,手机端按屏宽缩小尺寸;系统里开了「减少动画」的用户要整组关掉动画(prefers-reduced-motion),别让装饰拖慢首屏。

顶部导航不再靠「外观 → 菜单」手工维护:主题按分类目录树自动生成菜单,后台新建分类、前台自动多一项,排序按分类建立顺序,未分类不显示。分类简介写在分类描述里,会显示在前台分类页。要调整顺序就调分类的顺序或层级,不要回外观里再搭一套静态菜单,两套同时存在会互相打架。

6.3维护模式日常运维

维护模式由自制插件「明珠果苑维护模式 mzgy-maintenance」提供,用于整站升级、改版期间给未登录访客显示一个友好的临时页面,而不是报错或白屏。开关在后台「设置 → 明珠果苑维护」,一个勾选框,状态存于选项 mzgy_maintenance_active。

勾上后,未登录访客访问任意前台页面统一返回 503(带 Retry-After: 3600 头,提示搜索引擎稍后再来,不会误判为宕机)并显示维护页;已登录管理员照常浏览前台。后台、登录页、REST 接口始终放行,所以勾了维护也能正常登录、进后台。管理员顶栏会出现红色「维护模式:已开启」标记,防止忘关。

维护页有两个候选模板,靠重命名切换、不是复制覆盖。插件目录 /www/wwwroot/明珠果苑.com/wp-content/plugins/mzgy-maintenance/ 下:

候选文件 适用场景 页面内容
建设中maintenance.php 网站上线前 「网站建设中」,带上线倒计时与数字管理平台入口
维护中maintenance.php 升级、维护时 「网站升级维护中」,简洁提示页

插件实际加载的是同目录的 maintenance.php。把哪个候选文件名前的中文前缀去掉、重命名为 maintenance.php,前台就显示哪个;两个候选文件都长期保留在目录里,谁叫 maintenance.php 谁生效。同目录只能有一个 maintenance.php,是重命名切换,不要复制覆盖。

日常操作按下面的顺序:

场景 动作 要点
开维护 先确认 maintenance.php 是要展示的页,再到后台勾选「网站维护中」并保存 页面没重命名到位时,先按下面“切页”处理,再勾开关
关维护 后台取消勾选即恢复 页面文件不用动,留着下次再用
改文案 直接编辑对应候选文件(维护中maintenance.php / 建设中maintenance.php) 它当前就是 maintenance.php 时保存即生效;否则先重命名切换;配色按莫兰迪绿 #5B7B5E 已设定
切页(建设中/维护中互换) 在插件目录重命名:先把现有的 maintenance.php 改回带中文前缀的名字,再把要用的候选重命名为 maintenance.php 是重命名切换,不是覆盖;任何时候同目录只有一个 maintenance.php

开维护后自检四条:无痕窗口(未登录)打开前台,应看到维护页且 HTTP 状态为 503;登录管理员后打开前台,应正常看到网站而不是维护页;后台、登录页、接口可正常访问;维护结束后顶栏红标消失、无痕窗口恢复正常。

先分清 503 和 403,别误判。整站对未登录访客返维护页、状态码 503,是维护模式在生效;只有单篇文章对游客返 403、登录后能看,是内容卫士 mzgy-guard 的阅读权限控制(见开发手册 4.4),不是维护模式。核对维护中的内容时,用接口取 content.raw 或登录管理员看,不要用游客前台判断。

维护页是纯 HTML、无外部依赖,单独显示不会因样式或资源加载失败而变形。改了主文件 mzgy-maintenance.php 的逻辑后,必要时在后台「插件」页停用再启用一次。不要让静态 index.html 维护页与本插件两套机制并存(见开发手册 4.5)。

七、故障排查

7.1常见故障速查

现象 先查什么 处理
平台打不开或 502 ss -tlnp | grep 48080;docker ps 后端没起来就重启 Java 项目;容器停了就 docker start
登录后菜单空白 浏览器 F12 看接口;Redis 缓存 清 Redis 缓存后 Ctrl+F5
改了 jar 重启不生效 pgrep -af 'yudao-server\.jar' 是否只一个 确认不是 systemd 那套在跑;必要时 disable 它
内存突然变高 ps aux –sort=-%mem | head -12 先认进程再动手,别 kill 服务进程
磁盘增长快 du -sh /www/* | sort -rh 先看是日志、备份还是历史目录
内容管理系统白屏 nginx 错误日志、PHP-FPM 是否在跑 看 error.log 定位,不要急着重装
定时备份没执行 宝塔计划任务列表的“上次执行” 点「执行」手动跑一次,看日志定位
点菜单显示“功能建设中·敬请期待” 该菜单挂的是统一占位页 common/coming-soon/index 属预期,页面还没开发;开发完成后把该菜单的 component 改指真实页面。平台现有 62 个菜单是这么挂的
访客整站看到维护页、返回 503(非预期) 后台「设置 → 明珠果苑维护」的勾选状态 没在维护就取消勾选;正在维护属正常;放行规则见 6.3
勾了维护却不显示维护页 插件目录里 maintenance.php 是否存在、是否重名 把要用的候选重命名为 maintenance.php,同目录只能有一个,是重命名切换不是覆盖
单篇文章游客 403、登录后能看 内容卫士 mzgy-guard 的阅读权限 属正常访问控制,不是维护模式;整站 503 才是维护,见 6.3

7.2后端类

现象 原因 解决
内存被白占 1.2GB systemd 与宝塔各起一套同一份 jar systemctl disable + stop systemd 那套
改了 jar 重启不生效 systemctl restart 重启的不是在服务的那套 统一走宝塔 Java 项目页重启
jar 启动报类缺失 依赖未声明 + 实现类丢失 + 嵌套 jar 扫描 见 4.6
启动卡死在 iotScheduler iot 模块 Quartz 调度器阻塞 iot 模块暂停启用
产物 3.4GB 未带 -P boot,走了 cloud profile 固定命令带 -P boot
打包报 IotDeviceStateEnum 找不到 -DskipTests 仍编译测试代码,测试类 import 路径与主代码不符 改用 -Dmaven.test.skip=true
运行中 mvn clean 导致 jar 消失 clean 删除 target 运行期间不要 clean,打包用 package
PowerShell 下打包参数失效 -D 参数被拆 参数加双引号
定时任务页面 404 后端 JobController 被裁剪 方案 A 移植(待实施)

7.3前端类

现象 原因 解决
白屏、主 JS 404 jse 目录被改名 js,index.html 引用 /jse/ 重新解压 dist.zip 恢复目录结构
入口内部资源 404 硬编码 /web/ 前缀未配 Nginx 加 location ^~ /web/ rewrite
登录后“系统异常” 源码比 SQL 新,system_dept 缺 org_type 列 ALTER TABLE 补列
登录后 404 defaultHomePath 指向 /workspace 但菜单表无记录 补工作台菜单
菜单重复导致路由崩 SQL 跑了两遍 删除重插,只执行一次
子菜单 404 子菜单 path 带斜杠,拼出双斜杠 path 不带斜杠
“文档地址”提示条 VITE_APP_DOCALERT_ENABLE 未关 .env.production 置 false 后重编译
改偏好默认值不生效 localStorage 缓存旧偏好 偏好面板点一次或清缓存
构建崩在 jiti vite 与 jiti 版本冲突 保留 resolve.alias 的浏览器 mock
已登录,发版后点菜单白屏 发版后懒加载 chunk 已换名,旧页面请求旧 chunk 404 前端已内置 vite:preloadError 自愈,自动刷新一次即恢复;仍反复见部署手册 4.8
常规窗口总是旧版,无痕正常 浏览器会话恢复,关闭重开是整页快照、零请求 按本节后面三条 Edge 设置处理;普通用户无需处理

先分诊:无痕窗口打开正常、地址栏手输完整网址回车也正常,说明服务器上只有一个版本,是浏览器本地把旧页面留住了;若两种方式都仍是旧版,先回上面的表查服务器,不要动浏览器。

为了能实时观看修改后的效果,避免页面缓存造成旧版样式驻留,Edge 需按下面三条调整。

条目 作用 性质
第 1 条:启动时打开新标签页 直接关掉“恢复上一个会话标签页”这个动作——旧页面快照不再被还原 决定性,治本
第 2 条:关启动加速 + 关后台继续运行 Edge 默认“窗口关了、进程还常驻”。你以为是重新启动,其实是唤起那个带着旧会话的常驻进程,第 1 条的“启动时”逻辑可能根本没走。关掉后 Edge 才真正退出 保障,让第 1 条稳定生效
第 3 条:结束 msedge.exe 再打开 不是设置,是一次性清场:把当时常驻、持有旧会话的进程杀掉,让新设置从干净进程启动 只第一次需要

三条对应的开关位置:设置 → 起始、主页和新建标签页 → “启动时”选“打开新标签页”;设置 → 系统和性能 → 关掉“启动增强”与“关闭 Microsoft Edge 后继续运行后台扩展和应用”。

普通用户无需处理:输入网址、点链接、从收藏夹进入都属于正常导航,no-cache 会自动取到最新版;即便极端情况下恢复了登录页快照,也只看一次,登录跳转或刷新即自动更新。

7.4数据库类

现象 原因 解决
长期没有数据库备份 宝塔原生任务不认容器内的 PG,一直没建对应任务 建 Shell脚本 任务,失败会标红
备份“显示成功”却没文件 宝塔 MySQL 备份任务只刷状态 查任务日志,必要时同样改脚本方式
SQL 插入整批失败 system_role_menu.id 无自增 显式 id,MAX(id)+ROW_NUMBER()
导错库 宝塔数据库页不显示 Docker 容器 以 docker ps 为准
json 字段类型不符 官方 PG 版惯例用 text jsonb 改 text
中文域名加不进宝塔 面板输入框拦截 命令行 sed 写 punycode

7.5站点与磁盘类

现象 原因 解决
磁盘被占 1.3GB 站点备份把 jar 目录当站点,每天备一份 440MB,留 3 份 保留份数改 1;jar 需要时手动存 backup
删了文件磁盘没变 宝塔删除先进回收站 清空回收站后空间才真正释放
“内部服务器错误” proxy_pass 尾部斜杠吃掉 /admin-api 去掉尾部斜杠
curl 404 但浏览器正常 Host 头不匹配,走了默认站点 curl 加 -H "Host: …"
conflicting server name 同一域名配在两个站点 删除重复站、去重 server_name
sed 改配置后域名重复 同一条 sed 执行了两遍 改前先备份,改后用 grep 核对
PageAdmin 目录已删但进程还在 dotnet 进程加载着 dll,不随目录消失 kill 该进程,确认端口释放

附录 APostgreSQL 每日备份脚本全文

脚本存档在 H:\系统备忘\常用\备份命令\mzgy-pg-backup-daily.sh,服务器上的执行副本存放在宝塔计划任务「备份PostgreSQL数据库」的脚本框内。迁移或重建时,把下面全文粘贴到「计划任务 → 添加任务 → Shell脚本」即可,无需修改任何变量。

#!/bin/bash
# ============================================================
# 明珠果苑网站 — PostgreSQL 每日备份
# 容器 ruoyi-postgres (postgres:16),库:pgsql_mzgy、xxl_job
# 用途:粘贴到宝塔「计划任务 → Shell脚本」,每天 02:30 执行
# 2026-10-23 建立
# ============================================================
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
CONTAINER="ruoyi-postgres"
OUT="/www/data/backup/db"
DBS="pgsql_mzgy xxl_job"
KEEP_DAYS=30
TODAY=$(date +%Y%m%d)
LOG="$OUT/backup.log"
mkdir -p "$OUT"
log() { echo "[$(date '+%F %T')] $*" | tee -a "$LOG"; }
# 取容器内默认超级用户名,不写死、不落密码
PGUSER=$(docker exec "$CONTAINER" printenv POSTGRES_USER 2>/dev/null)
if [ -z "$PGUSER" ]; then
  log "失败:取不到 $CONTAINER 的 POSTGRES_USER,容器可能在重启"
  exit 1
fi
fail=0
for db in $DBS; do
  final="$OUT/${db}_${TODAY}.dump"
  part="$final.part"
  if ! docker exec "$CONTAINER" pg_dump -U "$PGUSER" -Fc -d "$db" > "$part" 2>>"$LOG"; then
    log "失败:$db 导出出错(详见上方 pg_dump 报错)"
    rm -f "$part"
    fail=1
    continue
  fi
  size=$(stat -c %s "$part" 2>/dev/null || echo 0)
  # 校验质量:文件不能太小,且目录(TOC)必须能被 pg_restore 读出
  if [ "$size" -lt 10240 ]; then
    log "失败:$db 备份只有 ${size} 字节,判定为无效"
    rm -f "$part"
    fail=1
    continue
  fi
  if ! docker exec -i "$CONTAINER" pg_restore -l < "$part" > /dev/null 2>>"$LOG"; then
    log "失败:$db 备份文件损坏,pg_restore 无法读取目录"
    rm -f "$part"
    fail=1
    continue
  fi
  mv -f "$part" "$final"
  chmod 600 "$final"
  log "成功:$db  $(du -h "$final" | cut -f1)  $final"
done
# 清理超过保留期的备份
find "$OUT" -maxdepth 1 -type f -name '*.dump' -mtime +"$KEEP_DAYS" | while read -r old; do
  rm -f "$old"
  log "清理:$old"
done
if [ "$fail" -ne 0 ]; then
  log "本次备份有失败项,请检查"
  exit 1
fi
log "两个库全部备份成功,当前目录占用 $(du -sh "$OUT" | cut -f1)"
exit 0

脚本里有两处容易被误改:KEEP_DAYS 是保留天数(改小会提前删历史备份);DBS 是库名列表,用空格分隔,增减库只需改这一行。

全文完

重庆明珠果苑农业开发有限公司运维手册 · 内部技术文档

栏目建设中,敬请期待