Repository navigation
Releases
v1.20.27
Full Changelog: v1.20.26...v1.20.27
v1.20.26
Full Changelog: v1.20.25...v1.20.26
v1.20.25
Full Changelog: v1.20.24...v1.20.25
v1.20.24
Full Changelog: v1.20.23...v1.20.24
v1.20.23
Full Changelog: v1.20.22...v1.20.23
v1.20.22
Full Changelog: v1.20.21...v1.20.22
v1.20.21 - Keepalives and resumable transfers
CLICD v1.20.21:远端传输加固——保活 + 断点续传 + 幂等重跑。
🔁 问题
上传是 cat > 文件:连接一断就从零重来、无保活、无重试。大快照同步长期失败(EOF),每次重跑都要再传几十 GB。
修复
- 保活:TCP keepalive(30s)+ SSH 层
keepalive@openssh.com(20s); - 断点续传:重试时从远端已有字节数继续(上传
cat >>、下载tail -c +N),重试 4 次、退避 5/15/45s; - 前缀校验:只比大小会把"同尺寸的不同文件"误判为已完成(实测抓到),现续传/跳过前比对双方前 64KB 的 MD5;
- ≤1MB 小文件一律重写:
snapshot-meta.json这类重新生成的文件尺寸可能不变; - 幂等:已完整的文件再同步直接跳过——重跑同步从"再传 50GB"变成"只补没传完的"。
实测(真 SFTP)
1.5GB 首传 16.35s MD5 一致;远端截断到 500MB 后重传 → 续传 1036MB 且 MD5 完全一致;重复上传 547ms 秒回;下载续传 MD5 一致。
Full Changelog: v1.20.20...v1.20.21
v1.20.20 - Delete remote copies with the local snapshot
CLICD v1.20.20:删除本地快照/备份时同步删除远端副本。
🗑️ 问题
本地删除后远端副本原封不动,池里积压大量孤儿:容器 3 远端 12 个目录而本地只剩 2 个、snapshots/6/(容器已删)、backups/8/ 无人能辨认——本次实测清理出 21 个孤儿、释放约 20GB。
实现
StorageClient.DeletePath递归删除并返回"本来是否存在"(区分"真删了"与"从没传上去"):SFTPrm -rf、WebDAV DELETE 集合、MinIO/S3 按前缀列举后逐个删;- 候选路径策略:覆盖「记录路径 + 新命名 + 旧数字命名」——本机 18 个快照的
remote_path全为空,只认记录会全部漏掉; - 空父目录逐级回收;删除为尽力而为,远端失败只记日志不影响本地删除。
实测(真 SFTP)
上传 → 删除 → 目录消失且空父目录回收;重复删除正确识别为不存在;伪造的传统路径孤儿同样被清除。
Full Changelog: v1.20.19...v1.20.20
v1.20.19 - Self-describing remote backups
CLICD v1.20.19:远端备份自描述——来源服务器 + 实例名 + meta.json。
🗂️ 问题
远端目录是 snapshots/<容器数字ID>/<快照ID>:分不清哪台实例、分不清来自哪台母鸡;多台 CLICD 共用远端池会互相混写;容器删除后留下无法辨认的孤儿(实测池里就有容器 6 的孤儿)。
新命名
snapshots/<来源服务器>/<实例名>/<快照ID>/(备份同理):
- 来源服务器自动取出口公网 IPv4(可用环境变量
CLICD_SOURCE_HOST_ID覆盖),回退主机名; - 实例名做安全清洗,纯非 ASCII 名回退
unnamed-<哈希>; - 旧快照完全兼容:恢复读取持久化的
remote_path,不重算路径。
snapshot-meta.json
随快照一起上传:来源服务器、实例 ID/名、快照备注、创建时间/人、大小、CLICD 版本——面板数据库丢了,远端每个目录也能自证身份。
Full Changelog: v1.20.18...v1.20.19
v1.20.18 - Rate limit the panel entry gate
CLICD v1.20.18:入口门禁加速率限制——穷举秘密路径从 0.6 小时变成 45 年。
🛡️ 背景
门禁的 302-vs-404 差异本身就是命中判定器,且没有速率限制:实测本机 5175 req/s,5 位小写前缀 0.6 小时即可穷举。
规则
- 同 IP 每分钟 ≤30 次被拒请求、10 分钟 ≤100 次;
- 超限封禁 1 小时,期间未认证请求(含敲门路径)一律 403;
- 只统计被门禁拒绝的请求:已登录、敲门动作、带敲门 cookie 的请求都不计数,正常用户不可能触发;
- 封禁写审计
security.entry_ban+ 服务日志;状态在内存中,重启即清空; - 按
RemoteAddr计数,刻意不信任 X-Forwarded-For(攻击者可控)。
实测
连发 35 次错误前缀:第 1–29 次 404、第 30 次起 403;封禁期间敲门路径也 403;另一 IP 敲门不受影响;重启后恢复。单测(注入时钟)覆盖双窗口触发、封禁过期重计数、IP 隔离、窗口滑出。
Full Changelog: v1.20.17...v1.20.18