• 欢迎访问誉卿博客,推荐使用最新版火狐浏览器和 Chrome 浏览器访问本网站。

  • 初不解禅心未住,悟后逍遥游处方。 山水有情皆由心,见山见水皆天堂。

BookLore 自托管数字书库部署与运维笔记

NAS yqdnsjs 2个月前 (08-16) 228次浏览 扫描二维码
booklore-web-ui-cover.jpg

目标:用 Docker Compose 在 VPS、NAS 或 1Panel 管理的服务器上部署 BookLore,搭建一个可自托管、多用户、可阅读、可同步、可整理元数据的数字书库。

1. 项目简介

BookLore 是一个自托管、多用户数字书库应用,目标是把电子书、漫画、元数据、阅读进度、设备同步和导入流程统一放在自己的服务器里管理。

它适合用来管理:

  • EPUB
  • PDF
  • MOBI / AZW3 等常见电子书格式
  • CBZ / CBR 等漫画格式
  • 多格式同书
  • 系列书籍
  • 多用户家庭书库

官方项目描述中提到,BookLore 支持智能书架、自动元数据、Kobo 与 KOReader 同步、BookDrop 导入、OPDS、以及 EPUB/PDF/漫画的内置阅读器。

官方参考链接:

2. 功能与优点

features-map.jpg

智能书架

BookLore 支持自定义书架和动态规则书架,可以按作者、系列、格式、标签、阅读状态、元数据字段等条件筛选图书。对于大型书库来说,这比单纯按文件夹浏览更灵活。

自动元数据

BookLore 可以从 Google Books、Open Library、Amazon 等来源拉取封面、简介、评分、评论等元数据。自动匹配后仍可人工编辑,适合处理标题不规范、系列信息缺失、封面错误等情况。

内置阅读器

浏览器里可以直接阅读 EPUB、PDF 和漫画文件,并记录阅读进度。这样在手机、平板、电脑上打开同一个 Web 地址,就能继续阅读。

多设备同步

BookLore 支持 OPDS,也支持 Kobo、KOReader 等阅读链路。它可以作为电子书客户端和硬件阅读器之间的书库中心。

多用户

多用户环境下,每个用户可以有自己的书架、阅读进度、偏好和访问范围。家庭书库或小团队共享书库会比较方便。

BookDrop 自动导入

BookDrop 是一个投递目录,把书放进去后,BookLore 会自动检测、提取信息、拉取元数据,并进入审核导入流程。适合批量整理新书。

自托管可控

书库文件、数据库和配置都在自己的服务器里,备份策略、访问权限、反向代理和内网访问都可自己控制。

3. 推荐架构

architecture.jpg

推荐结构:

<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. 手动部署流程

bookdrop-flow.jpg

整体流程:

  1. 安装 Docker 和 Docker Compose。
  2. 创建部署目录。
  3. 创建 .env。
  4. 创建 docker-compose.yml。
  5. 启动 MariaDB 和 BookLore。
  6. 登录 Web 页面创建管理员账号。
  7. 添加书库目录。
  8. 配置元数据、书架、BookDrop、OPDS。
  9. 设置 HTTPS 反向代理。
  10. 配置备份和升级策略。

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 的典型流程:

  1. 把文件放入 bookdrop/。
  2. BookLore 自动检测新增文件。
  3. 解析文件名、格式和基础元数据。
  4. 从元数据源拉取封面、简介、作者、评分等信息。
  5. 在 Web 页面审核。
  6. 确认后导入书库。

如果元数据匹配错误,优先在入库前人工修正。尤其是:

  • 同名不同作者。
  • 套装书。
  • 多卷系列。
  • 中英文混合书名。
  • 扫描版 PDF。
  • 漫画卷号。

13. OPDS、Kobo 与 KOReader

BookLore 可以作为电子书客户端的服务端书库。

常见用法:

  • 支持 OPDS 的阅读器可通过 OPDS 地址浏览书库。
  • Kobo 可用于同步书籍和阅读进度。
  • KOReader 可用于跨设备阅读体验。

公开部署 OPDS 时要注意:

  • 不要把无认证的 OPDS 暴露到公网。
  • 尽量放在 HTTPS 后面。
  • 多用户环境下检查每个用户的书库权限。
  • 如果走反向代理,确认外部访问地址和代理头设置正确。

14. 备份与恢复

backup-scope.jpg

必须备份:

<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 入口设计好。

喜欢 (1)