# Readest Lite — 部署与验证文档 ## 1. 准备工作 ### 1.1 系统要求 - Docker 24+ - Docker Compose v2+ - 至少 1GB 可用磁盘空间(数据库 + 书籍存储) ### 1.2 获取代码 ```bash git clone https://github.com/cshdotcom/readest-lite.git cd readest-lite ``` > **注意**:本仓库不再依赖 Git submodule。原 readest 项目的 `packages/foliate-js`、`packages/simplecc-wasm` 等是 submodule,但本仓库的 `Dockerfile` 已改为在构建时直接 `git clone --depth 1` 这两个 web 构建必需的子模块,所以 `git clone` 时**不需要** `--recursive` 参数。 ### 1.3 配置环境变量 ```bash cp .env.example .env ``` **必填项**(编辑 `.env`): ```bash # 管理员账号 ADMIN_EMAIL=your-email@example.com ADMIN_PASSWORD=YourStrongPassword123! # JWT 密钥(必须 32+ 字符,强烈建议随机) JWT_SECRET=$(openssl rand -hex 32) # 在 shell 中执行后填回 ``` **可选配置**: ```bash # DeepL 翻译(不配置则翻译功能不可用) DEEPL_FREE_API_KEYS=your-free-key:fx DEEPL_PRO_API_KEYS=your-pro-key # AI Gateway(不配置则 AI 聊天不可用) AI_GATEWAY_API_KEY=your-key ``` ## 2. 启动 ### 2.1 Docker Compose(推荐) ```bash docker compose up -d --build ``` 首次构建约 5-10 分钟(包含 pnpm install + Next.js build + Prisma generate)。 ### 2.2 直接 Docker ```bash docker build -t readest-lite . docker run -d \ --name readest-lite \ -p 8225:8225 \ --env-file .env \ -v readest_data:/data \ readest-lite ``` ### 2.3 查看启动日志 ```bash docker logs -f readest-lite ``` 预期输出: ``` [entrypoint] initializing SQLite database... [entrypoint] ensuring admin user... [init] admin user created: your-email@example.com (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) [init] done. [entrypoint] starting Next.js on port 8225... ▲ Next.js 16.x - Local: http://0.0.0.0:8225 ✓ Ready in 2.3s ``` ## 3. 验证 ### 3.1 基础访问 ```bash curl http://localhost:8225/ # 应返回登录页 HTML ``` ### 3.2 登录测试 ```bash # 获取 access_token TOKEN=$(curl -s http://localhost:8225/auth/v1/token?grant_type=password \ -H "Content-Type: application/json" \ -H "apikey: anon" \ -d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" \ | jq -r .access_token) echo "Token: $TOKEN" ``` ### 3.3 验证同步 API ```bash # 拉取初始同步数据 curl -s "http://localhost:8225/api/sync?since=0" \ -H "Authorization: Bearer $TOKEN" | jq . # 预期:{"books":[{"id":"0000...","book_hash":"0000...",...}],"configs":[],"notes":[],"statBooks":[],"statPages":[]} # 推送一本书 curl -s -X POST "http://localhost:8225/api/sync" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"books":[{"hash":"test123","metaHash":"meta123","format":"EPUB","title":"Test Book","author":"Author","createdAt":1700000000000,"updatedAt":1700000000000}]}' # 预期:{"books":[...],"configs":[],"notes":[]} ``` ### 3.4 验证存储 API ```bash # 申请上传 URL UPLOAD_RESP=$(curl -s -X POST "http://localhost:8225/api/storage/upload" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"fileName":"Readest/Books/test.epub","fileSize":1024,"bookHash":"test123"}') UPLOAD_URL=$(echo "$UPLOAD_RESP" | jq -r .uploadUrl) FILE_KEY=$(echo "$UPLOAD_RESP" | jq -r .fileKey) echo "Upload URL: $UPLOAD_URL" echo "File Key: $FILE_KEY" # 实际上传文件(模拟客户端 PUT) echo "test content" | curl -s -X PUT "$UPLOAD_URL" --data-binary @- # 预期:{"ok":true} # 申请下载 URL DOWNLOAD_URL=$(curl -s "http://localhost:8225/api/storage/download?fileKey=$FILE_KEY" \ -H "Authorization: Bearer $TOKEN" | jq -r .downloadUrl) # 下载文件 curl -s "$DOWNLOAD_URL" # 预期:test content ``` ### 3.5 验证分享功能 ```bash # 创建分享 SHARE_RESP=$(curl -s -X POST "http://localhost:8225/api/share/create" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"bookHash":"test123","expirationDays":7,"title":"Test Book","format":"EPUB"}') SHARE_TOKEN=$(echo "$SHARE_RESP" | jq -r .token) echo "Share URL: http://localhost:8225/s/$SHARE_TOKEN" # 公开访问分享元数据(无需 token) curl -s "http://localhost:8225/api/share/$SHARE_TOKEN" | jq . # 预期:{"title":"Test Book","author":null,"format":"EPUB","size":1024,...} # 撤销分享 curl -s -X POST "http://localhost:8225/api/share/$SHARE_TOKEN/revoke" \ -H "Authorization: Bearer $TOKEN" # 预期:204 No Content # 再次访问应返回 410 curl -s "http://localhost:8225/api/share/$SHARE_TOKEN" # 预期:{"error":"Share has been revoked","code":"revoked"} ``` ### 3.6 验证 Supabase Auth 兼容性 ```bash # supabase-js 启动时会拉 settings curl -s "http://localhost:8225/auth/v1/settings" | jq . # 预期:{"external":{"email":false,"phone":false},"disable_signup":true,...} # 获取当前用户 curl -s "http://localhost:8225/auth/v1/user" \ -H "Authorization: Bearer $TOKEN" | jq .user.email # 预期:"your-email@example.com" # 刷新 token REFRESH=$(curl -s "http://localhost:8225/auth/v1/token?grant_type=password" \ -H "Content-Type: application/json" -H "apikey: anon" \ -d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" | jq -r .refresh_token) curl -s -X POST "http://localhost:8225/auth/v1/token?grant_type=refresh_token" \ -H "Content-Type: application/json" -H "apikey: anon" \ -d "{\"refresh_token\":\"$REFRESH\"}" | jq .access_token # 预期:新 token 字符串 # 注册应被拒绝 curl -s -X POST "http://localhost:8225/auth/v1/signup" \ -H "Content-Type: application/json" -H "apikey: anon" \ -d '{"email":"new@example.com","password":"123"}' -w "\n%{http_code}\n" # 预期:403 + {"error_code":"signup_disabled",...} ``` ### 3.7 浏览器端验证 1. 打开 `http://localhost:8225` 2. 应跳转到 `/auth`,仅显示邮箱密码表单(无社交登录、无注册链接) 3. 用 ADMIN_EMAIL / ADMIN_PASSWORD 登录 4. 跳转到 `/library` 5. 上传一本 EPUB → 应能打开阅读 6. 修改阅读进度 → 刷新页面 → 进度保留 7. 设置菜单中无 "Upgrade to Readest Premium" 项 8. 进入 `/user` 页面:无方案对比卡片,无 Checkout 组件 9. 翻译一段文字:不报配额错误 10. 创建分享链接 → 复制到另一个浏览器(无登录)→ 应能看到分享落地页 ## 4. 数据备份 ### 4.1 数据卷位置 - `/data/db/readest.db` — SQLite 数据库 - `/data/books/` — 所有书籍文件 + 封面 - `/data/inbox/` — Send to Readest 入站文件 ### 4.2 备份命令 ```bash # 完整备份 docker run --rm -v readest_data:/data -v $(pwd):/backup alpine \ tar czf /backup/readest-backup-$(date +%Y%m%d).tar.gz /data # 仅备份数据库 docker cp readest-lite:/data/db/readest.db ./readest-$(date +%Y%m%d).db ``` ### 4.3 恢复 ```bash docker stop readest-lite docker run --rm -v readest_data:/data -v $(pwd):/backup alpine \ tar xzf /backup/readest-backup-20260101.tar.gz -C / docker start readest-lite ``` ## 5. 升级 ### 5.1 拉取新镜像 ```bash docker compose pull docker compose up -d ``` 容器启动时 `prisma db push` 会自动同步 schema(如有变更)。**数据库数据不会丢失**。 ### 5.2 修改管理员密码 编辑 `.env` 中的 `ADMIN_PASSWORD`,然后: ```bash docker compose restart ``` 启动脚本会检测到密码变化并更新数据库中的管理员密码。 ## 6. 故障排查 ### 6.1 容器启动失败 ```bash docker logs readest-lite 2>&1 | tail -50 ``` 常见问题: | 错误 | 解决方案 | |---|---| | `ADMIN_EMAIL and ADMIN_PASSWORD must be set` | 检查 .env 文件 | | `Prisma schema validation error` | 检查 prisma/schema.prisma 是否完整 | | `EADDRINUSE :::8225` | 端口被占用,修改 docker-compose.yml 端口映射 | | `argon2: cannot find module` | Dockerfile 中 argon2 拷贝路径错误,检查 build stage | ### 6.2 登录失败 ```bash # 验证 admin 账号是否创建成功 docker exec readest-lite sqlite3 /data/db/readest.db \ "SELECT id, email FROM User;" ``` ### 6.3 同步不工作 ```bash # 检查 token 是否有效 curl -s "http://localhost:8225/auth/v1/user" \ -H "Authorization: Bearer $TOKEN" | jq . # 如果返回 401,说明 token 过期,需要重新登录 ``` ### 6.4 文件上传失败 ```bash # 检查 /data/books 是否可写 docker exec readest-lite ls -la /data/books/ # 检查签名 URL 是否能解析 docker exec readest-lite sqlite3 /data/db/readest.db \ "SELECT id, fileKey, fileSize FROM File LIMIT 10;" ``` ## 7. 性能调优 ### 7.1 SQLite WAL 模式 默认 Prisma 已启用 WAL 模式,提升并发读写性能。如需确认: ```bash docker exec readest-lite sqlite3 /data/db/readest.db "PRAGMA journal_mode;" # 预期:wal ``` ### 7.2 数据库大小 ```bash docker exec readest-lite du -sh /data/db/ # 单用户场景,10万本书 + 100万条笔记 ≈ 200-500MB ``` ### 7.3 文件存储大小 ```bash docker exec readest-lite du -sh /data/books/ ``` ## 8. GitHub Actions 部署 ### 8.1 自动构建(已配置) 仓库已自带两个 workflow: - `.github/workflows/ci.yml` — 每次 push 到 main/master 时构建 Docker 镜像 + 跑容器启动 smoke test - `.github/workflows/docker-image.yml` — push 到 main/master 或打 `v*` tag 时构建并推送镜像到 GHCR **CI 不需要任何 secret 配置**:`GITHUB_TOKEN` 是 Actions 自动提供的,用于推送 GHCR。 ### 8.2 触发镜像构建 ```bash # 推送到 main 分支自动构建(tag: ghcr.io//readest-lite:main) git push origin main # 打 tag 触发版本镜像 git tag v0.1.0 git push origin v0.1.0 # 产出: # ghcr.io//readest-lite:0.1.0 # ghcr.io//readest-lite:0.1 # ghcr.io//readest-lite:sha- ``` ### 8.3 从 GHCR 拉取运行 构建成功后: ```bash docker pull ghcr.io/cshdotcom/readest-lite:main docker run -d \ --name readest-lite \ -p 8225:8225 \ -e ADMIN_EMAIL=admin@example.com \ -e ADMIN_PASSWORD=YourPassword123! \ -e JWT_SECRET=$(openssl rand -hex 32) \ -v readest_data:/data \ ghcr.io/cshdotcom/readest-lite:main ``` ### 8.4 本地 Docker 构建(无 GitHub Actions) ```bash git clone https://github.com/cshdotcom/readest-lite.git cd readest-lite cp .env.example .env # 编辑 .env 设置 ADMIN_EMAIL/ADMIN_PASSWORD/JWT_SECRET docker compose up -d --build ``` Dockerfile 会自动 `git clone --depth 1` 需要的 foliate-js 与 simplecc-wasm 子模块,**不依赖**外部 `git submodule update --init`。 ## 9. 安全建议 1. **修改默认 JWT_SECRET**:使用 `openssl rand -hex 32` 生成 2. **使用强管理员密码**:至少 16 字符,包含大小写字母、数字、符号 3. **反向代理 + HTTPS**:生产环境强烈建议在前面加 Nginx/Caddy 做 TLS 终止 4. **限制访问**:单账号模式没有 RLS,任何人拿到 token 都能访问所有数据;务必保护好管理员凭证 5. **定期备份**:至少每天备份一次 /data 卷 ## 10. 与原版差异说明 | 功能 | 原版 | Lite 版 | |---|---|---| | 注册 | 邮箱/社交登录/OAuth | 完全禁用,仅一个管理员 | | Pro/免费方案 | 4 套(free/plus/pro/purchase) | 单一 pro,所有功能无条件开放 | | 支付 | Stripe + Apple IAP + Google IAP | 完全删除 | | 配额 | 500MB/5GB/20GB | 无限 | | 数据库 | Postgres + Supabase RLS | SQLite(单用户无需 RLS) | | 对象存储 | R2/S3 + 预签名 URL | 本地文件系统 + HMAC 签名 URL | | 邮件入站 | Cloudflare Email Worker | 不支持(API 保留) | | 同步协议 | 完全一致 | 完全一致(1:1 复刻) | | 分享 | 完全一致 | 完全一致(1:1 复刻) | | 阅读器内核 | foliate-js | 完全一致(零改动) | | AI/TTS/翻译 | 完全一致 | 完全一致(透传) |