最近折腾服务器的时候,我重新认真思考了一遍备份这件事。
事情的起因其实很简单。
2026 年 10 月 1 日,InfiniCLOUD 的 zeze 节点发生故障。公告地址:https://infini-cloud.net/en/news_20261001.html
我原本放在 InfiniCLOUD 里的数据,随着这次故障全部失去了访问能力。
InfiniCLOUD 官方最初公告显示,zeze 节点自 10 月 1 日 1:53(日本时间)起发生故障,受到影响的用户无法通过文件浏览器以及外部应用访问文件。到了 10 月 3 日,官方进一步说明,目标服务器存在多块存储盘之间的数据严重不一致,情况已经超过预设阈值,存储区域数据无法取回的可能性正在增加。由于如果继续在原环境中等待数据抢救,服务恢复可能需要数月,因此官方决定准备新的服务器和数据区域,并在迁移后继续并行进行数据抢救。
云存储可以用来存东西,但不要把云端存了一份直接等同于已经完成备份。
这次我没有再去找一个功能复杂的网盘,而是决定自己搭一个非常简单的 WebDAV 存储服务。
我的需求很明确:
给几个轻量服务器保存配置文件、数据库和服务数据;
支持标准 WebDAV,可以直接挂载或者通过程序上传;
Docker 部署,方便维护;
不希望额外开放一个公网端口;
有基础的账号密码认证;
再配合 Fail2ban,防止暴力破解;
整体尽量简单,搭好之后就不再折腾。
最终选择的是 hacdias/webdav 。
一、创建 WebDAV 目录
首先创建工作目录:
mkdir -p /opt/webdav/data
cd /opt/webdav最终结构:
/opt/webdav/
├── docker-compose.yml
├── config.yml
└── data/
其中:
docker-compose.yml
负责 Docker 服务。
config.yml
负责 WebDAV 配置。
data/
则是真正存放备份文件的地方。
二、使用 Docker 部署
创建 Compose 文件:
写入:
services:
webdav:
image: ghcr.io/hacdias/webdav:latest
container_name: webdav
restart: unless-stopped
ports:
- "127.0.0.1:6065:6065"
volumes:
- ./config.yml:/config.yml:ro
- ./data:/data
command: ["-c", "/config.yml"]
logging:
driver: journald启动:
cd /opt/webdav
docker compose up -d查看:
docker ps查看日志:
docker logs webdav同时检查 journald:
journalctl CONTAINER_NAME=webdav -n 30 --no-pager三、配置 WebDAV
创建:
nano /opt/webdav/config.yml写入:
address: 0.0.0.0
port: 6065
tls: false
prefix: /
debug: false
directory: /data
permissions: CRUD
behindProxy: true
users:
- username: backup
password: "这里填写一个高强度随机密码"
directory: /data
permissions: CRUD
log:
format: json
colors: false
outputs:
- stderr四、1Panel 配置反向代理
接下来在 1Panel 中创建网站。
域名:
dav.example.com反向代理目标:
http://127.0.0.1:6065然后申请 HTTPS 证书。
最终访问:
https://dav.example.com/整个过程中,WebDAV 本身都不需要直接面对公网。
五、给 WebDAV 加上 Fail2ban
WebDAV 本身有账号密码认证,那么暴力破解自然也需要考虑。
这里直接使用 Fail2ban。
创建过滤器:
nano /etc/fail2ban/filter.d/webdav.conf写入:
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*invalid password\s*\{.*"remote_address":\s*"<HOST>:\d+"\s*\}
^.*invalid username\s*\{.*"remote_address":\s*"<HOST>:\d+"\s*\}
ignoreregex =然后创建 Jail:
nano /etc/fail2ban/jail.d/webdav.local写入:
[webdav]
enabled = true
filter = webdav
journalmatch = CONTAINER_NAME=webdav
maxretry = 5
findtime = 600
bantime = 604800
banaction = nftables[type=allports]
ignoreip = 127.0.0.1/8 ::1
backend = systemd这套配置的意思是:
10 分钟内失败 5 次
↓
触发封禁
↓
封 7 天官方项目同样提供了 Docker + journald + Fail2ban 的配置思路。
六、检查 Fail2ban
修改完配置后,先测试:
fail2ban-client -t确认没有错误后:
systemctl restart fail2ban然后:
systemctl status fail2ban --no-pager最后:
fail2ban-client status webdav正常情况下会看到:
Status for the jail: webdav
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- Journal matches: CONTAINER_NAME=webdav
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:其中:
Journal matches: CONTAINER_NAME=webdav非常关键。
这说明 Fail2ban 已经成功监控到了 WebDAV Docker 容器的日志。
七、实际测试一次
部署完成后,可以故意输入错误密码几次进行测试。
访问:
https://dav.example.com/故意输入错误密码。
然后查看:
journalctl CONTAINER_NAME=webdav -n 50 --no-pager应该能看到:
invalid password以及客户端 IP。
再执行:
fail2ban-client status webdav确认失败次数已经被 Fail2ban 统计。
如果触发封禁,也可以手动解封:
fail2ban-client set webdav unbanip 你的公网IP测试完成后,这部分基本就不用再动了。
八、最后
这次折腾 WebDAV,说到底并不是因为 WebDAV 有多么高级。
它甚至可以说是一个很普通、很简单的工具。
但我现在更在意的是:
数据在哪里?
有没有第二份?
第二份和第一份是不是分开的?
真正出问题的时候能不能恢复?InfiniCLOUD 这次 zeze 节点故障,让我重新意识到:
“能访问”不等于“安全”,“存了一份”更不等于“有备份”。
所以这次干脆自己搭一个简单的 WebDAV 备份仓库。
至少从现在开始,我的重要服务数据不会再只依赖单一存储。