在没有图形界面的服务器上,或不想使用客户端软件时,如何方便地管理云存储是个问题。
rclone 就是为此而生的,它可以方便地在命令行下挂载网盘,例如 Google Drive、Dropbox、OneDrive 等,还支持 Amazon S3 对象存储服务。
alist 是一个云存储管理工具,它把众多网盘整合起来,其中就包括很多 rclone 不支持的国内网盘。
普通网盘没什么好说的,rclone 就能搞定,对于阿里云、百度云等国内网盘,可以使用 alist 建立 WebDAV,然后用 rclone 挂载。
下面以 S3 和阿里云盘为例进行配置。
安装
以下安装命令以 root 用户执行。
rclone
Debian 的官方源中 rclone 版本过于陈旧,建议到官网下载:https://rclone.org/downloads/
或者脚本一键安装:
curl https://rclone.org/install.sh | sudo bash
macOS 上可以用 brew 安装,不过大概是开源协议的缘故,没有 FUSE 的支持,没有内置 mount 子命令,只能使用 nfsmount,因此也建议用脚本安装1。
macOS 脚本安装后也需要额外安装 FUSE,然后重启:
brew install macfuse --cask
alist
图方便的直接用官方的脚本即可,目前只有 Linux。
但是对我来说,alist 默认把二进制文件、配置文件、缓存目录、日志等全弄一个目录里了,而且 systemd 服务是以 root 用户运行的,我不喜欢,所以手动下载。
Linux
以 x86-64 Linux 为例:
curl -L https://github.com/AlistGo/alist/releases/latest/download/alist-linux-amd64.tar.gz | tar xz -C /usr/local/bin
cat <<END >/usr/local/lib/systemd/system/alist.service
[Unit]
Description=AList Service
Documentation=https://qianbinbin.github.io/posts/managing-cloud-storage-with-rclone-and-alist/
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=60
StartLimitBurst=4
[Service]
DynamicUser=yes
StateDirectory=%p
CacheDirectory=%p
LogsDirectory=%p
ExecStart=/usr/local/bin/alist server --data "\$STATE_DIRECTORY"
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
END
systemctl daemon-reload
systemctl enable alist.service
systemctl start alist.service
这将以受限的动态用户运行,配置文件和数据库将保存在 /var/lib/alist
下。
由于 alist 没有指定缓存和日志路径的命令行参数,首次启动后,编辑 /var/lib/alist/config.json
以下内容:
{
"temp_dir": "/var/cache/alist",
"log": {
"name": "/var/log/alist/alist.log"
}
}
缓存和日志目录将分别位于 /var/cache/alist
和 /var/log/alist
。这些目录都会由 systemd 自动生成2,通过动态用户的方式也能增强一下安全性。
alist 日志无法设置等级,令牌都是直接打印出来的,也是十分离谱。
而且默认 50M 才轮转,保存 30 个备份,还不压缩,虽然这些可以修改,但也是只有超过大小后才轮转,而不是按时间轮转。
我选择系统自带的 logrotate:
cat <<END >/etc/logrotate.d/alist
/var/log/alist/*.log {
daily
rotate 5
compress
delaycompress
missingok
notifempty
copytruncate
}
END
用 copytruncate 是因为 alist 不支持重新打开日志,轮转后无法写入,因此采用先复制再清空原日志的方式,但可能会造成少量日志丢失。
Web 服务运行在 0.0.0.0:5244
,也可以在配置文件中修改。公网 IP 用户要注意安全问题。
更多配置项参考 https://alistgo.com/zh/config/configuration.html。
然后删除原来的缓存和日志并重启服务:
systemctl stop alist.service
rm -rf /var/lib/alist/temp /var/lib/alist/log
systemctl start alist.service
首次启动时 alist 会为 admin 用户自动生成密码,使用 journalctl -u alist.service
查看,建议登陆后立即修改用户名和密码。
nginx 反向代理
可以参考官方文档建立一个 nginx 反向代理:
location /alist/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_redirect off;
proxy_pass http://127.0.0.1:5244/alist/;
# the max size of file to upload
client_max_body_size 20000m;
}
编辑 /var/lib/alist/config.json
,将 site_url
的值改为 /alist
,并重启服务,否则路径无法正确映射。
之后就可以用 http[s]://host/alist/
访问管理页面了。
macOS
curl -L https://github.com/AlistGo/alist/releases/latest/download/alist-darwin-amd64.tar.gz | tar xz -C ~/.local/bin
cat <<END >~/Library/LaunchAgents/org.binac.alist.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.binac.alist</string>
<key>ProgramArguments</key>
<array>
<string>$HOME/.local/bin/alist</string>
<string>server</string>
<string>--data</string>
<string>/usr/local/etc/alist</string>
</array>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/alist/error.log</string>
<key>StandardOutPath</key>
<string>/usr/local/var/log/alist/error.log</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
END
mkdir -p /usr/local/var/log/alist
launchctl load ~/Library/LaunchAgents/org.binac.alist.plist
在 /usr/local/var/log/alist/error.log
中查看初始密码。
修改 /usr/local/etc/alist/config.json
中缓存和日志相关配置:
{
"temp_dir": "/usr/local/var/cache/alist",
"log": {
"name": "/usr/local/var/log/alist/access.log"
}
}
删除原来的缓存和日志并重启:
launchctl unload ~/Library/LaunchAgents/org.binac.alist.plist
rm -rf /usr/local/etc/alist/temp /usr/local/etc/alist/log
launchctl load ~/Library/LaunchAgents/org.binac.alist.plist
由于系统自带的 newsyslog 不太好用,这里仍然使用 logrotate,使用 brew 安装,配置文件位于
/usr/local/etc/logrotate.d
下,参考前文 Linux 安装部分。
brew 自带的 logrotate 服务默认把检查时间设置为每天 6:25,可以按需求自行在
~/Library/LaunchAgents/homebrew.mxcl.logrotate.plist
中修改并重新载入。如果要支持 hourly 就需要设置每小时检查一次。
如果使用 newsyslog,alist 将无法自动打开新日志,不推荐:
sudo cat <<END >/etc/newsyslog.d/alist.conf
# logfilename [owner:group] mode count size when flags [/pid_file] [sig_num]
/usr/local/var/log/alist/*.log qianbinbin:admin 640 5 * $D0 GZ
END
Amazon S3 对象存储
创建桶
赛博大善人 Cloudflare R2 兼容 S3,并且 10G 以内存储免费、出口流量免费,简直是个人和小型工作室的福报。
首先登录控制台,进入 R2 对象存储,绑定支付方式(例如 Visa),并创建一个桶。
创建完成后,如果只是私人使用(相当于网盘),不想暴露在公网,就不要设置自定义域和 R2.dev 子域,但用 rclone 创建临时链接也是可行的。
如果设置了域,则可以当作图床等使用。
然后创建 API 令牌,按照喜好选择是管理所有桶还是指定桶。令牌页面只会显示一次,要妥善保管,配置 rclone 时要用到。
rclone 配置
运行 rclone config
进行配置,按提示来就可以了。
配置完成后,最好再编辑配置文件(通常为 ~/.config/rclone/rclone.conf
),在对应配置下增加一行 no_check_bucket = true
以减少查询。
最终配置类似于:
[<remote>]
type = s3
provider = Cloudflare
access_key_id = <key_id>
secret_access_key = <key>
endpoint = https://<user_id>.r2.cloudflarestorage.com
no_check_bucket = true
运行 rclone lsd <remote>:
查看根目录下的目录列表,rclone ls <remote>:
列出所有文件。
可以运行 rclone mount <remote>:<桶名> <挂载路径> --vfs-cache-mode full --vfs-cache-max-age 24h
来手动挂载。
Linux 自动挂载
rclone 可以作为 Unix mount helper 实现 mount 命令的挂载:
ln -s /usr/bin/rclone /sbin/mount.rclone
还可以添加到 /etc/fstab
中,这就很方便了,不需要写什么蛋疼的 systemd 脚本,但需要 fuse3 支持:
apt install fuse3
在 /etc/fuse.conf
中取消注释 user_allow_other
,以允许其他用户访问挂载目录。
然后在 /etc/fstab
增加以下行:
<remote>:<桶名> <挂载路径> rclone uid=<用户>,gid=<组>,nofail,_netdev,args2env,allow_other,vfs_cache_mode=full,vfs_cache_max_age=24h,cache_dir=/var/cache/rclone,config=</path/to/rclone.conf> 0 0
uid=<用户>,gid=<组>
改为需要挂载的用户和组,config=</path/to/rclone.conf>
改为自己的配置文件路径。
然后使用 mount -av
挂载试试。
macOS 自动挂载
创建 ~/Library/LaunchAgents/org.binac.rclone.cf-r2.plist
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.binac.rclone.cf-r2</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/rclone</string>
<string>mount</string>
<string><remote>:<桶名></string>
<string><挂载路径></string>
<string>--vfs-cache-mode</string>
<string>full</string>
<string>--vfs-cache-max-age</string>
<string>24h</string>
</array>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/rclone-cf-r2.log</string>
<key>StandardOutPath</key>
<string>/usr/local/var/log/rclone-cf-r2.log</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
把 <remote>:<桶名>
和 <挂载路径>
替换为自己的,接着加载:
launchctl load ~/Library/LaunchAgents/org.binac.rclone.cf-r2.plist
下载速率实测北美可以跑到 30 MiB/s,国内电信晚高峰只有 4 MiB/s 左右,也不是不能用,比现在的阿里云盘快多了。
阿里云盘
rclone 没有对阿里云盘的支持,需要通过第三方软件建立 WebDAV 服务,这一任务交给 alist 完成。然后再通过 rclone 挂载。
国内其他网盘也差不多这个步骤。
alist 配置
首先,打开 alist 管理页面,把用户权限 WebDAV 相关的都勾选上。
其次,按照官方文档 https://alistgo.com/zh/guide/drivers/common.html 和 https://alistgo.com/zh/guide/drivers/aliyundrive_open.html 建立存储。
他们的说明文字并不严谨,似乎是国内项目的通病。
其中,挂载路径是虚拟路径,是 Web 管理页面上的路径,不是本地文件系统的路径。alist 应该也没有本地挂载的功能。
缓存过期时间是网盘内容缓存的有效时间,超过这个时间视为过期,程序自动重新获取,不是令牌刷新时间。
WebDAV 策略如果用本地代理,意思是请求网盘的流量会从运行 alist 的主机发出,在网盘看来就只有一台机器在访问;如果使用 302 重定向,多个 IP 直连有被封号的风险。
另外需要注意的是,获取刷新令牌时可能需要梯子,或者按照文档修改 API 链接。
然后回到主页查看是否连接成功。
rclone 配置
前面已经建立了 WebDAV,接下来使用 rclone config
建立配置即可,没什么好说的,最终配置类似于:
[<remote>]
type = webdav
url = http://localhost:5244/dav<虚拟挂载路径>
user = <alist 用户名>
pass = <alist 密码>
唯一需要注意的是 url,如果本地挂载且没有使用反向代理,那么应该是
http://localhost:5244/dav<虚拟挂载路径>
,如果使用了反向代理,那么应该类似于
http://host/alist/dav<虚拟挂载路径>
。
Linux 自动挂载
参考前文,其他都一样,但 /etc/fstab
如此配置:
<remote>: <挂载路径> rclone uid=<用户>,gid=<组>,x-systemd.requires=alist.service,nofail,_netdev,args2env,allow_other,vfs_cache_mode=full,vfs_cache_max_age=24h,cache_dir=/var/cache/rclone,config=</path/to/rclone.conf>,timeout=2h 0 0
注意 x-systemd.requires=alist.service
部分,这会声明对
alist 服务的依赖,避免开机时 alist 还没启动导致挂载失败。
rclone 还有一个需要注意的全局参数 --timeout
,默认值是 5 分钟。
在上传大文件时,由于缓存的存在,rclone 很快就复制完成,然后等待服务返回结果,要是上传带宽不够当然是干等 5 分钟然后超时,接着就断开重新上传。
这会造成后台反复上传反复失败,从 alist 的 log 里也可以看到,alist 就会出现 405 错误。其实这跟网盘服务器没关系,每次上传 5 分钟即出错。运营商对上传流量还是管得比较严的,搞不好要被限制。
所以这里设置为 2h(2 小时),可以满足大部分上传要求。
macOS 自动挂载
其实 macOS 原生就支持 WebDAV,在访达中按 command + K 输入链接即可,但总存在奇奇怪怪的问题。
因此还是建议用 rclone,launchd 服务文件参考前文,也要注意 --timeout
参数。
阿里云盘(更新于 2023 年,已废弃)
阿里云盘(更新于 2023 年,已废弃)
配合 aliyundrive-webdav 项目,可以以 WebDAV 方式挂载阿里云盘。
这项目服务器经常 503,弃用了,建议使用 alist。
以下以 Debian 为例,运行阿里云盘 WebDAV 服务并使用 rclone 自动挂载。
aliyundrive-webdav
首先安装 aliyundrive-webdav:
# pip install aliyundrive-webdav
我讨厌虚拟环境,因为它总是把东西封装得面目全非,所以这里用特权用户安装,而且方便之后编写 systemd 脚本。根据个人喜好即可。
获取 token:
# aliyundrive-webdav qr login
手机打开阿里云盘 APP 扫码得到 token。
为 WebDAV 服务专门建立一个目录,用于存放 token:
# mkdir /var/lib/private/aliyundrive-webdav
# vim /var/lib/private/aliyundrive-webdav/refresh_token
将 token 复制到 refresh_token 文件中。
新建 systemd 脚本:
# cat /etc/systemd/system/aliyundrive-webdav.service
[Unit]
Description=Aliyun Drive WebDAV Service
After=network-online.target
[Service]
DynamicUser=yes
StateDirectory=aliyundrive-webdav
ExecStart=/usr/local/bin/aliyundrive-webdav --host localhost --workdir "$STATE_DIRECTORY" --cache-ttl 10
[Install]
WantedBy=multi-user.target
/var/lib/private
是个特殊的目录。
systemd 脚本如果指定了 StateDirectory
,就会从 /var/lib
寻找目标文件夹,通过 $STATE_DIRECTORY
来访问它。但如果同时指定了 DynamicUser=yes
,就会在 /var/lib
建立一个软链接指向 /var/lib/private
中的同名目标文件夹:
# ll /var/lib/aliyundrive-webdav
lrwxrwxrwx 1 root root 26 Mar 21 16:48 /var/lib/aliyundrive-webdav -> private/aliyundrive-webdav
由于只有特权用户能访问 /var/lib/private
,以此保证了安全性,这就是上面建立 /var/lib/private/aliyundrive-webdav
目录的原因。
aliyundrive-webdav 通过 --workdir
参数指定工作目录,就可以读取和更新 token 了。
# systemctl daemon-reload
# systemctl start aliyundrive-webdav.service
# systemctl enable aliyundrive-webdav.service
# systemctl status aliyundrive-webdav.service
/etc/fstab 自动挂载
rclone 可以作为 Unix mount helper 实现 mount 命令的挂载:
# ln -s /usr/bin/rclone /sbin/mount.rclone
还可以添加到 /etc/fstab
中,这就很方便了,不需要写什么蛋疼的 systemd 脚本。
不过这一方法需要 fuse3( 新版 rclone mount
似乎 fuse2 就行rclone mount
也需要 fuse3 了):
# apt install fuse3
# vim /etc/fuse.conf
取消注释 user_allow_other
,以允许其他用户访问挂载目录。
添加挂载项:
# mkdir /mnt/aliyun
# cat <<-END >>/etc/fstab
# https://rclone.org/commands/rclone_mount/#rclone-as-unix-mount-helper
:webdav: /mnt/aliyun rclone nofail,_netdev,args2env,webdav_url=http://localhost:8080,allow_other,vfs_cache_mode=full,vfs_cache_max_age=24h,cache_dir=/var/cache/rclone,config=/dev/null 0 0
END
第四列是关注的重点,各选项以 ,
分隔,例如,需要以指定用户挂载,可以添加 uid=xxx,gid=xxx
选项。
注:
Debian 从最近(2023 年 9 月前后)某次更新后,原本第四列的
x-systemd.automount
将会导致Fatal error: mount not ready
,如果此时访问目录则会报错Transport endpoint is not connected
,原因不明,因此删去这个选项。这个选项的作用是让目录在实际访问时挂载(延迟挂载),而不是开机就立即启动。
如果有其它需要的 rclone 参数也可以添加,但 GNU 风格的参数要手动翻译一下,前缀 --
去掉,-
改为 _
,例如 --vfs-cache-mode=full
要改为 vfs_cache_mode=full
。
看看成功了没有:
# mount -av
需要 debug 的话,在第四列添加 vv
以查看更详细的 log。
这一配置会自动挂载,而且只有在访问挂载目录时真正挂载。
OneDrive(写于 2020 年,可能已过时,仅供参考)
OneDrive(写于 2020 年,可能已过时,仅供参考)
rclone 提供了简单的交互式配置方式,运行 rclone config
即可,一般就是打开浏览器获取一个 token,网上有很多教程,在此就不赘述了。
以 OneDrive for Business 为例,主要说明一下如何在没有图形界面的情况下获取 token。
一种是先用其他带图形界面的系统配置一次,直接把 token 复制过去。
另一种就是在命令行下执行到这一步时:
Use auto config?
* Say Y if not sure
* Say N if you are working on a remote or headless machine
y) Yes
n) No
y/n> y
If your browser doesn't open automatically go to the following link: http://127.0.0.1:53682/auth?state=xxxxxxxxxxxxxxxxxxxxxx
Log in and authorize rclone for access
Waiting for code...
选择 y
的话理论上会打开浏览器访问那个地址,当然由于是服务器,不可能打开浏览器,这时我们重开一个 SSH 连接,并用 curl
访问:
$ curl http://127.0.0.1:53682/auth?state=xxxxxxxxxxxxxxxxxxxxxx
<a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?access_type=offline&client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&redirect_uri=http%3A%2F%2Flocalhost%3A53682%2F&response_type=code&scope=Files.Read+Files.ReadWrite+Files.Read.All+Files.ReadWrite.All+offline_access&state=xxxxxxxxxxxxxxxxxxxxxx">Temporary Redirect</a>.
复制 href
中的链接,对其 URL 解码,可以使用 Python 或其它工具,如:https://tool.chinaz.com/tools/urlencode.aspx
接着(客户端)使用浏览器访问解码后的 URL 并登陆账号,然后会重定向到一个本地 URL,在服务器上用 curl
访问此 URL。
这时 rclone 的配置应该会自动进行到下一步,其它照常配置即可。如果不行就多试几次。
挂载
安装 FUSE:
$ sudo apt install fuse
将名为 onedrive
的配置挂载到 /mnt/onedrive
下:
$ rclone mount onedrive:/ /mnt/onedrive --vfs-cache-mode full --vfs-cache-max-age 24h --vfs-cache-max-size 12G
其中 vfs-cache-mode
可选参数为 off|minimal|writes|full
,默认为 off
,写入文件时无法随机寻址,因此无法用于 aria2、Transmission 等分块下载软件。writes
或 full
则可以很好地模拟本地文件系统,writes
模式下只读打开的文件无缓存,full
模式下读写均有缓存。
vfs-cache-max-age
设置缓存保存时间,vfs-cache-max-size
设置缓存大小。
有一个很重要的参数 --allow-other
,表示允许其他用户访问挂载的目录,否则默认其他用户无法访问,不注意的话根本无从排查。而这个参数要求配置 fuse,将 /etc/fuse.conf
中的 user_allow_other
取消注释。--allow-root
参数允许 root 用户访问,同样需要设置 user_allow_other
。
参数 -vv
可查看 log 以排查错误,--daemon
以守护进程运行等。更多可参考:https://rclone.org/commands/rclone_mount/
查看一下是否已经挂载:
$ df -h
Filesystem Size Used Avail Use% Mounted on
onedrive: 5.0T 18G 5.0T 1% /mnt/onedrive
开机自启
systemd 脚本:
$ cat /etc/systemd/system/rclone.service
[Unit]
Description=rclone Service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=username
ExecStart=/usr/bin/rclone mount onedrive:/ /mnt/onedrive --vfs-cache-mode full --vfs-cache-max-age 24h --vfs-cache-max-size 12G
ExecStopPost=/bin/fusermount -qzu /mnt/onedrive
[Install]
WantedBy=multi-user.target
其中 User
设置为所运行的用户。
我实际使用时,停止进程后无法自动取消挂载,文件夹异常,因此用 fusermount -qzu /mnt/onedrive
取消挂载。
另外,开机时 Transmission 可能会在 rclone 之前运行,此时目录未挂载,Transmission 就会出错,于是修改其 systemd 脚本:
$ vim /lib/systemd/system/transmission-daemon.service
将 After=network.target
修改为 After=network.target rclone.service
,这样 Transmission 就在 rclone 后启动。