OneDrive Linux 客户端部署教程
OneDrive Linux 客户端部署教程(abraunegg/onedrive)
[!NOTE]
本教程基于 2026-08-02 在 AWSaws-sg-t4g(Ubuntu 24.04 ARM64)VPS 上的实际部署过程整理,覆盖编译安装、配置、两种运行方案、定时脚本、推送通知、常见坑与排错。脱敏说明:文中的服务器 IP 已做隐私处理,统一用
<SERVER_A_IP>/<SERVER_B_IP>占位表示。颜色说明:■ 红色 = 危险 / 错误 | ■ 橙色 = 警告 | ■ 绿色 = 成功 / 推荐 | ■ 蓝色 = 提示 / 命令
1. 架构总览
┌─────────────────────┐ scp tar.gz ┌──────────────────────────┐ upload-only ┌─────────────┐
│ Server A │ ───────────▶ │ Server B(本教程主角) │ ────────────▶ │ OneDrive 云端│
│ (数据源机) │ │ (中转 + 上传端) │ onedrive CLI │ (ustc.edu) │
└─────────────────────┘ └──────────────────────────┘ └─────────────┘
- Server A(
<SERVER_A_IP>):数据源。把/root/data/docker_data打包成 tar.gz,scp 推送到 Server B - Server B(
<SERVER_B_IP>,ssh aws-sg-t4g):中转 + 上传端。接收备份 → 每来源 IP 保留最新 2 份 → 每天 05:00 定时上传 OneDrive - OneDrive 账号根目录结构:
Apps/ Attachments/ backup/ npm/ oci-aws/ oci-start-docker/(其中Apps、Attachments是 Mac 端账号自带的空文件夹)
2. 环境信息
| 项目 | 值 |
|---|---|
| 系统 | Ubuntu 24.04.4 LTS |
| 架构 | arm64(AWS t4g) |
| 内存 | 1.8 GiB + 2 GiB swap |
| SSH 别名 | aws-sg-t4g → root@<SERVER_B_IP> |
| 客户端版本 | onedrive v2.5.11-6-gac3f042(master 源码编译) |
| 同步目录 | /root/data |
| 白名单 | backup/、npm/、oci-aws/、oci-start-docker/ |
3. 客户端编译安装
3.1 安装编译依赖(Debian/Ubuntu ARM64)
sudo apt update
sudo apt install -y build-essential libcurl4-openssl-dev libsqlite3-dev \
pkg-config git curl systemd-dev libdbus-1-dev ldc
[!WARNING]
ARM64 建议用发行版自带的ldc编译器(保证一致性)。编译需要约 1GB 内存 + 1GB swap,内存不足时ldc2会被 OOM killer 干掉(本机实测发生过)。
3.2 从源码编译安装
git clone https://github.com/abraunegg/onedrive.git
cd onedrive
./configure
make
sudo make install
验证:
onedrive --version
# onedrive v2.5.11-6-gac3f042
3.3 授权登录
onedrive --auth-uri
- 用浏览器打开输出的授权链接,登录微软账号并同意
- 把授权后浏览器跳转的完整 URL 粘贴回终端
- 成功后生成
~/.config/onedrive/refresh_token,即授权完成
4. 配置
4.1 主配置 ~/.config/onedrive/config
# 核心配置
sync_dir = "/root/data"
skip_dotfiles = "true"
# 性能优化:匹配你的单核 VPS,防止由于线程过多导致的不稳定
threads = "1"
| 参数 | 说明 |
|---|---|
sync_dir | 本地同步目录。关键:它永远对应 OneDrive 账号根目录,不是云端子目录 |
skip_dotfiles | 跳过 . 开头的文件 |
threads | 并发线程数,小内存 VPS 建议 1 |
4.2 sync_list 白名单(推荐)
文件位置:~/.config/onedrive/sync_list
backup/
npm/
oci-aws/
oci-start-docker/
- 每行一个相对
sync_dir的路径,目录带/结尾 - 文件存在即生效,不在白名单内的内容完全忽略(例如账号里 Mac 端的
Apps/、Attachments/不会被同步) - 修改 sync_list 后需要跑一次
--resync,否则客户端报 126
4.3 必须理解的概念
[!IMPORTANT]
sync_dir永远映射 OneDrive 账号根目录:把它指向本地子目录(如/root/data/backup)并不会"只同步云端 backup/",而是把整个账号镜像进该目录。正确做法是保持sync_dir = "/root/data",再用sync_list或--single-directory 'backup'限定范围。
- 状态文件(都在
~/.config/onedrive/):items.sqlite3:本地同步数据库(记录每个文件的状态).config.hash/.config.backup:配置快照(用于检测配置变更).sync_list.hash:白名单快照- 删数据库时若不同时清掉这几个 hash 快照文件,客户端仍会判定"配置变更 → 要求 resync"
- 配置/白名单变更:客户端用退出码 126 表示"需要
--resync"。
5. 常用命令
onedrive --sync # 一次性同步(双向)
onedrive --sync --upload-only # 一次性只上传,不下载
onedrive --monitor # 常驻监控(双向、实时)
onedrive --sync --single-directory 'backup' --upload-only # 只同步 backup/ 目录
onedrive --resync --sync # 重建数据库后全量同步(会交互确认)
onedrive --display-config # 显示生效配置
onedrive --display-sync-status # 查询云端待同步状态
onedrive --version # 版本
[!WARNING]
本版本(v2.5.x)的参数是--sync,不存在--synchronize。旧文档里的--synchronize会直接报Unrecognized option并退出,同步不会执行。
6. 方案选择:定时脚本 vs 常驻监控
| 对比项 | 常驻监控(--monitor) | 定时脚本(cron + --sync --upload-only) |
|---|---|---|
| 运行方式 | 常驻内存,开机自启、崩溃自动重启 | 到点跑一次,跑完退出 |
| 同步方向 | 双向,实时 | 只上传,不拉取云端变化 |
| 资源占用 | 约 30–190 MB 常驻 | 几乎为零 |
| 通知 | 无内建 Telegram 推送 | 可带成功/失败状态推送 |
| 失败处理 | systemd 自动重启 | 等下次触发 |
| 适合场景 | 需要频繁双向同步 | 单向备份(本场景) |
[!TIP]
本项目选择:定时脚本方案。原因:备份是凌晨生成的一次性大文件,不需要实时双向同步;定时上传 + 推送通知更省资源、更可控。
6.1 若选择常驻监控(参考)
# 安装用户级 systemd 服务
mkdir -p ~/.config/systemd/user
cp /root/onedrive/contrib/systemd/onedrive.service ~/.config/systemd/user/
loginctl enable-linger root
export XDG_RUNTIME_DIR=/run/user/0
systemctl --user daemon-reload
systemctl --user enable --now onedrive
# 停用 / 禁用
systemctl --user stop onedrive
systemctl --user disable onedrive
注意:
onedrive@.service(系统级模板)把配置目录硬编码为/home/%i/.config/onedrive,不适用于 root(root 家目录是/root),所以本项目使用用户级onedrive.service。
7. 定时脚本部署(Server B)
7.1 同步脚本 /root/onedrivebk.sh
#!/bin/bash
# OneDrive 定时备份同步脚本(每天 05:00 由 cron 执行)
LOG="/var/log/onedrivebk.log"
cd /root
echo "===== $(date "+%F %T") sync start =====" >> "$LOG"
/usr/local/bin/onedrive --sync --upload-only >> "$LOG" 2>&1
SYNC_EXIT=$?
echo "===== $(date "+%F %T") sync end (exit=$SYNC_EXIT) =====" >> "$LOG"
if [ "$SYNC_EXIT" -eq 0 ]; then
MSG="🎉🎉 onedrive 云数据备份成功 🎉🎉"
else
MSG="☹️☹️ OneDrive 云数据备份失败 (exit=${SYNC_EXIT}) ☹️☹️"
fi
chmod +x /root/tgMessagePush.sh && /root/tgMessagePush.sh "$MSG"
exit $SYNC_EXIT
功能:
- 增量上传:只上传新增/修改的本地文件,未变的跳过
- 本地删除的文件会传播到云端(upload-only 也包含删除同步)
- 日志写入
/var/log/onedrivebk.log,带起止时间和退出码 - 按退出码推送
🎉🎉 onedrive 云数据备份成功 🎉或☹️☹️ OneDrive 云数据备份失败 (exit=126) ☹️☹️到手机
7.2 推送脚本 /root/tgMessagePush.sh
支持自定义消息文本(./tgMessagePush.sh "文案"),不传参时使用 config.conf 里的 messageText;同时发 Bark + Telegram,均已正确做 URL 编码(中文/emoji/括号均可发送)。
#!/bin/bash
# 发送 Telegram / Bark 推送通知
# 用法: ./tgMessagePush.sh ["自定义消息文本"] (不传参数时使用 config.conf 里的 messageText)
# 从配置文件读取 barkApi、telegramBotToken、telegramBotUserId
cd "$(dirname "$0")"
config_file="config.conf"
barkApi=$(awk -F "=" "/barkApi/ {gsub(/^[ \t]+|[ \t]+\$/, \"\", \$2); print \$2}" "$config_file")
configMessage=$(awk -F "=" "/messageText/ {gsub(/^[ \t]+|[ \t]+\$/, \"\", \$2); print \$2}" "$config_file")
telegramBotToken=$(awk -F "=" "/telegramBotToken/ {gsub(/^[ \t]+|[ \t]+\$/, \"\", \$2); print \$2}" "$config_file")
telegramBotUserId=$(awk -F "=" "/telegramBotUserId/ {gsub(/^[ \t]+|[ \t]+\$/, \"\", \$2); print \$2}" "$config_file")
# 优先使用传入参数作为消息文本
messageText="${1:-$configMessage}"
# --- Bark 推送(路径式:/Key/OneDrive/正文,正文做 URL 编码)---
if [ -n "$barkApi" ]; then
encodedMsg=$(printf "%s" "$messageText" | jq -sRr @uri)
response=$(curl -sS "https://bark.zszweb.top/${barkApi}/OneDrive/${encodedMsg}?group=OneDrive&autoCopy=1&isArchive=1&sound=shake&level=timeSensitive&icon=https%3A%2F%2Fraw.githubusercontent.com%2FNodewebzsz%2Ftool%2Fmain%2FIconSet%2FColor%2B%2FOneDrive_1.png")
code=$(printf "%s" "$response" | jq -r ".code // empty" 2>/dev/null)
if [ "$code" = "200" ]; then
echo "bark 推送成功"
else
echo "bark 推送失败,请检查 bark 机器人 bark_api (response: ${response})"
fi
else
echo "未配置 bark 推送"
fi
# --- Telegram 推送 ---
if [ -n "$telegramBotToken" ]; then
response=$(curl -s -o /dev/null -w "%{http_code}" -X POST "https://api.telegram.org/bot${telegramBotToken}/sendMessage" \
--data-urlencode "chat_id=${telegramBotUserId}" \
--data-urlencode "parse_mode=HTML" \
--data-urlencode "text=${messageText}")
if [ "$response" = "200" ]; then
echo "Telegram 推送成功"
else
echo "Telegram 推送失败,请检查 Telegram 机器人 token 和 ID"
fi
else
echo "未配置 Telegram 推送"
fi
配置文件 /root/config.conf 需要包含以下键(值换成你自己的):
[bark]
barkApi=你的Bark设备Key
[telegram]
telegramBotToken=你的Telegram Bot Token
telegramBotUserId=你的Telegram用户ID
[message]
messageText=默认消息文案
7.3 crontab(每天 05:00)
0 5 * * * /root/onedrivebk.sh >> /var/log/onedrivebk.log 2>&1
# 添加(幂等写法)
(crontab -l 2>/dev/null | grep -v "onedrivebk.sh"; echo "0 5 * * * /root/onedrivebk.sh >> /var/log/onedrivebk.log 2>&1") | crontab -
设计理由:
- 05:00:避开 Server A 凌晨推送备份的时段,防止两个 onedrive 实例抢数据库锁
- 输出重定向到日志:cron 默认把输出发到 root 邮箱(基本没人看),落盘方便排查
7.4 logrotate 防止日志无限增长
/etc/logrotate.d/onedrivebk:
/var/log/onedrivebk.log {
daily
rotate 14
compress
missingok
notifempty
copytruncate
}
每天轮转一次,保留最近 14 份,旧的自动 gzip 压缩。
8. Server A 推送脚本(数据源侧,参考)
在被备份机 Server A 上运行的脚本(打包 → 传输 → 远程触发上传):
#!/bin/bash
# --- 配置区 ---
SRC_DIR="/root/data/docker_data"
DST_DIR="/root/data/backup"
SERVER_A_IP="161.118.255.194"
SERVER_B_IP="13.250.172.154"
SSH_USER="root"
SSH_PORT="22"
BACKUP_NAME_PREFIX="docker_data_backup_${SERVER_A_IP}"
ARCHIVE_FORMAT="tar.gz"
SRC_HOST="sg-arm-24g"
LOG_FILE="/var/log/backup.log"
# --- 1. 执行打包 ---
current_date=$(date +"%Y%m%d_%H%M%S")
backup_filename="${BACKUP_NAME_PREFIX}_${current_date}.${ARCHIVE_FORMAT}"
cd $(dirname $SRC_DIR) # 进入父目录以保证打包路径正确
tar -czf "/tmp/${backup_filename}" -C "${SRC_DIR}" .
# 配置免密登录
# ssh-copy-id "${SSH_USER}@${SERVER_B_IP}"
# --- 2. 传输到 B 服务器的/root/data/backup文件夹下---
scp -P "${SSH_PORT}" "/tmp/${backup_filename}" "${SSH_USER}@${SERVER_B_IP}:${DST_DIR}/"
rm -f "/tmp/${backup_filename}"
# --- 3. 远程触发 B 服务器的清理与同步 ---
# 加入防断连
# 注意:这里 tail -n +3 表示保留最新的 2 个文件
ssh -p "${SSH_PORT}" "${SSH_USER}@${SERVER_B_IP}" \
"find ${DST_DIR} -type f -name 'docker_data_backup_*_*.${ARCHIVE_FORMAT}' | \
sed 's/.*docker_data_backup_\([0-9.]*\)_.*/\1/' | \
sort | uniq | \
while read -r ip; do \
ls -t ${DST_DIR}/docker_data_backup_\"\$ip\"_*.${ARCHIVE_FORMAT} 2>/dev/null | tail -n +3 | xargs --no-run-if-empty rm -f; \
done && onedrive --sync --single-directory 'backup' --upload-only"
rc=$?
# --- 4. 推送完成通知(成功才推送)---
if [ "${rc}" -eq 0 ]; then
message="✅ [$(date '+%Y-%m-%d %H:%M:%S')] ${SRC_HOST} (${SERVER_A_IP}) 备份完成,数据已同步到 OneDrive 中转服务器 (${SERVER_B_IP})"
ssh -o ConnectTimeout=20 -o BatchMode=yes "${SSH_USER}@${SERVER_B_IP}" "/root/tgMessagePush.sh \"${message}\"" >> "${LOG_FILE}" 2>&1
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 备份同步失败,exit=${rc}" >> "${LOG_FILE}"
fi
exit "${rc}"
职责:
- 打包 Server A 的
/root/data/docker_data - scp 推送到 Server B 的
/root/data/backup/ - 远程在 B 机上:对每个来源 IP 只保留最新 2 个 tar.gz,然后触发
--single-directory 'backup' --upload-only上传
[!CAUTION]
B 机清理旧备份后,上传同步会把本地删除传播到云端——所以云端每个服务器的备份同样只保留最新 2 份。如需更长的云端保留期,需调整清理逻辑(例如把tail -n +3改为更大的数字)。
9. 常见坑与排错
| 现象 | 原因 | 处理 |
|---|---|---|
Unrecognized option --synchronize | 参数名错误 | 改用 --sync |
退出码 126,日志提示 --resync is required | 配置或 sync_list 变更 | 删 ~/.config/onedrive/ 下 .config.hash、.config.backup、items.sqlite3 后重跑;或执行 onedrive --resync --sync |
| 两个实例互相报错/抢锁 | 同时跑 monitor 和 cron 脚本 | 错开时间,只保留一个方案 |
Skipping item - invalid name (Microsoft Naming Convention) | 文件名含冒号 : 等微软禁用字符 | 正常跳过,本地文件不受影响 |
inotify_add_watch failed ... Permission denied | Docker 容器用户(uid 1001)目录权限问题 | 已改用 cron 方案规避;如必须监控,需处理目录权限 |
| curl HTTP/2 版本警告 | libcurl 8.5.0 已知 bug | 客户端自动降级 HTTP/1.1,无影响 |
Online file integrity failure | 上传校验失败 | 客户端自动按 modified 重新上传,无影响 |
| 手动删了本地文件,云端文件也消失 | upload-only 同样传播本地删除 | 符合预期,注意这是单向备份的设计 |
--resync 交互提示 | 官方安全确认 | 输入 Y 继续(会重建本地数据库) |
10. 验证清单
onedrive --version
# onedrive v2.5.11-6-gac3f042
onedrive --display-config
# sync_dir = "/root/data",threads = "1"
cat /root/.config/onedrive/sync_list
# backup/
# npm/
# oci-aws/
# oci-start-docker/
crontab -l
# 0 5 * * * /root/onedrivebk.sh >> /var/log/onedrivebk.log 2>&1
tail -5 /var/log/onedrivebk.log
# ===== 2026-08-02 19:41:00 sync end (exit=0) =====
export XDG_RUNTIME_DIR=/run/user/0
systemctl --user status onedrive
# inactive / disabled(监控服务已停用,不冲突)
手动跑一次完整流程:
cd /root && ./onedrivebk.sh
预期:Bark 推送成功 + Telegram 推送成功,手机收到 🎉🎉 onedrive 云数据备份成功 🎉🎉。
11. 安全注意事项
[!WARNING]
refresh_token、Telegram Bot Token、Bark Key 都是敏感凭据,严禁外传或进入代码库。
~/.config/onedrive/refresh_token等同于账号凭据,权限保持600,不要外传、不要进代码库/root/config.conf中的 Telegram Bot Token、Bark Key 同样敏感- 不要把任何云端凭据放进前端代码或
NEXT_PUBLIC_环境变量;需要管理员权限的操作必须在服务端完成 - 修改任何脚本前先
cp备份,避免操作失误影响正在运行的定时任务
附:本部署的时间线(供排查参考)
| 时间(CST) | 事件 |
|---|---|
| 15:17–15:19 | 系统重启,Docker 容器恢复,oci-start/watchtower 停止 |
| 15:22–15:23 | ldc2(D 编译器)编译时 OOM 被内核杀死 |
| 17:03 | onedrive v2.5.11 编译完成 |
| 17:13 / 17:28 | 配置创建 / 授权完成(refresh_token) |
| 17:40 | 首次 --sync,下载 4 个云端备份 |
| 17:47 | sync_dir 被改为 /root/data/backup(触发后续 resync 风波) |
| 17:50 | 错误方向的 --resync,把整个账号镜像进 backup/ |
| 17:54 | 监控服务启动,出现 EACCES 与误删 |
| 18:00 | sync_dir 改回 /root/data |
| 19:00–19:40 | 清理现场、重建数据库、加 sync_list、配置 crontab、logrotate、状态推送 |