架构理念:为什么这么做?
之前写过一篇文章,为什么我不建议你把 AI Agent “裸奔”在家里?——一套关于安全博弈的深度复盘 ,强调要把 OpenClaw 这个强大的 Agent 封装在隔离的沙盒,只执行被批准的指令。这就引出下一个问题,我们如何给 OpenClaw 投喂资料,又如何从隔离沙盒中取出结果文件?
事实上,即使你是在裸机安装,大部分人也会把 OpenClaw 单独安装在一台干净的主机上,很少有人会疯狂到把它安装在自己的日常主机。所以裸机安装也面临同样问题——如何与 OpenClaw 交换文件。

直观的想法是配置一个双向同步的文件协议,比如我以前介绍过的别再靠微信传文件了!双向同步 + WebDAV:手把手教你打造“永不丢失”的跨平台工作流。这篇文章就是教你通过免费的 WebDAV 服务器作为桥梁,在 OpenClaw 和你的日常电脑之间建立一个即时生效的文件交换机制(最长延迟 1 分钟)。建议你按照这篇内容,先去注册一个 InfiniCLOUD 免费空间,20G 容量够大好用,并准备好 WebDAV 的用户名和应用密码(可能不同于登录密码)。
本方案采用“宿主机同步,容器透明”的方式。宿主机运行 rclone 同步引擎,负责与 WebDAV 通讯与双向同步;容器内 OpenClaw 只读写本地目录,不需要感知网络同步。通过 Docker 的 Volume 挂载,将宿主机目录映射给容器。
我们不建议直接让 OpenClaw 自己在容器内跑 WebDAV 同步。在 Docker 环境中运行 AI 助手时,直接在容器内配置 WebDAV 同步通常面临:密码泄露风险、重启后配置丢失、容器体积变大等问题。
本指南假设同步目标目录固定为 orgmode。这是作者本人的一个偏好。如果你使用不同的文件夹,把这个文件夹名字作对应修改即可。
另外,因为主机环境不同,你的设置过程和这份指南可能略有不同。最好直接把本文丢给AI,然后把你的实际情况跟AI一边聊,一边实施。
为了减少“路径与用户名”造成的复用成本,本文统一用变量表达,你只需要在自己的机器上替换这几个变量即可:
UID1000:宿主机上 UID=1000 的真实用户名(例如 opc、ubuntu、debian、ec2-user 等)LOCAL_ROOT:宿主机上 OpenClaw 数据根目录(本文用 /opt/openclaw/data)LOCAL_DIR:宿主机需要同步的目录(本文用 ${LOCAL_ROOT}/workspace/orgmode)MOUNT_DIR:容器内映射目录(本文用 /home/node/.openclaw/workspace/orgmode)REMOTE:rclone remote 名称(建议固定为 infini)
宿主机:${LOCAL_DIR}
容器内:${MOUNT_DIR}
说明:容器内用户是 node,其 UID=1000;宿主机上 UID=1000 的用户不一定叫 node。因此同步脚本应当以“宿主机 UID=1000 的真实用户”运行。这样 rclone 写入的文件 owner 为 1000,容器内的 node 才能稳定读写,不会出现权限漂移。
另外,本文会生成日志文件。请注意:日志可能包含远端 URL、remote 名称与错误细节。排障时不要把日志全文直接贴到公开场合,建议只贴必要的几行并打码。
第一步:在宿主机安装 rclone
作为 root 用户登录 VPS,执行以下安装指令:
sudo -v ; curl -fsSL https://rclone.org/install.sh | sudo bash
rclone version
which rclone
第二步:配置 WebDAV 远程连接(必须用宿主机 UID=1000 用户)
关键点:后续我们会让同步脚本以宿主机 UID=1000 用户运行,所以 rclone 的配置也必须写到这个用户的 home 目录下。不要用 root 直接跑 rclone config,否则会出现 root 能用、UID=1000 用户不能用的情况。
先确认宿主机 uid=1000 的用户名(本文用 UID1000 变量表示):
getent passwd 1000
你会看到类似输出:
opc:x:1000:100:...
其中第一段就是用户名(例如 opc)。接下来用这个用户运行配置向导(以下命令请把 opc 替换成你的 UID1000 用户名):
su -s /bin/sh -c "rclone config" opc
按照以下顺序交互:
n (New remote)
name:
infini(建议固定用这个)Storage: 输入数字选择 WebDAV
url: 填入 WebDAV 完整地址
vendor: 选 Other
user: 您的用户名
password: 选 y 并输入您的应用密码
Edit advanced config: n
Keep this remote: y
q 退出
配置完成后,用同一个用户做连通性检查:
su -s /bin/sh -c "rclone listremotes && rclone lsd infini:" opc
如果你之前已经用 root 配过 rclone,也可以把配置复制给 UID=1000 用户(只做一次):
# 把 opc 换成你的 UID1000 用户名
mkdir -p /home/opc/.config/rclone
cp /root/.config/rclone/rclone.conf /home/opc/.config/rclone/rclone.conf
chown -R opc:opc /home/opc/.config/rclone
chmod 700 /home/opc/.config/rclone
chmod 600 /home/opc/.config/rclone/rclone.conf
复制后再次验证:
su -s /bin/sh -c "rclone listremotes && rclone lsd infini:" opc
如果你发现 su -s /bin/sh -c ... 后 rclone 找不到配置,可以换成带 login 环境的方式:
su - opc -s /bin/sh -c "rclone listremotes && rclone lsd infini:"
第三步:建立本地同步基准(核心步骤 ⚠️)
在宿主机创建物理目录,并执行首次同步。
注意:bisync(双向同步)第一次运行必须使用 --resync 参数来建立两端的快照索引,否则会报错。并且这一步也必须用宿主机 UID=1000 用户执行,避免后续权限与 listing 归属混乱。
# 1) 定义目录(按需改)
LOCAL_ROOT="/opt/openclaw/data"
LOCAL_DIR="${LOCAL_ROOT}/workspace/orgmode"
# 2) 创建目录
mkdir -p "${LOCAL_DIR}"
# 3) 目录归属对齐到 UID=1000(只做一次)
chown -R 1000:1000 "${LOCAL_ROOT}"
# 4) 首次执行初始化(建立索引快照),用 UID=1000 用户执行
# 把 opc 换成你的 UID1000 用户名
su -s /bin/sh -c "rclone bisync infini: ${LOCAL_DIR} --resync -P" opc
第四步:部署自动化双向同步脚本
为了实现自动同步且防止多个同步进程冲突,我们编写一个带锁的脚本。
这里有三点必须修正,否则会踩坑:
锁文件不要放
/tmp。一旦有人用 root 手工跑过脚本,可能留下 root 拥有的锁文件,导致 UID=1000 用户后续无法清理。--compare size,modtime在不少 WebDAV 上会告警或不可靠。我们改为只用--compare size。日志文件不要写
/var/log,因为 UID=1000 用户通常没有权限写/var/log。日志放到用户可写目录最稳。
脚本如下(仍以 opc 为例;如果你的 UID=1000 用户不是 opc,需要把脚本里的 home 路径改成对应用户的 home):
cat > /opt/openclaw/sync_infini.sh <<'EOF'
#!/bin/sh
set -eu
LOCAL_ROOT="/opt/openclaw/data"
LOCAL_DIR="${LOCAL_ROOT}/workspace/orgmode"
# IMPORTANT: set this to the real HOME of the UID=1000 user (example: /home/opc)
USER_HOME="/home/opc"
CACHE_DIR="${USER_HOME}/.cache/openclaw_sync"
LOG_FILE="${CACHE_DIR}/openclaw_rclone_bisync.log"
WORKDIR="${CACHE_DIR}/rclone/bisync"
LOCK_FILE="${CACHE_DIR}/sync_infini.lock"
mkdir -p "$LOCAL_DIR" "$CACHE_DIR" "$WORKDIR"
command -v rclone >/dev/null 2>&1 || { echo "[ERROR] rclone not found" >> "$LOG_FILE"; exit 1; }
RCLONE_CMD='rclone bisync infini:/ '"$LOCAL_DIR"' \
--workdir '"$WORKDIR"' \
--recover \
--compare size \
--create-empty-src-dirs \
--no-slow-hash \
--timeout 30s \
--contimeout 10s \
--retries 3 \
--low-level-retries 10 \
--log-file '"$LOG_FILE"' \
--log-level INFO'
if command -v flock >/dev/null 2>&1; then
# Use flock to avoid overlap; if already locked, exit quietly.
flock -n "$LOCK_FILE" sh -c "$RCLONE_CMD" || exit 0
else
# Fallback to PID logic if flock not available
PID_FILE="${CACHE_DIR}/sync_infini.pid"
if [ -f "$PID_FILE" ]; then
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
if [ -n "${pid:-}" ] && ps -p "$pid" >/dev/null 2>&1; then
exit 0
fi
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT
sh -c "$RCLONE_CMD"
fi
EOF
chmod 755 /opt/openclaw/sync_infini.sh
注意:脚本里 USER_HOME="/home/opc" 这行必须改成你的 UID=1000 用户 home 目录。
先手动用 UID=1000 用户跑一次验证:
# 把 opc 换成你的 UID1000 用户名
su -s /bin/sh -c "/opt/openclaw/sync_infini.sh" opc
tail -n 60 /home/opc/.cache/openclaw_sync/openclaw_rclone_bisync.log
看到 Bisync successful 基本就说明脚本与权限没问题。
每 24 小时做一次验证。万一某次同步错误,确保最多 24 小时后也会恢复正常,所以还需要一个修复版 sync_infini_resync.sh:
cat > /opt/openclaw/sync_infini_resync.sh <<'EOF'
#!/bin/sh
set -eu
LOCAL_ROOT="/opt/openclaw/data"
LOCAL_DIR="${LOCAL_ROOT}/workspace/orgmode"
USER_HOME="/home/opc"
CACHE_DIR="${USER_HOME}/.cache/openclaw_sync"
LOG_FILE="${CACHE_DIR}/openclaw_rclone_bisync_resync.log"
WORKDIR="${CACHE_DIR}/rclone/bisync"
LOCK_FILE="${CACHE_DIR}/sync_infini.lock"
mkdir -p "$LOCAL_DIR" "$CACHE_DIR" "$WORKDIR"
command -v rclone >/dev/null 2>&1 || { echo "[ERROR] rclone not found" >> "$LOG_FILE"; exit 1; }
RCLONE_CMD='rclone bisync infini:/ '"$LOCAL_DIR"' \
--workdir '"$WORKDIR"' \
--resync \
--compare size \
--create-empty-src-dirs \
--no-slow-hash \
--timeout 30s \
--contimeout 10s \
--retries 3 \
--low-level-retries 10 \
--log-file '"$LOG_FILE"' \
--log-level INFO'
if command -v flock >/dev/null 2>&1; then
flock -n "$LOCK_FILE" sh -c "$RCLONE_CMD" || exit 0
else
PID_FILE="${CACHE_DIR}/sync_infini.pid"
if [ -f "$PID_FILE" ]; then
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
if [ -n "${pid:-}" ] && ps -p "$pid" >/dev/null 2>&1; then
exit 0
fi
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT
sh -c "$RCLONE_CMD"
fi
EOF
chmod 755 /opt/openclaw/sync_infini_resync.sh
测试:
su -s /bin/sh -c "/opt/openclaw/sync_infini_resync.sh" opc
tail -n 60 /home/opc/.cache/openclaw_sync/openclaw_rclone_bisync_resync.log
将脚本加入定时任务。注意:这里不再用 root 的 crontab,而是写入 UID=1000 用户的 crontab(因为它就是后续同步的真实执行者)。
su -s /bin/sh -c '(crontab -l 2>/dev/null; echo "* * * * * /opt/openclaw/sync_infini.sh") | crontab -' opc
su -s /bin/sh -c '(crontab -l 2>/dev/null; echo "5 4 * * * /opt/openclaw/sync_infini_resync.sh") | crontab -' opc
su -s /bin/sh -c 'crontab -l' opc
同时建议确认 root 没有同步任务,避免两套同步同时跑:
crontab -l
第五步:修改 Docker 配置进行关联
修改您的 docker-compose.yml 文件,在 volumes 下增加挂载点。这里建议使用绝对路径,避免 ./data 因为 compose 所在目录不同而指向错误位置。
推荐写法如下:
services:
openclaw:
build: .
image: ghcr.io/openclaw/openclaw:latest
container_name: openclaw
restart: always
env_file: .env
volumes:
- /opt/openclaw/data:/home/node/.openclaw
使用 Docker Compose 重新拉起:
docker compose down
docker compose up -d
可选验证(确认容器内 uid=1000 并且目录存在):
docker exec -it openclaw sh -lc 'id; ls -ld /home/node/.openclaw/workspace/orgmode'
第六步:权限修正(终极避坑)
在本方案中,只要满足下面两点,就不需要反复 chown:
${LOCAL_ROOT}在宿主机上归属为 UID=1000rclone 同步脚本由该 UID=1000 用户执行(我们已经通过它的 crontab 实现)
如果你需要一次性修正权限,执行:
chown -R 1000:1000 /opt/openclaw/data
不要对目录递归 chmod -R 755,这会改变大量文件的权限语义;通常只需要正确的属主即可。
验收标准
下面两条命令可以快速验证“权限与同步闭环”已经通了。
第一,检查宿主机目录里新文件 owner 是否为 1000:
ls -ln /opt/openclaw/data/workspace/orgmode | head
第二,在容器里用 node 身份写一个文件,确认能写入宿主机挂载目录:
docker exec -u 1000:1000 -it openclaw sh -lc 'touch /home/node/.openclaw/workspace/orgmode/_from_openclaw && ls -ln /home/node/.openclaw/workspace/orgmode/_from_openclaw'
常见问题排查 (Troubleshooting)
错误:cannot find prior Path1 or Path2 listings
原因:首次运行 bisync 没有用 --resync,或者你更换了本地目录导致旧 listing 不匹配。
解决:用 UID=1000 用户对目标目录重新 resync:
su -s /bin/sh -c "rclone bisync infini: /opt/openclaw/data/workspace/orgmode --resync -P" opc
文件不同步:
先看日志是否每分钟追加:
tail -n 80 /home/opc/.cache/openclaw_sync/openclaw_rclone_bisync.log
确认定时任务是否存在:
su -s /bin/sh -c "crontab -l" opc
如果日志时间比你本地时间差一小时,通常是 VPS 系统时区为 UTC,这不影响同步功能。
总结:如何使用?
您想给 AI 发文件:把文件丢进 WebDAV 同步盘,最多 1 分钟内就会出现在 AI 的 orgmode 目录。
AI 给您发文章:AI 写在 orgmode 里,最多 1 分钟内您的设备就会收到同步结果。
这套系统一旦配好,维护成本很低,容器重启也不会影响同步。
另外,可能有人会问,用syncthing是不是更简单一些?用于OpenClaw这个项目,其实WebDAV更合适。
第一,内网与外网 Syncthing 往往绕不开端口与网络策略,这对普通用户其实是更麻烦,攻击面也更广的问题。WebDAV完全没有这个问题。
第二,只有两点同步,Syncthing才比较合适。如果涉及多台电脑,手机,平板之间的同步,有一个中心的WebDAV比完全点对点的Syncthing更能保持一致性。
第三,可能也是更重要的,大部分手机端App只支持WebDAV这种同步方式。举个例子,先前我推荐过用OpenClaw管理安排日程,OpenClaw应用之:你的人生规划师—Orgmode + WebDAV + Orgzly 。安卓端Orgzly就只支持WebDAV。如果使用Syncthing 则失去这种能力。还有大量其它手机APP与OpenClaw的文件交换都如此。
第四,Syncthing 的配置其实也不会比WebDAV简化多少。同样要考虑的是宿主机同步,然后映射进入OpenClaw。
综合看,还是WebDAV是唯一合适的。