三股水
BookOrbit 自托管阅读平台完整部署教程
本文从 Obsidian 撰写发布

BookOrbit 自托管阅读平台完整部署教程

本文档基于一次真实的部署过程整理,涵盖了从零开始部署 BookOrbit 的全流程,以及过程中遇到的各种问题及解决方案。

一、BookOrbit 是什么?

BookOrbit 是一个开源的自托管数字图书馆和阅读平台,你可以把它理解为「私有云书架」—— 所有数据都保存在你自己的服务器上,不需要依赖任何第三方服务。

它能做什么?

📚 统一管理多种阅读内容
支持 EPUB、KEPUB、MOBI、AZW3、PDF 等电子书格式,以及 CBZ/CBR 漫画和 M4B/MP3/FLAC 有声书。所有内容在一个平台上管理,不需要在多个应用之间切换。

🔍 自动补全书籍信息
从 Google Books、Amazon、Goodreads、Open Library 等 9 个来源自动抓取封面、作者、简介等元数据,并支持字段级锁定,你可以决定哪些信息被更新、哪些保留。

📱 多设备阅读同步
支持与 Kobo 阅读器深度集成,书籍自动推送,阅读进度双向同步。也支持 OPDS 协议,可连接 KOReader、Thorium、Moon Plus Reader 等第三方阅读应用。对于 Kindle 用户,支持 Send-to-Kindle 邮件投递。

📊 阅读统计与分析
提供每日阅读时间统计、热力图、连续阅读记录、阅读目标追踪等功能,无需依赖 Goodreads 等第三方服务。

👨‍👩‍👧‍👦 家庭共享
支持多用户独立账户,每个人的阅读进度和数据相互隔离,可与家人共享书库。

为什么选它而不是 Calibre 或 Kavita?

  • 相比 Calibre:BookOrbit 提供更现代化的 Web 界面和 Docker 部署体验,同时原生支持有声书和漫画管理,不像 Calibre 需要各种插件和配置。
  • 相比 Kavita:部分用户选择 BookOrbit 是因为它没有将高级功能置于付费墙之后,功能完全开源。
  • 相比 Audiobookshelf:BookOrbit 胜在支持 Kobo/KOReader 同步,且多媒体库的展示和管理方式更统一。

二、环境要求

  • 操作系统:Linux (Ubuntu/Debian 推荐)
  • 配置要求:至少 2GB 内存,建议 4GB+(尤其是需要同时运行其他 Docker 服务时)
  • 软件依赖:Docker & Docker Compose
  • 网络:能够访问 GitHub Container Registry (ghcr.io),国内可能较慢

三、完整部署步骤

以下所有命令均在服务器终端执行。

第一步:创建项目目录

mkdir -p /wwwroot/bookorbit
cd /wwwroot/bookorbit

第二步:创建 docker-compose.yml

cat > docker-compose.yml << 'EOF'
services:
  bookorbit:
    image: ghcr.io/bookorbit/bookorbit:latest
    container_name: bookorbit-app
    ports:
      - "8090:3000"
    volumes:
      - ./data:/app/data
      - ./books:/books
      - ./auto_ingest:/app/data/book-dock
    environment:
      - DB_HOST=postgres
      - DB_PORT=5432
      - PGUSER=bookorbit
      - PGPASSWORD=bookorbit@123
      - PGDATABASE=bookorbit
      - POSTGRES_USER=bookorbit
      - POSTGRES_PASSWORD=bookorbit@123
      - POSTGRES_DB=bookorbit
      - JWT_SECRET=your_jwt_secret_here_min_32_chars
      - SETUP_BOOTSTRAP_TOKEN=your_setup_token_here
      - HOST=0.0.0.0
      - PORT=3000
      - NODE_ENV=production
    depends_on:
      - postgres
    restart: unless-stopped
    networks:
      - bookorbit-net

  postgres:
    image: pgvector/pgvector:pg15
    container_name: bookorbit-db
    environment:
      - POSTGRES_USER=bookorbit
      - POSTGRES_PASSWORD=bookorbit@123
      - POSTGRES_DB=bookorbit
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    restart: unless-stopped
    networks:
      - bookorbit-net

networks:
  bookorbit-net:
    driver: bridge
EOF
   

第三步:生成安全密钥

BookOrbit 在生产环境强制要求两个安全密钥。执行以下命令生成并自动替换到配置文件中:

JWT_SECRET=$(openssl rand -base64 32 | tr -d '\n')
SETUP_TOKEN=$(openssl rand -base64 16 | tr -d '\n')
echo "JWT_SECRET=$JWT_SECRET"
echo "SETUP_BOOTSTRAP_TOKEN=$SETUP_TOKEN"

sed -i "s|your_jwt_secret_here_min_32_chars|$JWT_SECRET|g" docker-compose.yml
sed -i "s|your_setup_token_here|$SETUP_TOKEN|g" docker-compose.yml

第四步:设置目录权限

这是最容易忽略但最关键的一步。Docker 容器内运行的用户 UID 是 1000,如果宿主机目录权限不对,上传文件时会报 Internal Server Error。

mkdir -p data books auto_ingest pgdata
sudo chown -R 1000:1000 data books auto_ingest pgdata
sudo chmod -R 755 data books auto_ingest pgdata

第五步:启动服务

docker-compose up -d
docker-compose ps
docker-compose logs -f bookorbit

第六步:验证部署

curl -I http://127.0.0.1:8090

看到 HTTP/1.1 200 OK 表示部署成功。

四、常见问题及解决方案

Q1: 镜像拉取缓慢

国内访问 GitHub Container Registry 速度较慢,可配置 Docker 镜像加速器,或耐心等待。

Q2: 端口被占用

错误信息:Bind for 0.0.0.0:8090 failed: port is already allocated

查看端口占用:
sudo lsof -i :8090
sudo netstat -tlnp | grep 8090

解决方案:修改 docker-compose.yml 中的端口映射为其他端口,如 "8099:3000"

Q3: 数据库连接失败

错误信息:getaddrinfo ENOTFOUND postgres

原因:容器不在同一个 Docker 网络中,或网络未正确创建。

解决方案:
docker-compose down
docker-compose up -d
docker network inspect bookorbit_bookorbit-net

Q4: 缺少 JWT_SECRET 或 SETUP_BOOTSTRAP_TOKEN

错误信息:
JWT_SECRET: Invalid input: expected string, received undefined
SETUP_BOOTSTRAP_TOKEN is required in production

解决方案:按照部署步骤第三步生成并配置这两个环境变量。

Q5: 容器内端口映射错误

现象:容器状态显示 Running,但 curl 返回 Connection reset by peer。

原因:BookOrbit 容器内实际监听的是 3000 端口,如果映射为 8090:8080 会导致连接被重置。

解决方案:修改端口映射为 "8090:3000"。

Q6: extension "vector" is not available

错误信息:extension "vector" is not available

原因:使用了普通 postgres 镜像,缺少 BookOrbit 所需的 vector 扩展。

解决方案:使用 pgvector/pgvector:pg15 镜像替代 postgres:15-alpine。

Q7: 前端上传文件返回 Internal Server Error

原因:目录权限不足,容器用户无法写入挂载目录。

解决方案:
sudo chown -R 1000:1000 /wwwroot/bookorbit/data
sudo chown -R 1000:1000 /wwwroot/bookorbit/books
sudo chmod -R 755 /wwwroot/bookorbit/data
sudo chmod -R 755 /wwwroot/bookorbit/books

Q8: 服务器崩溃/卡死,所有服务无法访问

原因及解决方案:

  • 通过宝塔面板文件管理器上传电子书会触发文件监控事件,可能导致解析死锁 —— 禁止使用宝塔面板传书!
  • 大量书籍同时扫描时 CPU/内存耗尽 —— 分批导入,每次 10-20 本
  • 容器未限制资源使用 —— 限制容器 CPU 和内存

紧急恢复命令:
docker kill bookorbit-app
systemctl stop docker

限制资源使用:
docker update --cpus=0.5 --memory=512M bookorbit-app
docker update --cpus=0.5 --memory=512M bookorbit-db

Q9: Setup token 页面为空,无法填写

原因:前端缓存了旧页面,环境变量未正确注入。

解决方案:

  1. 确认 docker-compose.yml 中 SETUP_BOOTSTRAP_TOKEN 已配置
  2. 浏览器按 Ctrl+F5 强制刷新,或使用无痕模式访问
  3. 如果页面仍要求输入,直接粘贴配置文件中的 Token 值即可

Q10: 外部无法访问

排查步骤:
ufw status
ufw allow 8090/tcp

同时检查云服务商安全组,确保 8090 端口已放行。

五、错误原因总结

本次部署过程中遇到的所有错误及根本原因:

  1. 镜像拉取缓慢 —— 国内访问 GitHub Container Registry 速度慢
  2. 端口 8090 被占用 —— 其他 Docker 容器占用了该端口
  3. getaddrinfo ENOTFOUND postgres —— 容器未在同一 Docker 网络中
  4. JWT_SECRET 未定义 —— 未设置 JWT_SECRET 环境变量
  5. SETUP_BOOTSTRAP_TOKEN 未定义 —— 未设置 SETUP_BOOTSTRAP_TOKEN 环境变量
  6. extension "vector" is not available —— 使用了普通 PostgreSQL 镜像
  7. Connection reset by peer —— 端口映射错误,容器内监听 3000 但映射到 8080
  8. Internal Server Error —— 目录权限不足,容器用户无法写入
  9. 服务器完全崩溃 —— 宝塔面板上传电子书触发文件监控死锁
  10. Setup token 页面为空 —— 前端缓存未刷新

关键教训:

  1. 生产环境必须设置 JWT_SECRET 和 SETUP_BOOTSTRAP_TOKEN
  2. 端口映射必须与容器内监听端口一致(3000)
  3. 必须使用 pgvector/pgvector:pg15 作为数据库镜像
  4. 目录权限必须在启动前设置(UID 1000)
  5. 绝对禁止用宝塔面板文件管理器上传电子书
  6. 容器必须限制资源使用
  7. 配置变更后需强制刷新浏览器

六、最终配置文件

以下是经过完整测试的最终 docker-compose.yml:

services:
bookorbit:

image: ghcr.io/bookorbit/bookorbit:latest
container_name: bookorbit-app
ports:
  - "8090:3000"
volumes:
  - ./data:/app/data
  - ./books:/books
  - ./auto_ingest:/app/data/book-dock
environment:
  - DB_HOST=postgres
  - DB_PORT=5432
  - PGUSER=bookorbit
  - PGPASSWORD=bookorbit@123
  - PGDATABASE=bookorbit
  - POSTGRES_USER=bookorbit
  - POSTGRES_PASSWORD=bookorbit@123
  - POSTGRES_DB=bookorbit
  - JWT_SECRET=k5z0BcJsS4g3H+ih9ghoOjJW1ij+woT6pV4fXaBarvI=
  - SETUP_BOOTSTRAP_TOKEN=GYjK8vPqXXMYZ26H3AzdHw==
  - HOST=0.0.0.0
  - PORT=3000
  - NODE_ENV=production
depends_on:
  - postgres
restart: unless-stopped
networks:
  - bookorbit-net

postgres:

image: pgvector/pgvector:pg15
container_name: bookorbit-db
environment:
  - POSTGRES_USER=bookorbit
  - POSTGRES_PASSWORD=bookorbit@123
  - POSTGRES_DB=bookorbit
volumes:
  - ./pgdata:/var/lib/postgresql/data
restart: unless-stopped
networks:
  - bookorbit-net

networks:
bookorbit-net:

driver: bridge

七、使用指南

添加书籍的三种方式

方式一:Web 界面上传(推荐)
登录 BookOrbit → 进入书库 → 点击上传按钮 → 选择文件

方式二:自动摄入目录(Book Dock)
将书籍放入 /wwwroot/bookorbit/auto_ingest/ 目录,系统会自动识别并导入
cp /path/to/book.epub /wwwroot/bookorbit/auto_ingest/

方式三:SSH/SCP 上传到 books 目录
scp -P 22 book.epub root@your_ip:/wwwroot/bookorbit/books/
然后在 Web 界面手动触发扫描

常用 Docker 命令

docker-compose up -d 启动
docker-compose down 停止
docker-compose logs -f 查看日志
docker-compose restart 重启
docker-compose pull && docker-compose up -d 更新镜像并重启

目录结构说明

/wwwroot/bookorbit/
├── docker-compose.yml
├── data/ 应用数据(元数据、封面、配置等)
├── books/ 主书库目录(存放已整理的电子书)
├── auto_ingest/ 自动摄入目录(Book Dock,用于导入新书)
└── pgdata/ PostgreSQL 数据库文件

首次使用流程

  1. 浏览器访问 http://你的服务器IP:8090
  2. 创建管理员账户
  3. 在设置中创建书库(Library),扫描目录填 /books
  4. 开始上传或导入书籍

八、重要教训

绝对禁止的操作

  1. 使用宝塔面板文件管理器上传电子书到 BookOrbit 目录 → 会触发文件监控导致服务器完全崩溃
  2. 一次性上传大量书籍 → 资源耗尽,建议每次 10-20 本
  3. 不设置资源限制 → 容器可能耗尽宿主机资源
  4. 忽略目录权限 → 导致上传失败

最佳实践

  1. 通过 Web 界面上传是最安全的方式
  2. 使用 auto_ingest 目录实现自动处理,省心省力
  3. 分批导入书籍,避免负载过高
  4. 开启容器的 CPU 和内存限制
  5. 定期备份 data、books、pgdata 三个目录

关键配置点速查

端口映射:宿主机:容器,容器内实际监听端口是 3000
数据库镜像:必须使用 pgvector/pgvector:pg15,包含 vector 扩展
安全密钥:JWT_SECRET 和 SETUP_BOOTSTRAP_TOKEN 必须设置
目录权限:容器用户 UID 是 1000,需 chown -R 1000:1000
资源限制:建议 --cpus=0.5 --memory=512M

九、结语

遇到问题时,查看日志是解决问题的第一步:

docker-compose logs -f bookorbit

BookOrbit 是一个功能强大的自托管阅读平台,虽然部署过程中可能会遇到各种问题,但只要按照本文档的步骤逐一排查,最终一定能顺利运行。祝你的私人书库顺利搭建!

😊
提交