All checks were successful
CI / Backend (push) Successful in 25s
Release / Test backend (push) Successful in 24s
CI / UI (push) Successful in 51s
Release / Check ui (push) Successful in 29s
CI / UI (pull_request) Successful in 27s
CI / Backend (pull_request) Successful in 44s
Release / Docker / caddy (push) Successful in 54s
Release / Docker / ui (push) Successful in 2m4s
Release / Docker / runner (push) Successful in 2m56s
Release / Docker / backend (push) Successful in 3m23s
Release / Gitea Release (push) Successful in 12s
106 lines
5.0 KiB
YAML
106 lines
5.0 KiB
YAML
# LibNovel homelab runner
|
|
#
|
|
# Connects to production PocketBase and MinIO via public subdomains.
|
|
# All secrets come from Doppler (project=libnovel, config=prd_homelab).
|
|
# Run with: doppler run -- docker compose up -d
|
|
#
|
|
# Differs from prod runner:
|
|
# - RUNNER_WORKER_ID=homelab-runner-1 (unique, avoids task claiming conflicts)
|
|
# - MINIO_ENDPOINT/USE_SSL → storage.libnovel.cc over HTTPS
|
|
# - POCKETBASE_URL → https://pb.libnovel.cc
|
|
# - MEILI_URL → https://search.libnovel.cc (Caddy-proxied)
|
|
# - VALKEY_ADDR → unset (not exposed publicly)
|
|
# - RUNNER_SKIP_INITIAL_CATALOGUE_REFRESH=true
|
|
# - REDIS_ADDR → rediss://redis.libnovel.cc:6380 (prod Redis via Caddy TLS proxy)
|
|
# - LibreTranslate service for machine translation (internal network only)
|
|
|
|
services:
|
|
libretranslate:
|
|
image: libretranslate/libretranslate:latest
|
|
restart: unless-stopped
|
|
environment:
|
|
LT_API_KEYS: "true"
|
|
LT_API_KEYS_DB_PATH: "/app/db/api_keys.db"
|
|
# Limit to source→target pairs the runner actually uses
|
|
LT_LOAD_ONLY: "en,ru,id,pt,fr"
|
|
LT_DISABLE_WEB_UI: "true"
|
|
LT_UPDATE_MODELS: "false"
|
|
volumes:
|
|
- libretranslate_models:/home/libretranslate/.local/share/argos-translate
|
|
- libretranslate_db:/app/db
|
|
healthcheck:
|
|
test: ["CMD", "python3", "-c", "import urllib.request,sys; urllib.request.urlopen('http://localhost:5000/languages'); sys.exit(0)"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 120s
|
|
|
|
runner:
|
|
image: kalekber/libnovel-runner:latest
|
|
restart: unless-stopped
|
|
stop_grace_period: 135s
|
|
depends_on:
|
|
libretranslate:
|
|
condition: service_healthy
|
|
environment:
|
|
# ── PocketBase ──────────────────────────────────────────────────────────
|
|
POCKETBASE_URL: "https://pb.libnovel.cc"
|
|
POCKETBASE_ADMIN_EMAIL: "${POCKETBASE_ADMIN_EMAIL}"
|
|
POCKETBASE_ADMIN_PASSWORD: "${POCKETBASE_ADMIN_PASSWORD}"
|
|
|
|
# ── MinIO (S3 API via public subdomain) ─────────────────────────────────
|
|
MINIO_ENDPOINT: "storage.libnovel.cc"
|
|
MINIO_ACCESS_KEY: "${MINIO_ROOT_USER}"
|
|
MINIO_SECRET_KEY: "${MINIO_ROOT_PASSWORD}"
|
|
MINIO_USE_SSL: "true"
|
|
MINIO_PUBLIC_ENDPOINT: "${MINIO_PUBLIC_ENDPOINT}"
|
|
MINIO_PUBLIC_USE_SSL: "${MINIO_PUBLIC_USE_SSL}"
|
|
|
|
# ── Meilisearch (via search.libnovel.cc Caddy proxy) ────────────────────
|
|
MEILI_URL: "${MEILI_URL}"
|
|
MEILI_API_KEY: "${MEILI_API_KEY}"
|
|
VALKEY_ADDR: ""
|
|
# Force IPv4 DNS resolution — homelab has no IPv6 route to search.libnovel.cc
|
|
GODEBUG: "preferIPv4=1"
|
|
|
|
# ── Kokoro TTS ──────────────────────────────────────────────────────────
|
|
KOKORO_URL: "${KOKORO_URL}"
|
|
KOKORO_VOICE: "${KOKORO_VOICE}"
|
|
|
|
# ── Pocket TTS ──────────────────────────────────────────────────────────
|
|
POCKET_TTS_URL: "${POCKET_TTS_URL}"
|
|
|
|
# ── LibreTranslate (internal Docker network) ────────────────────────────
|
|
LIBRETRANSLATE_URL: "http://libretranslate:5000"
|
|
LIBRETRANSLATE_API_KEY: "${LIBRETRANSLATE_API_KEY}"
|
|
|
|
# ── Asynq / Redis (prod Redis via Caddy TLS proxy) ──────────────────────
|
|
# The runner connects to prod Redis over TLS: rediss://redis.libnovel.cc:6380.
|
|
# Caddy on prod terminates TLS and proxies to the local redis:6379 sidecar.
|
|
REDIS_ADDR: "${REDIS_ADDR}"
|
|
REDIS_PASSWORD: "${REDIS_PASSWORD}"
|
|
|
|
# ── Runner tuning ───────────────────────────────────────────────────────
|
|
RUNNER_WORKER_ID: "${RUNNER_WORKER_ID}"
|
|
RUNNER_POLL_INTERVAL: "${RUNNER_POLL_INTERVAL}"
|
|
RUNNER_MAX_CONCURRENT_SCRAPE: "${RUNNER_MAX_CONCURRENT_SCRAPE}"
|
|
RUNNER_MAX_CONCURRENT_AUDIO: "${RUNNER_MAX_CONCURRENT_AUDIO}"
|
|
RUNNER_MAX_CONCURRENT_TRANSLATION: "${RUNNER_MAX_CONCURRENT_TRANSLATION}"
|
|
RUNNER_TIMEOUT: "${RUNNER_TIMEOUT}"
|
|
RUNNER_METRICS_ADDR: "${RUNNER_METRICS_ADDR}"
|
|
RUNNER_SKIP_INITIAL_CATALOGUE_REFRESH: "true"
|
|
|
|
# ── Observability ───────────────────────────────────────────────────────
|
|
LOG_LEVEL: "${LOG_LEVEL}"
|
|
GLITCHTIP_DSN: "${GLITCHTIP_DSN}"
|
|
|
|
healthcheck:
|
|
test: ["CMD", "/healthcheck", "file", "/tmp/runner.alive", "120"]
|
|
interval: 60s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
volumes:
|
|
libretranslate_models:
|
|
libretranslate_db:
|