用 Komga + Google Drive 打造一套「近乎无限存储」的私有漫画库
本文由 Claude Sonnet 5 根据真实部署经历攥写;Gemini 3.1 Pro 润色
事情的起因是我手头有一台只剩 20G 硬盘的闲置 VPS。我想用它搭个能长期攒漫画的私人阅读库。
传统思路是「本地下载好,再定时同步到网盘」。但对于 20G 的小盘来说,稍微多攒几套漫画就满了,更别提还要天天操心同步冲突和冗余占用的问题。
这篇文章记录的是另一条路:把 Google Drive 直接「假装」成本地硬盘挂载给服务器,VPS 只负责跑应用和做短期缓存。
核心工具链很简单:Komga 作为阅读服务端,rclone 提供 VFS(虚拟文件系统)挂载,Google Drive 充当无限后备存储。外围再套上 Docker Compose 和 Cloudflare Tunnel 解决部署和公网访问。
这套架构听起来特别优雅,跑通之后也确实很好用。但从理论可行到日常稳定,我经历了存储占满、数据库计数错乱、OAuth 授权莫名失效等一系列真实故障。这篇文章把方案、踩过的坑和最终配置都记录下来,希望能帮同样想折腾的小白少走几步弯路。
为什么选择 Komga?
Komga 是一个开源的漫画/电子书服务端。它不仅有网页端,能通过 OPDS 接入移动端的阅读 App(比如 Panels、Mihon),还支持元数据刮削。
最契合这个项目的一点是,它是无状态的。书籍文件存放在哪里、怎么组织,Komga 并不在乎。它只负责扫描文件、建立索引、提取缩略图,然后把这些信息存进自己独立的 SQLite 数据库里。
正是这种「文件与索引完全解耦」的设计,让我们可以放心大胆地把它架在 FUSE 网盘挂载这种伴随网络延迟的文件系统上。
架构总览
不废话,先看整体的数据流向:

在这个架构下,VPS 永远只缓冲你最近在看的那一小部分数据。漫画下载进去后,rclone 会先将其缓存在本地,后台异步上传到 Drive;阅读时,如果在缓存里就直接读取,不在就实时向 Drive 发起分片下载。磁盘占用和总藏书量完全解耦。
详细配置指南
为了让小白也能上手,以下是完整的配置流程和排坑说明。
第一步:配置 Google Cloud 项目与 OAuth
很多教程会让你直接用 rclone 默认的配置连接网盘,建议不要这么做。默认配置是所有人共享同一个额度,高峰期极易被限流。自己建一个凭证,每天 750GB 的上传额度完全独享。
- 登录 Google Cloud Console,新建一个项目。
- 在「APIs & Services -> Library」中搜索 Google Drive API 并启用。
- 在「APIs & Services -> Credentials」中创建一个 OAuth 客户端 ID,应用类型选择 Desktop app。
完成后,你会拿到 client_id 和 client_secret。
关键避坑:发布状态(Publishing status) 刚建好的 OAuth 应用默认是「测试中 (Testing)」状态。这里有两个致命限制:
- 只有手动加入「测试用户名单」的账号才能授权,否则会报 403 错误。
- Token 生命周期受限,可能七天后半夜悄悄失效。
解决方法很简单:在同一个页面,点击 「发布应用 / Publish App」,将其切换为 「生产中 / In production」。因为这是个人使用,不用担心 Google 的审核流程。授权时浏览器会弹出「未验证应用」的警告,点击高级继续即可。
沙盒隔离
为了安全,可以在 rclone 配置里加上 root_folder_id,将 rclone 的权限锁定在 Drive 的一个特定文件夹内:
[gdrive]
type = drive
client_id = 你的_client_id
client_secret = 你的_client_secret
scope = drive
root_folder_id = 你的漫画文件夹ID (从网页端 URL 获取)
第二步:配置 rclone 挂载与 Systemd 守护
首先在本地电脑(需要浏览器)执行授权命令,拿到 Token JSON,并填入服务器的 rclone.conf 中:
rclone authorize "drive" "你的_client_id" "你的_client_secret"
接着,在服务器上配置 systemd 服务来管理挂载。网络波动后,systemd 能自动帮你恢复挂载。
创建文件 /etc/systemd/system/komga-rclone.service:
[Unit]
Description=Rclone Mount for Komga
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/rclone mount gdrive: /root/komga/manga \
--config /root/.config/rclone/rclone.conf \
--cache-dir /var/cache/rclone \
--vfs-cache-mode full \
--vfs-cache-max-size 4G \
--vfs-cache-min-free-space 3G \
--dir-cache-time 168h \
--drive-stop-on-upload-limit \
--allow-other \
--rc --rc-addr=127.0.0.1:5572 --rc-no-auth
ExecStartPost=/usr/bin/docker restart -t 120 komga
ExecStop=/bin/fusermount -uz /root/komga/manga
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
配置解析:
Type=notify与ExecStartPost:确保 rclone 完全挂载就绪后,再重启 Komga 容器。否则 Komga 扫到一个空目录,会把所有藏书标记为「已删除」。--cache-dir /var/cache/rclone:千万别用默认的/tmp。Ubuntu 的定时任务每天会清理/tmp,如果正在排队上传的缓存文件被系统删了,数据会直接丢失。--vfs-cache-mode full:必须开启全缓存,否则每次翻页都会重新向 Drive 发起请求。--vfs-cache-min-free-space 3G:真正的磁盘防爆护栏。下载速度过快时,软限制max-size拦不住,这个参数能在磁盘剩余 3G 时强行切断写入。--rc:开启本地控制接口。排查问题时,通过这个接口查询状态,绝不能再起一个独立的 rclone 进程去读配置文件,否则极易触发 Google 的并发风控导致 Token 被封。
启动并设置开机自启:
systemctl daemon-reload
systemctl enable --now komga-rclone
第三步:使用 Docker 部署 Komga
创建 /root/komga/docker-compose.yml:
services:
komga:
image: gotson/komga:latest
container_name: komga
volumes:
- ./config:/config
- ./manga:/manga:ro,shared
ports:
- "127.0.0.1:25600:25600"
environment:
- JAVA_TOOL_OPTIONS=-Xmx512m
- TZ=Asia/Taipei
mem_limit: 1g
stop_grace_period: 120s
restart: unless-stopped
关键配置说明:
/manga:ro,shared:ro表示只读。Komga 不需要修改源文件,防止它随手改个文件导致 rclone 把整本漫画重新上传,白白浪费流量。127.0.0.1:25600:只监听本地。外部访问统一通过反向代理(如 Nginx Proxy Manager)接入。stop_grace_period: 120s:给足优雅退出的时间。Docker 默认关机只等 10 秒,如果 Komga 正在扫描数据库时被强制SIGKILL杀死,会导致数据库记录错乱。
在同一目录下运行 docker compose up -d 即可启动。
第四步:给 Komga 的扫描踩刹车
在本地硬盘上,Komga 的默认设置没什么问题。但在网络挂载环境下,必须进入 Komga 的「设置 -> 编辑库 -> 分析」中,关闭以下两个选项:
- 计算文件的哈希值(File hashing)
- 分析页面尺寸(Analyze dimensions)
如果不关闭,Komga 为了计算 MD5 或读取分辨率,会把新添加的漫画从头到尾完整下载一遍。关闭后,实测扫描几十本新书只需要不到一分钟。
第五步:日常维护与兜底方案
为了系统长期稳定运行,还需要做几项收尾工作。
1. 添加 Swap 内存 一台 2G 内存的小机器跑 Java 应用极易 OOM(内存溢出)。添加一个 2G 的 Swap 可以有效兜底:
fallocate -l 2G /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
2. 限制 Docker 日志大小
Docker 默认的日志驱动没有大小限制,久而久之会吃光磁盘。
修改 /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
运行 systemctl reload docker 生效。
3. 数据库定时备份
漫画可以重下,但 database.sqlite 里的阅读进度和元数据丢了就找不回来了。
我写了一个脚本 /usr/local/bin/komga-backup.sh,将其配合 systemd timer 每天凌晨执行:
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/root/backup
RCLONE_CONF=/root/.config/rclone/rclone.conf
STAMP=$(date +%F)
ARCHIVE="$BACKUP_DIR/komga-config-$STAMP.tar.gz"
mkdir -p "$BACKUP_DIR"
docker stop komga >/dev/null
tar czf "$ARCHIVE" -C /root/komga config
docker start komga >/dev/null
rclone copy "$ARCHIVE" gdrive:_komga_backup/ --config "$RCLONE_CONF"
find "$BACKUP_DIR" -name 'komga-config-*.tar.gz' -mtime +7 -delete
踩坑记录:数据库计数的幽灵错乱
在这里特别记录一个我遇到的典型故障。
之前因为没有设置 stop_grace_period,容器在扫描进行到一半时被 SIGKILL 强制杀掉。结果导致 Komga 界面里部分系列显示「书籍总数为 0」,但点进去又能正常看书。
这是因为 Komga 在 SERIES 表里缓存了一个 BOOK_COUNT 列。扫描被强杀导致真实的 BOOK 表记录存下了,但 SERIES 表的计数没有更新。
遇到这种情况,千万不要点击重新扫描全库,那会在 VFS 上产生巨大的流量开销。我写了一小段 Python 脚本,直接用 SQL 重算并修复缓存列,零下载、零等待:
#!/bin/bash
# 检查并修复 Komga 的 BOOK_COUNT 缓存列
set -euo pipefail
DB=/root/komga/config/database.sqlite
FIX=0
[[ "${1:-}" == "--fix" ]] && FIX=1
stale=$(python3 - "$DB" <<'PY'
import sqlite3, sys
con = sqlite3.connect(f"file:{sys.argv[1]}?mode=ro", uri=True)
rows = con.execute("""SELECT s.NAME, s.BOOK_COUNT, COUNT(b.ID)
FROM SERIES s
LEFT JOIN BOOK b ON b.SERIES_ID = s.ID AND b.DELETED_DATE IS NULL
WHERE s.DELETED_DATE IS NULL GROUP BY s.ID""").fetchall()
bad = sum(1 for _, cached, real in rows if cached != real)
print(bad)
PY
)
[[ "$stale" -eq 0 ]] && { echo "数据库计数一致"; exit 0; }
[[ "$FIX" -eq 0 ]] && { echo "发现 $stale 个系列计数错误,请带上 --fix 参数运行以修复"; exit 1; }
docker stop komga >/dev/null
python3 - "$DB" <<'PY'
import sqlite3, sys
con = sqlite3.connect(sys.argv[1])
con.execute("""UPDATE SERIES SET BOOK_COUNT = (
SELECT COUNT(*) FROM BOOK
WHERE BOOK.SERIES_ID = SERIES.ID AND BOOK.DELETED_DATE IS NULL)""")
con.commit()
PY
docker start komga >/dev/null
最后
这套系统部署完毕后,体验非常优秀。在一台廉价的 VPS 上,我获得了一个容量上不封顶的私人漫画库,日常的按需加载几乎感受不到延迟。
但这中间的折腾也让我深刻意识到:基于网络的虚拟文件系统,和真正的本地硬盘在行为逻辑上是完全不同的。 在本地无感的操作(算哈希、读元数据),在网络上都是高昂的全量下载;在本地随意终止的进程,在网络 I/O 的延迟下可能直接导致数据库写入断裂。
希望这篇记录能帮你避开这些隐蔽的陷阱,顺利搭建起属于自己的漫画库。
最后修改 Last modified: 2026年7月25日 25 Jul 2026