Readest 懒猫本地托管教程

zhyuer

发布于171天前
你相信光吗
微信读书会员过期后,我一直在寻找对应的开源平替工具,支持“读书+听书”一体的,最后发现了 readest 这款开源工具。搜索懒猫商店发现已存在这块应用。下载使用后发现这只是一个 Web 客户端,并不具备服务端的功能(书籍、进度、标注、笔记多端同步),于是开始研究懒猫本地托管方法。


https://appstore.lazycat.cloud/#/shop/detail/wcloud.gblw.app.readest


## 参考链接

- https://developer.lazycat.cloud/advanced-dev-image.html
- https://developer.lazycat.cloud/advanced-depends.html
- https://developer.lazycat.cloud/spec/manifest.html
- https://github.com/readest/readest/wiki/Supabase-Tables-Schema-for-Sync-API

## 先说结果

- 一个支持跨端同步(书籍、进度、标注、笔记等)的 Web 客户端
- PC 端、IOS 端体验良好,支持 Edge TTS,音色优于系统自带 TTS,(中国大陆不在Edge TTS 服务范围)

![snip_1765684454010.png](https://dl.playground.lazycat.cloud/guidelines/964/28c68a46-6d2c-4bb9-b589-5266a2310e97.png "snip_1765684454010.png")
- readest 镜像需要本地构建,部署较繁琐,折腾部署方案就花了差不多整一周时间
- 共 18 个容器,整体内存占用约 3GB
- Android 端 Web 兼容性有问题,需开启滚动模式,展开/查看菜单项需要拉到顶部或底部才能显示

![snip_1765684354035.png](https://dl.playground.lazycat.cloud/guidelines/964/5d03ee93-98cb-4b2d-8c83-a8c5fcba0cc6.png "snip_1765684354035.png")

## 部署步骤

1. 克隆 readest 项目到本地

```shell
git clone https://github.com/readest/readest/
```

2. 编辑配置文件 readest/apps/readest-app/.env.local

-  http://readestpro.zycat.heiyu.space, zycat 需替换为你自己的设备名称

```.env
#NEXT_PUBLIC_POSTHOG_KEY=YOUR_POSTHOG_KEY
#NEXT_PUBLIC_POSTHOG_HOST=YOUR_POSTHOG_HOST

NEXT_PUBLIC_SUPABASE_URL=http://readestpro.zycat.heiyu.space:8080
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE

NEXT_PUBLIC_STORAGE_FIXED_QUOTA=0

NEXT_PUBLIC_API_BASE_URL=http://readestpro.zycat.heiyu.space:8080

SUPABASE_ADMIN_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q

DEEPL_PRO_API_KEYS=YOUR_DEEPL_PRO_API_KEYS
DEEPL_FREE_API_KEYS=YOUR_DEEPL_FREE_API_KEYS

# r2, s3
NEXT_PUBLIC_OBJECT_STORAGE_TYPE=s3

#R2_TOKEN_VALUE=YOUR_R2_TOKEN_VALUE
#R2_ACCESS_KEY_ID=YOUR_R2_ACCESS_KEY_ID
#R2_SECRET_ACCESS_KEY=YOUR_R2_SECRET_ACCESS_KEY
#R2_BUCKET_NAME=YOUR_R2_BUCKET_NAME
#R2_ACCOUNT_ID=YOUR_R2_ACCOUNT_ID
#R2_REGION=YOUR_R2_REGION

S3_ENDPOINT=http://readestpro.zycat.heiyu.space:9000
S3_ACCESS_KEY_ID=readest
S3_SECRET_ACCESS_KEY=readest12345
S3_BUCKET_NAME=readest-books
S3_REGION=us-east-1
```

3. 本地构建 readest 镜像并推送到自己的懒猫盒子

- 需要将 zycat 替换为你的懒猫盒子名称

```shell
vi readest/Dockfile

# 在 RUN pnpm 行下新增
RUN pnpm --filter @readest/readest-app setup-vendors
---------------------------------------------------------
# readest 项目根目录
cd readest  

# 拉取所有子模块,默认的 git clone 不会自动拉取 submodule,需要额外执行
git submodule update --init --recursive

# 构建镜像,这一步可能需要魔法
lzc-docker build --network=host --platform linux/amd64 -t lzc/readestpro:latest .

# 重新 tag 镜像成 dev.$BOXNAME.heiyu.space 地址, $BOXNAME 为目标盒子名.
lzc-docker tag lzc/readestpro:latest dev.zycat.heiyu.space/lzc/readestpro:latest

# 推送镜像
lzc-docker push dev.zycat.heiyu.space/lzc/readestpro:latest

# 拉取镜像
lzc-docker pull dev.zycat.heiyu.space/lzc/readestpro:latest

lzc-docker images | grep readest
```

4. 完整配置文件 supabase/docker/.env

-  http://readestpro.zycat.heiyu.space, zycat 需替换为你自己的设备名称

```.env
############
# Secrets
# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION
############

POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
DASHBOARD_USERNAME=supabase
DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated
SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
VAULT_ENC_KEY=your-encryption-key-32-chars-min
PG_META_CRYPTO_KEY=your-encryption-key-32-chars-min


############
# Database - You can change these to any PostgreSQL database that has logical replication enabled.
############

POSTGRES_HOST=db
POSTGRES_DB=postgres
POSTGRES_PORT=5432
# default user is postgres


############
# Supavisor -- Database pooler
############
# Port Supavisor listens on for transaction pooling connections
POOLER_PROXY_PORT_TRANSACTION=6543
# Maximum number of PostgreSQL connections Supavisor opens per pool
POOLER_DEFAULT_POOL_SIZE=20
# Maximum number of client connections Supavisor accepts per pool
POOLER_MAX_CLIENT_CONN=100
# Unique tenant identifier
POOLER_TENANT_ID=your-tenant-id
# Pool size for internal metadata storage used by Supavisor
# This is separate from client connections and used only by Supavisor itself
POOLER_DB_POOL_SIZE=5


############
# API Proxy - Configuration for the Kong Reverse proxy.
############

KONG_HTTP_PORT=8000
KONG_HTTPS_PORT=8443


############
# API - Configuration for PostgREST.
############

PGRST_DB_SCHEMAS=public,storage,graphql_public


############
# Auth - Configuration for the GoTrue authentication server.
############

## General
SITE_URL=http://readestpro.zycat.heiyu.space:8080
ADDITIONAL_REDIRECT_URLS=
JWT_EXPIRY=3600
DISABLE_SIGNUP=false
API_EXTERNAL_URL=http://readestpro.zycat.heiyu.space:8080

## Mailer Config
MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify"
MAILER_URLPATHS_INVITE="/auth/v1/verify"
MAILER_URLPATHS_RECOVERY="/auth/v1/verify"
MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify"

## Email auth
ENABLE_EMAIL_SIGNUP=true
ENABLE_EMAIL_AUTOCONFIRM=true
SMTP_ADMIN_EMAIL=admin@example.com
SMTP_HOST=supabase-mail
SMTP_PORT=2500
SMTP_USER=fake_mail_user
SMTP_PASS=fake_mail_password
SMTP_SENDER_NAME=fake_sender
ENABLE_ANONYMOUS_USERS=false

## Phone auth
ENABLE_PHONE_SIGNUP=true
ENABLE_PHONE_AUTOCONFIRM=true


############
# Studio - Configuration for the Dashboard
############

STUDIO_DEFAULT_ORGANIZATION=Default Organization
STUDIO_DEFAULT_PROJECT=Default Project

# replace if you intend to use Studio outside of localhost
SUPABASE_PUBLIC_URL=http://readestpro.zycat.heiyu.space:8080

# Enable webp support
IMGPROXY_ENABLE_WEBP_DETECTION=true

# Add your OpenAI API key to enable SQL Editor Assistant
OPENAI_API_KEY=


############
# Functions - Configuration for Functions
############
# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.
FUNCTIONS_VERIFY_JWT=false


############
# Logs - Configuration for Analytics
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
############

# Change vector.toml sinks to reflect this change
# these cannot be the same value
LOGFLARE_PUBLIC_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-public
LOGFLARE_PRIVATE_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-private

# Docker socket location - this value will differ depending on your OS
DOCKER_SOCKET_LOCATION=/var/run/docker.sock

# Google Cloud Project details
GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID
GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER
```

5. 完整配置文件 lzc-manifest.yml 
-  readest 镜像需要本地构建、推送到自己的微服后引用
-  http://readestpro.zycat.heiyu.space, zycat 需替换为你自己的设备名称
```yml
lzc-sdk-version: '0.1'
name: ReadestPro
package: cloud.lazycat.app.readestpro
version: 1.0.0

application:
  healthcheck:
    - disable=true
    
  routes:
    - /=file:///lzcapp/pkg/content/www/

  subdomain: readestpro

  ingress:
    - protocol: tcp
      port: 8080
      service: nginx
    - protocol: tcp
      port: 9000
      service: minio
    - protocol: tcp
      port: 9001
      service: minio
    - protocol: tcp
      port: 3000
      service: studio
services:
  studio: 
    image: registry.lazycat.cloud/lmwf-zy/supabase/studio:143c7254d5ff8226
    depends_on: 
      - analytics
    environment:
      - HOSTNAME=0.0.0.0

      - STUDIO_PG_META_URL=http://meta:8080
      - POSTGRES_PORT=5432
      - POSTGRES_HOST=db
      - POSTGRES_DB=postgres
      - POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
      - PG_META_CRYPTO_KEY=your-encryption-key-32-chars-min

      - DEFAULT_ORGANIZATION_NAME=Default Organization
      - DEFAULT_PROJECT_NAME=Default Project
      - OPENAI_API_KEY=

      - SUPABASE_URL=http://kong:8000
      - SUPABASE_PUBLIC_URL=http://meta:8080
      - SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
      - SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
      - AUTH_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      
      - LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key-public
      - LOGFLARE_PUBLIC_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-public
      - LOGFLARE_PRIVATE_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-private

      - LOGFLARE_URL=http://analytics:4000
      - NEXT_PUBLIC_ENABLE_LOGS=true
      - NEXT_ANALYTICS_BACKEND_PROVIDER=postgres
      
  kong: 
    image: registry.lazycat.cloud/lmwf-zy/library/kong:d6eb117a5c049bbe
    binds:
      - /lzcapp/pkg/content/api/kong.yml:/home/kong/temp.yml
    entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start'
    depends_on: 
      - analytics
    environment:
      - KONG_DATABASE=off
      - KONG_DECLARATIVE_CONFIG=/home/kong/kong.yml
      - KONG_DNS_ORDER=LAST,A,CNAME
      - KONG_PLUGINS=request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction
      - KONG_NGINX_PROXY_PROXY_BUFFER_SIZE=160k
      - KONG_NGINX_PROXY_PROXY_BUFFERS=64 160k
      - SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
      - SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
      - DASHBOARD_USERNAME=supabase
      - DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated
      
  auth: 
    image: registry.lazycat.cloud/lmwf-zy/supabase/gotrue:22db5735d64b8603
    depends_on: 
      - db
      - analytics
    environment:
      - GOTRUE_API_HOST=0.0.0.0
      - GOTRUE_API_PORT=9999
      - API_EXTERNAL_URL=http://readestpro.zycat.heiyu.space:8080

      - GOTRUE_DB_DRIVER=postgres
      - GOTRUE_DB_DATABASE_URL=postgres://supabase_auth_admin:your-super-secret-and-long-postgres-password@db:5432/postgres

      - GOTRUE_SITE_URL=http://readestpro.zycat.heiyu.space:8080
      - GOTRUE_URI_ALLOW_LIST=
      - GOTRUE_DISABLE_SIGNUP=false

      - GOTRUE_JWT_ADMIN_ROLES=service_role
      - GOTRUE_JWT_AUD=authenticated
      - GOTRUE_JWT_DEFAULT_GROUP_NAME=authenticated
      - GOTRUE_JWT_EXP=3600
      - GOTRUE_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long

      - GOTRUE_EXTERNAL_EMAIL_ENABLED=true
      - GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=false
      - GOTRUE_MAILER_AUTOCONFIRM=true

      - GOTRUE_SMTP_ADMIN_EMAIL=admin@example.com
      - GOTRUE_SMTP_HOST=supabase-mail
      - GOTRUE_SMTP_PORT=2500
      - GOTRUE_SMTP_USER=fake_mail_user
      - GOTRUE_SMTP_PASS=fake_mail_password
      - GOTRUE_SMTP_SENDER_NAME=fake_sender
      - GOTRUE_MAILER_URLPATHS_INVITE=/auth/v1/verify
      - GOTRUE_MAILER_URLPATHS_CONFIRMATION=/auth/v1/verify
      - GOTRUE_MAILER_URLPATHS_RECOVERY=/auth/v1/verify
      - GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE=/auth/v1/verify

      - GOTRUE_EXTERNAL_PHONE_ENABLED=true
      - GOTRUE_SMS_AUTOCONFIRM=true

      
  rest:
    image: registry.lazycat.cloud/lmwf-zy/postgrest/postgrest:b07efdcfb13d393b
    depends_on: 
      - db
      - analytics
    environment:
      - PGRST_DB_URI=postgres://authenticator:your-super-secret-and-long-postgres-password@db:5432/postgres
      - PGRST_DB_SCHEMAS=public,storage,graphql_public
      - PGRST_DB_ANON_ROLE=anon
      - PGRST_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - PGRST_DB_USE_LEGACY_GUCS=false
      - PGRST_APP_SETTINGS_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - PGRST_APP_SETTINGS_JWT_EXP=3600
    command: postgrest
      
  realtime:
    image: registry.lazycat.cloud/lmwf-zy/supabase/realtime:4a4ef43f4b576bce
    depends_on:
      - db
      - analytics
    environment:
      - PORT=4000
      - DB_HOST=db
      - DB_PORT=5432
      - DB_USER=postgres
      - DB_PASSWORD=your-super-secret-and-long-postgres-password
      - DB_NAME=postgres
      - DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime
      - DB_ENC_KEY=supabaserealtime
      - API_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
      - VAULT_ENC_KEY=your-32-character-encryption-key
      - ERL_AFLAGS=-proto_dist inet_tcp
      - DNS_NODES=''
      - RLIMIT_NOFILE=10000
      - APP_NAME=realtime
      - SEED_SELF_HOST=true
      - RUN_JANITOR=true
      
  storage:
    image: registry.lazycat.cloud/lmwf-zy/supabase/storage-api:5838f517bd510914
    binds:
      - /lzcapp/pkg/content/storage:/var/lib/storage
    depends_on: 
      - db
      - rest
      - imgproxy
    environment:
      - ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
      - SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
      - POSTGREST_URL=http://rest:3000
      - PGRST_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - DATABASE_URL=postgres://supabase_storage_admin:your-super-secret-and-long-postgres-password@db:5432/postgres
      - REQUEST_ALLOW_X_FORWARDED_PATH=true
      - FILE_SIZE_LIMIT=524288000
      - STORAGE_BACKEND=file
      - FILE_STORAGE_BACKEND_PATH=/var/lib/storage
      - TENANT_ID=stub
      - REGION=stub
      - GLOBAL_S3_BUCKET=stub
      - ENABLE_IMAGE_TRANSFORMATION=true
      - IMGPROXY_URL=http://imgproxy:5001

  imgproxy:
    image: registry.lazycat.cloud/lmwf-zy/darthsim/imgproxy:09e0863f6700bf2d
    binds:
      - /lzcapp/pkg/content/storage:/var/lib/storage
    environment:
      - IMGPROXY_BIND=:5001
      - IMGPROXY_LOCAL_FILESYSTEM_ROOT=/
      - IMGPROXY_USE_ETAG=true
      - IMGPROXY_ENABLE_WEBP_DETECTION=true
      
  meta:
    image: registry.lazycat.cloud/lmwf-zy/supabase/postgres-meta:fabf579a3a3b3f06
    depends_on: 
      - db
      - analytics
    environment:
      - PG_META_PORT=8080
      - PG_META_DB_HOST=db
      - PG_META_DB_PORT=5432
      - PG_META_DB_NAME=postgres
      - PG_META_DB_USER=supabase_admin
      - PG_META_DB_PASSWORD=your-super-secret-and-long-postgres-password
      - CRYPTO_KEY=your-encryption-key-32-chars-min
      
  functions:
    image: registry.lazycat.cloud/lmwf-zy/supabase/edge-runtime:c59b3510c720b539
    binds:
      - /lzcapp/pkg/content/functions:/home/deno/functions
    depends_on: 
      - analytics
    environment:
      - JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - SUPABASE_URL=http://kong:8000
      - SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
      - SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
      - SUPABASE_DB_URL=postgresql://postgres:your-super-secret-and-long-postgres-password@db:5432/postgres
      - VERIFY_JWT=false
    command: start --main-service /home/deno/functions/main

  analytics:
    image: registry.lazycat.cloud/lmwf-zy/supabase/logflare:4acd3bef97c3ea7f
    depends_on: 
      - db
    environment:
      - LOGFLARE_NODE_HOST=127.0.0.1
      - DB_USERNAME=supabase_admin
      - DB_DATABASE=_supabase
      - DB_HOSTNAME=db
      - DB_PORT=5432
      - DB_PASSWORD=your-super-secret-and-long-postgres-password
      - DB_SCHEMA=_analytics
      - LOGFLARE_PUBLIC_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-public
      - LOGFLARE_PRIVATE_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-private
      - LOGFLARE_SINGLE_TENANT=true
      - LOGFLARE_SUPABASE_MODE=true

      - POSTGRES_BACKEND_URL=postgresql://postgres:your-super-secret-and-long-postgres-password@db:5432/postgres
      - POSTGRES_BACKEND_SCHEMA=_analytics
      - LOGFLARE_FEATURE_FLAG_OVERRIDE="multibackend=true"

      
  db:
    image: registry.lazycat.cloud/zhyuer/supabase/postgres:4afa38a0abab3443
    binds:
      - /lzcapp/pkg/content/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql
      - /lzcapp/pkg/content/db/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql
      - /lzcapp/pkg/content/db/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql
      - /lzcapp/pkg/content/db/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql
      - /lzcapp/pkg/content/db/data:/var/lib/postgresql/data
      - /lzcapp/pkg/content/db/_supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql
      - /lzcapp/pkg/content/db/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql
      - /lzcapp/pkg/content/db/pooler.sql:/docker-entrypoint-initdb.d/migrations/99-pooler.sql
      - /lzcapp/pkg/content/db-config:/etc/postgresql-custom
    depends_on: 
      - vector
    environment:
      - POSTGRES_HOST=/var/run/postgresql
      - PGPORT=5432
      - POSTGRES_PORT=5432
      - PGPASSWORD=your-super-secret-and-long-postgres-password
      - POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
      - PGDATABASE=postgres
      - POSTGRES_DB=postgres
      - JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - JWT_EXP=3600
    command: postgres -c config_file=/etc/postgresql/postgresql.conf -c log_min_messages=fatal

  vector:
    image: registry.lazycat.cloud/lmwf-zy/timberio/vector:ac274060ba59b51b
    binds:
      - /lzcapp/pkg/content/logs/vector.yml:/etc/vector/vector.yml
    environment:
      - LOGFLARE_PUBLIC_ACCESS_TOKEN=your-super-secret-and-long-logflare-key-public
    command: --config /etc/vector/vector.yml

  supavisor:
    image: registry.lazycat.cloud/lmwf-zy/supabase/supavisor:0397203264f82154
    binds:
      - /lzcapp/pkg/content/pooler/pooler.exs:/etc/pooler/pooler.exs
    depends_on: 
      - db
      - analytics
    environment:
      - PORT=4000
      - POSTGRES_PORT=5432
      - POSTGRES_DB=postgres
      - POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
      - DATABASE_URL=ecto://supabase_admin:your-super-secret-and-long-postgres-password@db:5432/_supabase
      - CLUSTER_POSTGRES=true
      - SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq
      - VAULT_ENC_KEY=your-encryption-key-32-chars-min
      - API_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - METRICS_JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
      - REGION=local
      - ERL_AFLAGS=-proto_dist inet_tcp
      - POOLER_TENANT_ID=your-tenant-id
      - POOLER_DEFAULT_POOL_SIZE=20
      - POOLER_MAX_CLIENT_CONN=100
      - POOLER_POOL_MODE=transaction
      - DB_POOL_SIZE=5
    command: /bin/sh -c '/app/bin/migrate && /app/bin/supavisor eval "$$(cat /etc/pooler/pooler.exs)" && /app/bin/server'

  readest:
    image: dev.zycat.heiyu.space/lzc/readestpro8080:latest
    binds:
      - /lzcapp/var/readest/readest-books:/app/books
      - /lzcapp/pkg/content/.env.local:/app/apps/readest-app/.env.local
    depends_on: 
      - kong
      - storage
    
  nginx:
    image: registry.lazycat.cloud/lmwf-zy/library/nginx:ab28673d0b8a92e8
    binds:
      - /lzcapp/pkg/content/nginx.conf:/etc/nginx/nginx.conf
      - /lzcapp/pkg/content/.env.loacl:/app/apps/readest-app/.env.local
    depends_on:
      - readest
      - kong
      - studio

  minio:
    image: registry.lazycat.cloud/lmwf-zy/minio/minio:10f512273fa2015f
    binds: 
      - /lzcapp/var/minio/data:/data
    environment:
      - MINIO_ROOT_USER=readest
      - MINIO_ROOT_PASSWORD=readest12345
    command: server /data --console-address ":9001"

  minio-init:
    image: registry.lazycat.cloud/lmwf-zy/minio/mc:9e7a141f8056ebff
    depends_on:
      - minio
    entrypoint: sh -c '/usr/bin/mc alias set local http://minio:9000 readest readest12345 && /usr/bin/mc mb --ignore-existing local/readest-books && tail -f /dev/null'
```

## 应用初始化

首次启动应用会提示应用状态异常,此时在后台执行下面命令后重启应用
```shell
# 1. 将 schema 所有权移交给 postgres 用户
lzc-docker exec -it cloudlazycatappreadestpro-db-1 psql -U supabase_admin -d postgres -c "ALTER SCHEMA _realtime OWNER TO postgres;"

# 2. 赋予 postgres 用户全部权限
lzc-docker exec -it cloudlazycatappreadestpro-db-1 psql -U supabase_admin -d postgres -c "GRANT ALL PRIVILEGES ON SCHEMA _realtime TO postgres;"
```

成功进入应用后还需在浏览器进行初始化,访问 http://readestpro.[your_device_name].heiyu.space:3000/project/default/sql/1 ,将参考链接中的 4 段 SQL 语句依次复制到浏览器执行

![snip_1765681501919.png](https://dl.playground.lazycat.cloud/guidelines/964/a9a5b05e-cbf9-4196-93d4-6011d5b19ab7.png "snip_1765681501919.png")

参考链接:https://github.com/readest/readest/wiki/Supabase-Tables-Schema-for-Sync-API

操作成功后可以在Table Eidor 菜单看到 多了 4 张表,这一步如果不成功则同步 API 无法使用

![snip_1765681547027.png](https://dl.playground.lazycat.cloud/guidelines/964/8b4e7b90-2ad2-4f7e-9744-a2fd4b77dd82.png "snip_1765681547027.png")

## 开始使用

1. 使用任意邮箱进行用户注册、登录

![snip_1765681768187.png](https://dl.playground.lazycat.cloud/guidelines/964/1907d1a0-83c0-4bda-9650-5cdbafeb5190.png "snip_1765681768187.png")

2. 上传的书籍、阅读进度、笔记和批注会跟随账号同步

![snip_1765682022402.png](https://dl.playground.lazycat.cloud/guidelines/964/17732e24-b637-44a4-8f06-fd7a3257bbee.png "snip_1765682022402.png")


![snip_1765682273881.png](https://dl.playground.lazycat.cloud/guidelines/964/5a5ba36f-92c9-4a3b-ab4e-c237b84bab30.png "snip_1765682273881.png")

## 最后

花费了一整周的时间在懒猫团队的帮助下完成了该项目的本地化托管,虽然有成功后的喜悦,但更多的是对过程中投入的大量时间、精力以及熬夜带来的危害感到有点不值得,后续得减少对这类事件的偏执,将更多的精力投入到更有意义的事情上。

整个项目文件已打包至 GitHub,需修改部分配置实现本地化,因架构问题需要通过文件导航页跳转一次,如部署过程有问题可在评论区讨论。

https://github.com/7opone/ReadestPro

- lzc-manifest.yml 需修改 readest 镜像地址

- config/www/index.html、config/.env、config/.env.local、config/nginx.conf 需修改对应域名为自己本地域名

评论

1
虫子樱桃147天前

还是微信读书会员最有性价比

说点什么呢~
收藏
1
1
0