
世界守护者
Hytale 服务器的智能分层备份保留策略。
WorldKeeper
适用于 Hytale 服务器的智能分层备份保留系统。
问题所在
Hytale 默认的备份系统(AdminUI)每隔 X 分钟备份一次,并保留最近的 Y 份副本。以典型配置为例:每 30 分钟备份一次,保留 10 份,你只有 5 小时 的恢复窗口。如果问题在夜间未被发现,你最早的备份也已经被污染了。
WorldKeeper 如何解决
WorldKeeper 使用分层保留策略(祖-父-子),既保留频繁的近期备份,也保留较旧的恢复点:
| 层级 | 默认间隔 | 默认保留量 | 覆盖范围 |
|---|---|---|---|
| 快照 | 30 分钟 | 12 份 | 最近 6 小时 |
| 日备份 | 每日 | 7 份 | 最近 7 天 |
| 归档 | 每周 | 4 份 | 最近 4 周 |
总计:23 份备份(按每份 304 MB 计算约 7 GB),覆盖长达 4 周的历史记录。
新的备份始终以快照形式开始。当最早的快照超过 24 小时后,它会被提升为日备份;当最早的日备份超过 7 天后,它会被提升为归档。每个层级中多余的备份会被自动删除。所有间隔和保留数量均可配置。
功能特点
- 分层保留 —— 快照、日备份和归档,自动提升
- 网页仪表盘 —— 通过浏览器查看、下载、创建和删除备份
- 活动配置显示 —— Web UI 精确显示当前配置,无需猜测
- 前后钩子 —— 在每次备份前后运行服务器命令或 Shell 脚本
- AdminUI 冲突检测 —— 启动时警告两个系统是否同时运行
- 可配置恢复 —— 基于 Web 的恢复功能默认关闭,可通过配置开启
安装
前置要求
- Java 21+
- Maven 3.6+
- Hytale 专用服务器
构建
# 将 Hytale 服务器 API 安装到本地 Maven 仓库(一次性设置)
mvn install:install-file \
-Dfile=/path/to/HytaleServer.jar \
-DgroupId=com.hypixel.hytale \
-DartifactId=Server \
-Dversion=0.0.1 \
-Dpackaging=jar
# 构建模组
mvn clean package
输出:target/hytale-gfs-backup-1.0.0.jar
部署
# 复制到服务器模组文件夹
cp target/hytale-gfs-backup-1.0.0.jar /path/to/Server/mods/
# 重启 Hytale 服务器
首次启动时,WorldKeeper 会在 mods/com.gfsbackup_WorldKeeper/config.json 创建其配置文件。
禁用 AdminUI 备份
WorldKeeper 独立于内置的 AdminUI 备份系统运行。同时运行两者意味着两个系统会将备份写入同一个 backups/ 文件夹。如果检测到 AdminUI 备份仍处于启用状态,WorldKeeper 会在启动时记录一条警告。
要禁用 AdminUI 备份,请编辑 Server/AdminUI/Backup.json:
{
"enabled": false
}
配置
所有设置位于 mods/com.gfsbackup_WorldKeeper/config.json。首次运行时使用默认值创建。
{
"enabled": true,
"backupFolder": "backups",
"worldFolder": "universe",
"tiers": {
"son": {
"enabled": true,
"intervalMinutes": 30,
"retentionCount": 12,
"description": "30-minute backups for 6 hours"
},
"father": {
"enabled": true,
"intervalMinutes": 1440,
"retentionCount": 7,
"description": "Daily backups for 7 days"
},
"grandfather": {
"enabled": true,
"intervalMinutes": 10080,
"retentionCount": 4,
"description": "Weekly backups for 4 weeks"
}
},
"hooks": {
"preBackup": [
"say [WorldKeeper] Starting backup..."
],
"postBackup": [
"say [WorldKeeper] Backup complete!"
]
},
"webServer": {
"enabled": true,
"port": 8081,
"allowRestore": false,
"allowedIPs": []
},
"advanced": {
"serverSaveBeforeBackup": true,
"deleteEmptyBackups": true,
"asyncBackup": true
}
}
配置参考
| 键 | 默认值 | 描述 |
|---|---|---|
enabled |
true |
整个模组的总开关 |
backupFolder |
"backups" |
备份 ZIP 文件存放目录,相对于 Server/ |
worldFolder |
"universe" |
要备份的世界目录,相对于 Server/ |
层级
配置内部使用 son、father、grandfather。它们在 Web UI 中对应 快照、日备份 和 归档。
| 键 | 描述 |
|---|---|
enabled |
启用/禁用此层级 |
intervalMinutes |
备份运行的频率(son 层级驱动调度器) |
retentionCount |
此层级中保留的最大备份数量 |
Web 服务器
| 键 | 默认值 | 描述 |
|---|---|---|
enabled |
true |
启用 Web UI |
port |
8081 |
Web UI 的 HTTP 端口 |
allowRestore |
false |
允许从 Web UI 恢复备份 |
allowedIPs |
[] |
IP 白名单(空列表 = 允许所有 IP) |
高级设置
| 键 | 默认值 | 描述 |
|---|---|---|
serverSaveBeforeBackup |
true |
备份前将世界数据刷新到磁盘 |
deleteEmptyBackups |
true |
删除 0 字节的备份 |
asyncBackup |
true |
异步运行备份 |
Web UI
通过 http://localhost:8081(或你配置的端口)访问仪表盘。
- 每个层级的备份表格,表头显示活动配置(例如:"快照 -- 每 30 分钟,保留 12 份")
- 可折叠的配置面板,显示完整的活动配置
- 总计备份数量、大小和上次备份时间
- 创建、下载和删除备份
- 恢复备份(当
allowRestore启用时) - 每 30 秒自动刷新
REST API
| 端点 | 方法 | 描述 |
|---|---|---|
/api/backups |
GET | 列出所有备份及统计信息和配置 |
/api/backups/create |
POST | 触发手动备份 |
/api/backups/download/:filename |
GET | 下载备份 ZIP 文件 |
/api/backups/restore/:filename |
POST | 恢复备份(需要 allowRestore 为 true) |
/api/backups/delete/:filename |
DELETE | 删除备份 |
钩子
钩子可以在每次备份前后运行服务器命令或系统命令。
- 以
say或/开头的行作为 服务器命令 执行 - 所有其他行作为 系统命令 通过 Shell 执行(30 秒超时)
变量替换
| 变量 | 描述 |
|---|---|
{{backup_file}} |
备份 ZIP 文件的完整路径 |
{{backup_filename}} |
仅文件名(例如 2026-02-01_09-31-10.zip) |
{{backup_tier}} |
层级名称(SON、FATHER、GRANDFATHER) |
{{backup_size}} |
文件大小(字节) |
示例
{
"hooks": {
"preBackup": [
"say [WorldKeeper] Starting world backup..."
],
"postBackup": [
"say [WorldKeeper] Complete!",
"/usr/local/bin/notify-discord.sh 'Backup done: {{backup_filename}} ({{backup_tier}})'"
]
}
}
恢复备份
备份是 universe/ 目录的 ZIP 压缩包,包含世界、区块、玩家数据、传送点和记忆。
手动恢复过程:
- 停止 Hytale 服务器
- 重命名或移动当前的
Server/universe/目录 - 将备份 ZIP 解压到
Server/(它将重新创建universe/文件夹) - 启动服务器
Web UI 的恢复功能(通过 allowRestore 启用)会安全地将备份解压到 temp-restore/ 目录。你仍然需要手动交换文件夹并重启服务器。
存储估算
存储空间取决于你的世界大小。假设世界大小约为 304 MB:
| 配置文件 | 快照 | 日备份 | 归档 | 总计 |
|---|---|---|---|---|
| 默认 | 12 (3.6 GB) | 7 (2.1 GB) | 4 (1.2 GB) | 约 7 GB |
| 激进 | 6 (1.8 GB) | 3 (0.9 GB) | 2 (0.6 GB) | 约 3.3 GB |
| 保守 | 24 (7.3 GB) | 14 (4.3 GB) | 8 (2.4 GB) | 约 14 GB |
项目结构
src/main/
├── java/com/gfsbackup/hytale/
│ ├── GFSBackupPlugin.java # 插件生命周期
│ ├── config/
│ │ ├── BackupConfig.java # 配置 POJO
│ │ └── ConfigManager.java # JSON 加载/保存
│ ├── backup/
│ │ ├── BackupManager.java # 备份创建/恢复/删除
│ │ ├── ZipUtility.java # ZIP 压缩 + 校验和
│ │ └── HookExecutor.java # 前后钩子执行
│ ├── retention/
│ │ ├── BackupTier.java # SON/FATHER/GRANDFATHER 枚举
│ │ ├── BackupMetadata.java # 每份备份的元数据
│ │ ├── BackupIndex.java # 索引持久化
│ │ └── RetentionPolicy.java # GFS 提升 + 清理
│ ├── scheduler/
│ │ └── BackupScheduler.java # ScheduledExecutorService 定时器
│ └── web/
│ ├── WebServer.java # 嵌入式 Jetty 设置
│ └── servlets/ # REST API 处理器
└── resources/
├── manifest.json # Hytale 模组清单
├── default-config.json # 默认配置模板
└── webapp/ # Web UI (HTML/CSS/JS)
安全性
WorldKeeper 运行一个 无认证 的 HTTP 服务器。任何能够访问该端口的人都可以查看、创建、下载和删除你的备份。请谨慎对待。
让端口远离公共互联网
最重要的一点:不要将 8081 端口(或你配置的任何端口)暴露到互联网上。 你的防火墙应该阻止来自外部流量的访问。如果你需要远程访问,请使用以下方式之一:
- SSH 隧道:
ssh -L 8081:localhost:8081 user@your-server,然后在本地打开http://localhost:8081 - 带认证的反向代理:在 Nginx/Caddy 前面加上 HTTP Basic 认证或 SSO
IP 白名单
WorldKeeper 支持可选的 IP 白名单。默认情况下列表为空,这意味着所有 IP 都被允许。 如果你向列表中添加 IP,则只有这些地址可以访问 Web UI——其他所有请求都会收到 403 Forbidden 并记录警告。
要将其限制为仅本地访问:
{
"webServer": {
"allowedIPs": ["127.0.0.1"]
}
}
要允许特定 IP:
{
"webServer": {
"allowedIPs": ["127.0.0.1", "192.168.50.10"]
}
}
注意:白名单检查的是精确 IP 匹配。它不支持 CIDR 范围——请逐个列出每个 IP,或者使用反向代理来处理更复杂的规则。
如果暴露可能存在的风险
| 端点 | 风险 |
|---|---|
POST /api/backups/create |
通过备份垃圾请求耗尽磁盘空间 |
DELETE /api/backups/delete/* |
所有备份被删除 |
GET /api/backups/download/* |
世界数据被窃取 |
POST /api/backups/restore/* |
触发恢复操作(如果 allowRestore 已开启) |
建议
- 保持
allowRestore设置为false,除非你确实需要它 - 监控磁盘使用情况——即使有保留限制,快速的重复备份创建也可能在清理程序运行前填满磁盘
- 检查服务器日志中的 "Blocked request from unauthorized IP" 警告——如果你看到它们,说明有人在探测这个端口
使用 Claude Code 构建
本模组使用 Claude Code 构建。我们包含了该过程中的制品,以便你了解其过程并根据自己的项目进行调整:
- PLAN.md —— 在生成任何代码之前编写和批准的全部实施计划。一些细节在实施过程中有所变化(错误的 Java 版本、错误的 Jetty 依赖名称、未记录的插件 API 怪癖),但整体架构得以保持。
- PROMPT.md —— 一个可复用的提示词,你可以将其提供给大语言模型,为自己的游戏服务器构建类似工具,以及关于哪些方法有效、需要注意什么的提示。
技术栈
- Java 21
- Hytale 服务器 API
- 嵌入式 Jetty 12.1.4(Web 服务器)
- Gson(JSON 序列化)
- Maven 及 shade 插件(生成 Uber JAR)
许可证
MIT
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。