Cloudflare R2 基于 AWS S3 兼容协议构建,其最大的优势在于零外网流出费用(Zero Egress Fees)。通过 FUSE(Filesystem in Userspace)与 rclone 工具,我们可以将 R2 的 Bucket 挂载为 Debian 13 本地目录,像操作普通磁盘一样读写文件,非常适合冷数据备份、静态资源托管与日志归档等场景。

本文记录在 Debian 13 环境下从获取凭据、配置 rclone、排查典型权限/路径报错,到实现 systemd 开机自启守护挂载的完整流程。

1. 准备工作:获取 Cloudflare R2 凭据

在挂载之前,需要获取 R2 的 S3 兼容 API 凭据。

  1. 登录 Cloudflare Dashboard。
  2. 在左侧菜单进入 Storage & Databases → R2。
  3. 点击右侧面板中的 Manage R2 API Tokens(管理 R2 API 令牌)。
  4. 点击 Create API token(创建 API 令牌):
    • Token name:输入标识名称(例如 debian13-r2)。
    • Permissions:选择 Object Read & Write(对象读写)。
    • Specify bucket(s):
      • 若选择 Apply to all buckets,令牌具有全局桶权限;
      • 若选择 Apply to specific buckets(如仅授予 hk-ecs),需特别注意后续命令用法(见第 4 节踩坑点)。
  5. 点击创建后,立即复制并保存生成的以下三项核心凭据(Secret Access Key 仅展示一次):
    • Access Key ID
    • Secret Access Key
    • S3 Endpoint URL(格式通常为:https://<ACCOUNT_ID>.r2.cloudflarestorage.com)

2. 环境安装:FUSE3 与 rclone

在 Debian 13 (Trixie) 上更新软件源并安装依赖:

sudo apt update
sudo apt install -y fuse3 rclone

允许非 root 用户挂载与跨用户读写(可选但推荐):

# 编辑 fuse 配置文件
sudo sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf

3. 配置 rclone

创建或编辑 rclone 配置文件:

mkdir -p ~/.config/rclone
nano ~/.config/rclone/rclone.conf

在文件中添加以下配置块(将占位符替换为你自己的实际信息):

[r2]
type = s3
provider = Cloudflare
access_key_id = 你的_ACCESS_KEY_ID
secret_access_key = 你的_SECRET_ACCESS_KEY
endpoint = https://<你的_ACCOUNT_ID>.r2.cloudflarestorage.com
acl = private

特别注意:

  • endpoint 必须是根域名,末尾切勿携带 Bucket 名称(例如绝对不能写成 ...r2.cloudflarestorage.com/hk-ecs)。

4. 连通性测试与常见踩坑排查(重要)

在挂载前,请务必进行命令行连通性测试。以下是配置过程中最容易遇到的三个典型问题:

坑 1:命令遗漏冒号 :

错误现象:

# rclone lsd r2
NOTICE: "r2" refers to a local folder, use "r2:" to refer to your remote...
ERROR : : error listing: directory not found

原因:在 rclone 语法中,r2 代表当前目录下的名为 r2 的本地文件夹,r2:(带冒号)才代表名为 r2 的远程存储。

解法:远程目标名称后必须附加英文冒号。

坑 2:endpoint 包含桶路径导致列表为空

错误配置:

endpoint = https://xxx.r2.cloudflarestorage.com/hk-ecs

现象:执行 rclone lsd r2: 不报错,但输出为空,实际上并未正确连入 S3 顶层 API。

解法:检查 ~/.config/rclone/rclone.conf,将 endpoint 末尾多余的 /桶名 路径移除。

坑 3:单桶授权导致 403 AccessDenied

错误现象:

# rclone lsd r2:
ERROR : : error listing: AccessDenied: Access Denied
        status code: 403, request id: , host id: 
Failed to lsd with 2 errors: last error was: AccessDenied: Access Denied

原因:在 Cloudflare 创建 API Token 时,若权限被限制为"仅指定的单个 Bucket"(例如仅授予 hk-ecs),调用 rclone lsd r2: 会触发顶层 ListBuckets API,而该 Token 无权列举全量 Bucket,因而被 Cloudflare 直接返回 403 拒绝。

解法:跳过账户级列表,直接访问受权的具体 Bucket:

# 验证指定 Bucket(将 hk-ecs 替换为你的桶名)
rclone lsd r2:hk-ecs
rclone ls r2:hk-ecs

如果该命令能正常列出文件(或空桶正常返回且退出码为 0),则说明凭据与权限完全正确。

5. 执行本地挂载

测试通过后,创建本地挂载点目录并挂载:

# 1. 创建本地挂载目标目录
sudo mkdir -p /mnt/r2

# 2. 挂载指定桶(以 hk-ecs 为例)
rclone mount r2:hk-ecs /mnt/r2 \
  --vfs-cache-mode full \
  --vfs-cache-max-size 10G \
  --vfs-cache-max-age 24h \
  --allow-other \
  --daemon

挂载参数说明:

  • --vfs-cache-mode full:开启完整 VFS 读写缓存。对象存储不支持随机覆写,开启此项会将文件写入本地临时缓存,待关闭后再完整回写至 R2,确保兼容常见应用操作。
  • --vfs-cache-max-size 10G:限制本地最大缓存占用为 10GB(根据主机剩余磁盘空间调整)。
  • --allow-other:允许非挂载发起用户(如 www-data、普通用户)访问该目录。
  • --daemon:作为后台进程脱机运行。

验证挂载状态:运行 df -h /mnt/r2:

Filesystem      Size  Used Avail Use% Mounted on
r2:hk-ecs       1.0P     0  1.0P   0% /mnt/r2

挂载成功,容量显示为虚拟的 1.0P。

6. 配置 systemd 开机自启动守护进程

使用 --daemon 在服务器重启后挂载会丢失。推荐使用 systemd 服务托管挂载进程。

6.1 卸载临时手动挂载

fusermount -u /mnt/r2

6.2 创建 systemd 服务单元

创建文件 /etc/systemd/system/rclone-r2.service:

[Unit]
Description=Rclone Mount Cloudflare R2 Storage
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/rclone mount r2:hk-ecs /mnt/r2 \
  --config=/root/.config/rclone/rclone.conf \
  --vfs-cache-mode full \
  --vfs-cache-max-size 10G \
  --vfs-cache-max-age 24h \
  --dir-cache-time 1h \
  --attr-timeout 1m \
  --allow-other \
  --log-file=/var/log/rclone-r2.log \
  --log-level=NOTICE
ExecStop=/bin/fusermount -u -z /mnt/r2
Restart=on-failure
RestartSec=10s
User=root

[Install]
WantedBy=multi-user.target

6.3 启用并启动服务

# 重载 systemd 配置
systemctl daemon-reload

# 启动服务
systemctl start rclone-r2

# 设置开机自启动
systemctl enable rclone-r2

# 检查服务运行状态
systemctl status rclone-r2

7. 生产使用注意事项

  • 不可用于活跃数据库:切勿将 MySQL、PostgreSQL、SQLite 等事务型数据库目录直接存放在挂载点。对象存储缺乏块级就地写入与严格的文件级互斥锁,会导致数据严重损坏。
  • 控制 Class A / Class B API 调用:
    • 避免在挂载目录下频繁执行深层递归命令(如全盘 find 或 ls -R)。
    • 通过在挂载参数中添加 --dir-cache-time 1h,可使目录结构在本地缓存 1 小时,极大减少列举对象的 API 请求量。
  • 安全卸载方式:若需维护或调整参数,切勿直接 kill -9 杀死挂载进程,应使用:
    systemctl stop rclone-r2
    # 或者手动懒卸载
    fusermount -u -z /mnt/r2