
目标:用 Docker Compose 在 VPS、NAS 或 1Panel 管理的服务器上部署 BookLore,搭建一个可自托管、多用户、可阅读、可同步、可整理元数据的数字书库。
1. 项目简介
BookLore 是一个自托管、多用户数字书库应用,目标是把电子书、漫画、元数据、阅读进度、设备同步和导入流程统一放在自己的服务器里管理。
它适合用来管理:
- EPUB
- MOBI / AZW3 等常见电子书格式
- CBZ / CBR 等漫画格式
- 多格式同书
- 系列书籍
- 多用户家庭书库
官方项目描述中提到,BookLore 支持智能书架、自动元数据、Kobo 与 KOReader 同步、BookDrop 导入、OPDS、以及 EPUB/PDF/漫画的内置阅读器。
官方参考链接:
- GitHub 仓库:booklore-app/booklore
- 官方文档:BookLore Docs
- Docker 镜像:ghcr.io/booklore-app/booklore
- Docker Compose 参考:BookLore README
2. 功能与优点

智能书架
BookLore 支持自定义书架和动态规则书架,可以按作者、系列、格式、标签、阅读状态、元数据字段等条件筛选图书。对于大型书库来说,这比单纯按文件夹浏览更灵活。
自动元数据
BookLore 可以从 Google Books、Open Library、Amazon 等来源拉取封面、简介、评分、评论等元数据。自动匹配后仍可人工编辑,适合处理标题不规范、系列信息缺失、封面错误等情况。
内置阅读器
浏览器里可以直接阅读 EPUB、PDF 和漫画文件,并记录阅读进度。这样在手机、平板、电脑上打开同一个 Web 地址,就能继续阅读。
多设备同步
BookLore 支持 OPDS,也支持 Kobo、KOReader 等阅读链路。它可以作为电子书客户端和硬件阅读器之间的书库中心。
多用户
多用户环境下,每个用户可以有自己的书架、阅读进度、偏好和访问范围。家庭书库或小团队共享书库会比较方便。
BookDrop 自动导入
BookDrop 是一个投递目录,把书放进去后,BookLore 会自动检测、提取信息、拉取元数据,并进入审核导入流程。适合批量整理新书。
自托管可控
书库文件、数据库和配置都在自己的服务器里,备份策略、访问权限、反向代理和内网访问都可自己控制。
3. 推荐架构

推荐结构:
<code class="language-text">用户浏览器 -> HTTPS 反向代理 -> BookLore 容器 -> MariaDB 数据库 书库文件 -> 挂载到 BookLore 容器 BookDrop 投递目录 -> 挂载到 BookLore 容器 </code>
更具体一点:
- 反向代理负责 HTTPS、域名、证书和公网入口。
- BookLore 容器负责 Web UI、API、阅读器、元数据处理、导入队列。
- MariaDB 容器负责保存用户、书籍、元数据、阅读进度等结构化数据。
books/保存电子书原文件。bookdrop/保存待自动导入的投递文件。data/保存 BookLore 应用数据。
4. 网络存储特别注意
这是部署 BookLore 最容易踩坑的地方。
官方 README 明确提醒:BookLore 的文件写入、重命名、整理等操作是按本地文件系统设计的。NAS、NFS、SMB/CIFS、云盘 FUSE 等网络存储可能因为延迟、缓存、锁机制或文件系统语义差异,导致静默损坏、写入不完整、文件丢失等风险。
如果书库目录在 NAS、NFS、SMB/CIFS 或其他网络挂载上,必须使用:
<code class="language-env"># 指定 BookLore 使用网络存储模式,避免直接改写网络书库文件 DISK_TYPE=NETWORK </code>
网络存储模式下,BookLore 会把元数据保存在数据库里,并禁用会直接修改文件的整理功能。这是网络书库更稳的方式。
如果书库目录是服务器本地磁盘,可以使用:
<code class="language-env"># 指定 BookLore 使用本地磁盘模式,允许本地文件系统上的整理和写入能力 DISK_TYPE=LOCAL </code>
公开分享部署教程时,建议专门强调这点:NAS 书库优先 DISK_TYPE=NETWORK。
5. 手动部署流程

整体流程:
- 安装 Docker 和 Docker Compose。
- 创建部署目录。
- 创建
.env。 - 创建
docker-compose.yml。 - 启动 MariaDB 和 BookLore。
- 登录 Web 页面创建管理员账号。
- 添加书库目录。
- 配置元数据、书架、BookDrop、OPDS。
- 设置 HTTPS 反向代理。
- 配置备份和升级策略。
6. 创建部署目录
示例目录使用 1Panel 常见 Compose 路径,也可以换成普通 Docker Compose 目录。
<code class="language-bash">sudo mkdir -p /opt/1panel/docker/compose/booklore # 创建 BookLore 的 Compose 部署目录 cd /opt/1panel/docker/compose/booklore # 进入 BookLore 部署目录 sudo mkdir -p data books bookdrop mariadb/config # 创建应用数据、书库、投递目录和数据库目录 sudo chown -R 1000:1000 data books bookdrop mariadb # 把目录属主改为容器运行用户,避免写入权限问题 </code>
如果不确定 UID/GID:
<code class="language-bash">id # 查看当前用户、用户组和附加组信息 id -u # 查看当前用户 UID,用于 APP_USER_ID 和 DB_USER_ID id -g # 查看当前用户 GID,用于 APP_GROUP_ID 和 DB_GROUP_ID </code>
7. 创建 .env
建议把密码和可变参数放在 .env,不要直接硬编码到 docker-compose.yml。
生成随机密码:
<code class="language-bash">openssl rand -base64 32 # 生成数据库用户密码,可填入 DB_PASSWORD openssl rand -base64 32 # 生成 MariaDB root 密码,可填入 MYSQL_ROOT_PASSWORD </code>
创建 .env:
<code class="language-env"># BookLore 容器运行用户 UID,需和宿主机目录权限匹配 APP_USER_ID=1000 # BookLore 容器运行用户 GID,需和宿主机目录权限匹配 APP_GROUP_ID=1000 # 容器时区,国内服务器通常使用 Asia/Shanghai TZ=Asia/Shanghai # BookLore 连接 MariaDB 的 JDBC 地址,服务名 mariadb 来自 compose DATABASE_URL=jdbc:mariadb://mariadb:3306/booklore # BookLore 使用的数据库用户名 DB_USER=booklore # BookLore 使用的数据库密码,部署时必须替换为随机强密码 DB_PASSWORD=CHANGE_ME_DB_PASSWORD # 存储模式;本地磁盘用 LOCAL,NAS/NFS/SMB 网络存储建议用 NETWORK DISK_TYPE=NETWORK # MariaDB 容器运行用户 UID,通常与宿主机目录权限一致 DB_USER_ID=1000 # MariaDB 容器运行用户 GID,通常与宿主机目录权限一致 DB_GROUP_ID=1000 # MariaDB root 密码,部署时必须替换为随机强密码 MYSQL_ROOT_PASSWORD=CHANGE_ME_MYSQL_ROOT_PASSWORD # MariaDB 初始化数据库名 MYSQL_DATABASE=booklore </code>
注意:.env 示例中的注释是给人看的。实际部署时保留整行 # 注释通常没问题,但不要在变量值后面追加奇怪字符。
8. 创建 docker-compose.yml
下面是可分享的通用模板,不包含真实路径、真实端口和真实密码。
<code class="language-yaml">services: # 定义本 compose 项目里的服务列表
booklore: # BookLore 主应用服务
image: ghcr.io/booklore-app/booklore:latest # 使用 BookLore 官方 GHCR 镜像
container_name: booklore # 固定容器名,方便在 Docker 或 1Panel 中识别
restart: unless-stopped # 容器异常退出或服务器重启后自动恢复
environment: # BookLore 应用环境变量
- USER_ID=${APP_USER_ID} # 指定应用容器写文件时使用的用户 UID
- GROUP_ID=${APP_GROUP_ID} # 指定应用容器写文件时使用的用户组 GID
- TZ=${TZ} # 指定容器时区
- DATABASE_URL=${DATABASE_URL} # 指定 MariaDB JDBC 连接地址
- DATABASE_USERNAME=${DB_USER} # 指定数据库用户名
- DATABASE_PASSWORD=${DB_PASSWORD} # 指定数据库密码
- DISK_TYPE=${DISK_TYPE} # 指定存储模式,NAS 网络存储建议 NETWORK
depends_on: # 定义主应用启动依赖
mariadb: # 指定 BookLore 依赖 MariaDB 服务
condition: service_healthy # 等待 MariaDB 健康检查通过后再启动 BookLore
ports: # 定义宿主机到容器的端口映射
- "6060:6060" # 把宿主机 6060 映射到 BookLore 容器 6060
volumes: # 定义宿主机目录到容器目录的挂载
- ./data:/app/data # 持久化 BookLore 应用数据
- ./books:/books # 挂载书库目录,生产环境可替换成自己的书库路径
- ./bookdrop:/bookdrop # 挂载 BookDrop 自动导入目录
healthcheck: # 定义 BookLore 健康检查
test: wget -q -O - http://localhost:6060/api/v1/healthcheck # 请求健康检查接口
interval: 60s # 每 60 秒检查一次
retries: 5 # 连续失败 5 次后标记为不健康
start_period: 60s # 容器启动后等待 60 秒再开始健康检查
timeout: 10s # 单次健康检查最长等待 10 秒
networks: # 指定容器加入的 Docker 网络
- booklore # 加入 booklore 内部网络
mariadb: # MariaDB 数据库服务
image: lscr.io/linuxserver/mariadb:11.4.5 # 使用 linuxserver 维护的 MariaDB 镜像
container_name: booklore-mariadb # 固定数据库容器名
restart: unless-stopped # 数据库容器异常退出或服务器重启后自动恢复
environment: # MariaDB 初始化环境变量
- PUID=${DB_USER_ID} # 指定数据库容器写文件时使用的用户 UID
- PGID=${DB_GROUP_ID} # 指定数据库容器写文件时使用的用户组 GID
- TZ=${TZ} # 指定数据库容器时区
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # 指定 MariaDB root 密码
- MYSQL_DATABASE=${MYSQL_DATABASE} # 指定初始化数据库名
- MYSQL_USER=${DB_USER} # 指定应用数据库用户名
- MYSQL_PASSWORD=${DB_PASSWORD} # 指定应用数据库密码
volumes: # 定义数据库持久化目录
- ./mariadb/config:/config # 持久化 MariaDB 数据文件和配置
healthcheck: # 定义 MariaDB 健康检查
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"] # 使用 mariadb-admin 检查数据库是否可用
interval: 10s # 每 10 秒检查一次数据库状态
timeout: 5s # 单次健康检查最长等待 5 秒
retries: 10 # 连续失败 10 次后标记为不健康
networks: # 指定数据库加入的 Docker 网络
- booklore # 加入 booklore 内部网络
networks: # 定义 Docker 网络
booklore: # 创建 booklore 内部网络
</code>
9. 启动服务
启动前检查配置:
<code class="language-bash">cd /opt/1panel/docker/compose/booklore # 进入 BookLore 部署目录 docker compose config # 检查 compose 文件和 .env 变量是否能正确解析 </code>
拉取镜像并启动:
<code class="language-bash">docker compose pull # 拉取 BookLore 和 MariaDB 镜像 docker compose up -d # 后台启动或更新 BookLore 服务 docker compose logs -f # 实时查看启动日志,观察数据库连接和应用启动状态 </code>
检查状态:
<code class="language-bash">docker ps --format "table {{.Names}}t{{.Status}}t{{.Ports}}" # 查看容器状态和端口映射
curl -I http://127.0.0.1:6060/ # 从服务器本机测试 BookLore Web 服务是否返回响应
</code>
正常情况下应看到:
<code class="language-text">booklore Up ... 0.0.0.0:6060->6060/tcp booklore-mariadb Up ... healthy 3306/tcp </code>
然后打开:
<code class="language-text">http://YOUR_SERVER_LAN_IP:6060/ </code>
首次进入页面后,按页面提示创建管理员账号。
10. 反向代理与 HTTPS
生产环境建议放到 HTTPS 域名后面,不建议长期直接暴露 http://IP:6060。
Nginx / OpenResty 示例:
<code class="language-nginx">server { # 定义一个 HTTPS 虚拟主机
listen 443 ssl; # 监听标准 HTTPS 端口
server_name books.example.com; # 设置访问域名,需替换成自己的域名
ssl_certificate /path/to/fullchain.pem; # 指定证书链文件路径
ssl_certificate_key /path/to/privkey.pem; # 指定证书私钥文件路径
client_max_body_size 1024m; # 允许上传较大的电子书或漫画压缩包
location / { # 匹配所有 Web 请求
proxy_pass http://127.0.0.1:6060; # 反向代理到本机 BookLore 服务
proxy_set_header Host $host; # 传递原始 Host 头
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递代理链路 IP
proxy_set_header X-Forwarded-Proto $scheme; # 传递外部访问协议
proxy_http_version 1.1; # 使用 HTTP/1.1 代理协议
} # 结束 location 配置
} # 结束 server 配置
</code>
如果 80/443 被封,可以使用自定义 HTTPS 端口:
<code class="language-nginx">listen 8443 ssl; # 监听示例 HTTPS 端口,实际端口请按自己的环境调整 </code>
自定义端口访问示例:
<code class="language-text">https://books.example.com:8443/ </code>
如果通过 1Panel 配置反向代理:
- 网站类型选择反向代理。
- 代理地址填
http://127.0.0.1:6060。 - 开启 HTTPS 证书。
- 上传文件较大时调高上传大小限制。
- 若使用自定义 HTTPS 端口,要确认 OpenResty 已监听该端口。
11. 书库目录规划
建议书库结构尽量清楚,但不要为了 BookLore 过度改动原始文件。
<code class="language-text">books/ # 主书库根目录
小说/ # 按类型或主题划分的一级分类
示例书名/ # 同一本书的多格式文件可放在同一个文件夹
示例书名.epub # EPUB 格式文件
示例书名.pdf # PDF 格式文件
漫画/ # 漫画或图像类书籍分类
示例漫画.cbz # CBZ 漫画文件
bookdrop/ # 自动导入投递目录
待导入.epub # 放入后等待 BookLore 检测和审核
</code>
实践建议:
- 同一本书的不同格式可以放在同一个书名文件夹,便于后续合并为一本书的多个格式。
- 系列图书可以放在系列文件夹里,再在 BookLore 中检查系列元数据。
- NAS 网络挂载书库建议
DISK_TYPE=NETWORK。 - 不要让自动整理工具和 BookLore 同时改同一批文件。
- 批量导入前先备份原始书库。
12. BookDrop 与元数据流程
BookDrop 的典型流程:
- 把文件放入
bookdrop/。 - BookLore 自动检测新增文件。
- 解析文件名、格式和基础元数据。
- 从元数据源拉取封面、简介、作者、评分等信息。
- 在 Web 页面审核。
- 确认后导入书库。
如果元数据匹配错误,优先在入库前人工修正。尤其是:
- 同名不同作者。
- 套装书。
- 多卷系列。
- 中英文混合书名。
- 扫描版 PDF。
- 漫画卷号。
13. OPDS、Kobo 与 KOReader
BookLore 可以作为电子书客户端的服务端书库。
常见用法:
- 支持 OPDS 的阅读器可通过 OPDS 地址浏览书库。
- Kobo 可用于同步书籍和阅读进度。
- KOReader 可用于跨设备阅读体验。
公开部署 OPDS 时要注意:
- 不要把无认证的 OPDS 暴露到公网。
- 尽量放在 HTTPS 后面。
- 多用户环境下检查每个用户的书库权限。
- 如果走反向代理,确认外部访问地址和代理头设置正确。
14. 备份与恢复

必须备份:
<code class="language-text">docker-compose.yml # 保存容器编排、端口、卷挂载和环境变量引用 .env # 保存数据库密码、UID/GID、时区和存储模式 data/ # 保存 BookLore 应用数据 mariadb/config/ # 保存 MariaDB 数据库文件 books/ # 保存电子书原始文件 bookdrop/ # 保存待导入文件,按需要备份 </code>
简单备份命令:
<code class="language-bash">cd /opt/1panel/docker/compose # 进入 Compose 项目根目录 tar -czf booklore-backup-$(date +%F).tar.gz booklore # 打包 BookLore 部署目录 </code>
更稳的备份策略:
- 数据库目录和书库目录都要备份。
- 升级前单独做一次完整压缩包。
- 书库在 NAS 上时,确认 NAS 端也有快照或版本备份。
- 大书库建议用 restic、kopia、rsync、ZFS 快照等工具增量备份。
恢复时的基本顺序:
<code class="language-bash">cd /opt/1panel/docker/compose # 进入 Compose 项目根目录 tar -xzf booklore-backup-YYYY-MM-DD.tar.gz # 解压之前备份的 BookLore 目录 cd booklore # 进入恢复后的 BookLore 部署目录 docker compose up -d # 启动 BookLore 和 MariaDB 服务 docker compose logs -f # 查看恢复后的启动日志 </code>
15. 升级方法
升级前先备份:
<code class="language-bash">cd /opt/1panel/docker/compose # 进入 Compose 项目根目录 tar -czf booklore-before-upgrade-$(date +%F).tar.gz booklore # 升级前打包当前部署目录 </code>
升级:
<code class="language-bash">cd /opt/1panel/docker/compose/booklore # 进入 BookLore 部署目录 docker compose pull # 拉取最新镜像 docker compose up -d # 使用新镜像重建并启动容器 docker compose logs -f # 查看升级后的启动日志 </code>
检查:
<code class="language-bash">docker ps --format "table {{.Names}}t{{.Status}}t{{.Ports}}" # 检查 BookLore 和数据库容器状态
curl -I http://127.0.0.1:6060/ # 从服务器本机检查 Web 服务是否可访问
</code>
升级注意:
- 不要在未备份数据库的情况下升级。
- 不要随意更换 MariaDB 主版本。
- 如果从
latest切到固定版本,要先确认版本迁移说明。 - 升级后检查登录、书库列表、封面、阅读器、OPDS 和 BookDrop。
- 如果使用 1Panel 编辑容器配置,注意它可能覆盖手工修改过的 compose 文件。
16. 常见故障排查
页面打不开
检查容器:
<code class="language-bash">docker ps --format "table {{.Names}}t{{.Status}}t{{.Ports}}" # 查看 BookLore 和 MariaDB 是否运行
docker compose logs --tail 100 booklore # 查看 BookLore 最近 100 行日志
docker compose logs --tail 100 mariadb # 查看 MariaDB 最近 100 行日志
</code>
检查端口:
<code class="language-bash">ss -tlnp | grep 6060 # 查看宿主机是否监听 6060 端口 curl -I http://127.0.0.1:6060/ # 从服务器本机测试 BookLore 是否响应 </code>
数据库连接失败
重点检查:
.env中的DB_PASSWORD。.env中的DATABASE_URL。docker-compose.yml里的数据库服务名是否和 JDBC 地址一致。- MariaDB 健康检查是否通过。
文件上传失败
检查反向代理上传限制:
<code class="language-nginx">client_max_body_size 1024m; # 放宽上传大小限制,适合较大的 PDF 或漫画压缩包 </code>
检查目录权限:
<code class="language-bash">ls -la /opt/1panel/docker/compose/booklore # 查看 BookLore 部署目录权限 ls -la /opt/1panel/docker/compose/booklore/books # 查看书库目录权限 sudo chown -R 1000:1000 /opt/1panel/docker/compose/booklore/books # 修正书库目录属主 sudo chown -R 1000:1000 /opt/1panel/docker/compose/booklore/bookdrop # 修正 BookDrop 目录属主 </code>
NAS 书库异常
如果书库是 NFS、SMB、CIFS 或其他网络挂载:
<code class="language-env"># 网络存储模式会避免 BookLore 直接改写网络书库文件 DISK_TYPE=NETWORK </code>
还要检查:
- 挂载是否稳定。
- 容器是否能看到挂载目录。
- UID/GID 是否有读取权限。
- NAS 是否有快照备份。
元数据匹配不准
常见原因:
- 文件名不规范。
- 中文书名和外文元数据混淆。
- 套装书和单本书标题相似。
- 扫描版 PDF 缺少内嵌信息。
- 作者译名不统一。
处理建议:
- 入库前先在 BookDrop 审核。
- 同一本书多格式先放在一个文件夹。
- 系列书保留卷号。
- 必要时手动编辑元数据。
17. 安全清单
上线前检查:
- 使用 HTTPS。
- 管理员账号使用强密码。
- 不公开无认证 OPDS。
- 不公开数据库端口。
.env不分享、不上传公开仓库。- 反向代理限制上传大小但不要无限放开。
- NAS 书库使用
DISK_TYPE=NETWORK。 - 数据库和书库目录都有备份。
- 外网访问时尽量加反向代理认证或访问控制。
18. 可分享版发布前检查
分享笔记前,搜索这些关键词:
<code class="language-text">192.168. # 检查是否残留内网 IP yourdomain # 检查是否残留个人域名或个人标识 password # 检查是否残留真实密码 DB_PASSWORD= # 检查是否残留真实数据库密码 MYSQL_ROOT_PASSWORD= # 检查是否残留真实 root 密码 /mnt/ # 检查是否残留个人挂载路径 </code>
如果能搜到真实信息,先替换成占位符:
<code class="language-text">YOUR_SERVER_LAN_IP # 内网服务器 IP 占位符 books.example.com # 示例域名占位符 CHANGE_ME_DB_PASSWORD # 数据库密码占位符 CHANGE_ME_MYSQL_ROOT_PASSWORD # MariaDB root 密码占位符 /path/to/books # 书库路径占位符 </code>
19. 一句话结论
BookLore 的价值在于:它把电子书文件、元数据、阅读器、阅读进度、书架、系列、OPDS 和设备同步整合成一个自托管书库中心。部署时最重要的不是“跑起来”,而是把存储模式、数据库备份、书库备份和 HTTPS 入口设计好。
