231 lines
9.3 KiB
YAML
231 lines
9.3 KiB
YAML
networks:
|
|
bettersight_default:
|
|
# LOCAL DEV — CLAUDE.md §4 uses an external `pangolin_default` network
|
|
# (Dokploy/Pangolin-managed, production only). Locally there is no
|
|
# Pangolin reverse proxy, so this is a plain compose-managed bridge
|
|
# network instead. Do not port this network block to production —
|
|
# production still uses the external pangolin_default per CLAUDE.md.
|
|
driver: bridge
|
|
|
|
volumes:
|
|
pocketbase_data:
|
|
|
|
services:
|
|
flask-api:
|
|
build: ./backend
|
|
container_name: flask-api
|
|
command: gunicorn app:app -w 4 -b 0.0.0.0:5000
|
|
env_file: ./backend/.env
|
|
environment:
|
|
# Overrides backend/.env's values with container-network-correct
|
|
# addresses. host.docker.internal reaches the PocketBase instance
|
|
# already running on the host machine (per user instruction, that
|
|
# instance is started manually and is NOT the pocketbase service
|
|
# below — this compose file never starts its own PocketBase).
|
|
- POCKETBASE_URL=http://host.docker.internal:8090
|
|
- REDIS_URL=redis://bettersight-redis:6379
|
|
- FIRECRAWL_URL=http://firecrawl-api:3002
|
|
ports:
|
|
- "5050:5000"
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- bettersight-redis
|
|
|
|
bettersight-worker:
|
|
build: ./backend
|
|
container_name: bettersight-worker
|
|
command: rq worker high normal low -u redis://bettersight-redis:6379
|
|
env_file: ./backend/.env
|
|
environment:
|
|
- POCKETBASE_URL=http://host.docker.internal:8090
|
|
- REDIS_URL=redis://bettersight-redis:6379
|
|
- FIRECRAWL_URL=http://firecrawl-api:3002
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- bettersight-redis
|
|
|
|
bettersight-redis:
|
|
image: redis:alpine
|
|
container_name: bettersight-redis
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
|
|
# ── Opt-in only — real self-hosted Firecrawl is a 3-service stack
|
|
# built from source (no stable published image — see CLAUDE.md §4's
|
|
# "Firecrawl — real self-hosted stack" note). Builds from a local
|
|
# clone at ./firecrawl (`git clone https://github.com/firecrawl/
|
|
# firecrawl.git`) rather than a remote git build context — this
|
|
# environment's network couldn't reliably clone the repo itself
|
|
# (git's smart-HTTP protocol specifically; plain HTTPS to GitHub's
|
|
# API and to PyPI both worked fine, so this was not general
|
|
# bandwidth throttling). Re-point back to the GitHub URL below if
|
|
# building somewhere with normal git connectivity, and drop the
|
|
# local clone from the repo (it's gitignored, not committed).
|
|
#
|
|
# Build context is the app subdirectory itself (./firecrawl/apps/api),
|
|
# not the repo root — apps/api/Dockerfile's COPY instructions (e.g.
|
|
# `COPY sharedLibs/go-html-to-md ...`) are written relative to
|
|
# apps/api/, matching upstream firecrawl's own docker-compose.yaml
|
|
# (`build: apps/api`). Pointing context at the repo root with
|
|
# `dockerfile: apps/api/Dockerfile` resolves the Dockerfile from the
|
|
# right place but still resolves every COPY inside it against the
|
|
# repo root, not apps/api/ — breaks on the first COPY that assumes
|
|
# otherwise.
|
|
# Firecrawl's NUQ queue backend needs a real Postgres, not just Redis —
|
|
# discovered only once firecrawl-api actually started: without
|
|
# NUQ_DATABASE_URL set, harness.ts's setupNuqPostgres() tries to
|
|
# auto-provision a Postgres container by shelling out to `docker`/
|
|
# `podman` from *inside* the firecrawl-api container itself, which
|
|
# obviously has neither installed and isn't meant to (no
|
|
# Docker-in-Docker here). Firecrawl ships a purpose-built Postgres
|
|
# image for this at apps/nuq-postgres/ — pg_cron preloaded plus the
|
|
# NUQ schema (nuq.sql) baked in as an initdb script — build that
|
|
# rather than pointing at a vanilla postgres image, which would boot
|
|
# without the schema NUQ expects.
|
|
#
|
|
# Setting POSTGRES_HOST to this container's name (anything other
|
|
# than "localhost") is what flips setupNuqPostgres() into its
|
|
# docker-compose branch, which just builds the connection URL
|
|
# directly and skips the Docker/Podman auto-provision path entirely
|
|
# — this is the code path Firecrawl's own authors intended for
|
|
# exactly this setup, not a workaround.
|
|
#
|
|
# NUQ_RABBITMQ_URL turned out not to be optional in practice, despite
|
|
# most call sites gracefully checking `if (config.NUQ_RABBITMQ_URL)`
|
|
# and falling back to polling mode when absent. The harness always
|
|
# spawns an extract-worker subprocess (dist/src/services/extract-worker.js)
|
|
# regardless of which routes are actually used, and that subprocess's
|
|
# consumeExtractJobs() throws immediately without it — no config
|
|
# check gates whether it starts. The harness treats any subprocess
|
|
# exit as fatal to the whole process, so without RabbitMQ the entire
|
|
# firecrawl-api container crash-looped every ~2s even though
|
|
# Bettersight never calls /extract. Upstream's own docker-compose.yaml
|
|
# confirms this isn't optional either — it lists rabbitmq as a hard
|
|
# `depends_on: condition: service_healthy` for the api service. Stock
|
|
# image, no build needed.
|
|
firecrawl-rabbitmq:
|
|
image: rabbitmq:3-management
|
|
container_name: firecrawl-rabbitmq
|
|
profiles: ["firecrawl"]
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
|
|
firecrawl-nuq-postgres:
|
|
build:
|
|
context: ./firecrawl/apps/nuq-postgres
|
|
container_name: firecrawl-nuq-postgres
|
|
profiles: ["firecrawl"]
|
|
environment:
|
|
- POSTGRES_USER=postgres
|
|
- POSTGRES_PASSWORD=postgres
|
|
- POSTGRES_DB=postgres
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
|
|
# No separate firecrawl-worker service — checked upstream's own
|
|
# docker-compose.yaml (firecrawl/docker-compose.yaml) and it defines
|
|
# only one `api` container, command `node dist/src/harness.js
|
|
# --start-docker`. That harness process spins up the queue workers
|
|
# internally (NUQ_WORKER_COUNT etc — see apps/api/src/harness.ts)
|
|
# rather than running as a separate process. A prior version of this
|
|
# file ran a second container on `pnpm run workers`, which crash
|
|
# looped: the runtime image only carries node_modules/dist/native
|
|
# (no package.json — see the Dockerfile's runtime stage), so pnpm
|
|
# had nothing to run against. This matches the older split-process
|
|
# Firecrawl architecture CLAUDE.md's §4 was written against, not the
|
|
# current one — do not reintroduce a second container here.
|
|
firecrawl-api:
|
|
build:
|
|
context: ./firecrawl/apps/api
|
|
# context: https://github.com/firecrawl/firecrawl.git#main&context=apps/api
|
|
container_name: firecrawl-api
|
|
profiles: ["firecrawl"]
|
|
environment:
|
|
- PORT=3002
|
|
- HOST=0.0.0.0
|
|
- REDIS_URL=redis://bettersight-redis:6379
|
|
- REDIS_RATE_LIMIT_URL=redis://bettersight-redis:6379
|
|
- PLAYWRIGHT_MICROSERVICE_URL=http://firecrawl-playwright:3000/scrape
|
|
- USE_DB_AUTHENTICATION=false
|
|
- NUM_WORKERS_PER_QUEUE=8
|
|
- POSTGRES_HOST=firecrawl-nuq-postgres
|
|
- POSTGRES_PORT=5432
|
|
- POSTGRES_USER=postgres
|
|
- POSTGRES_PASSWORD=postgres
|
|
- POSTGRES_DB=postgres
|
|
- NUQ_RABBITMQ_URL=amqp://firecrawl-rabbitmq:5672
|
|
depends_on:
|
|
- bettersight-redis
|
|
- firecrawl-playwright
|
|
- firecrawl-nuq-postgres
|
|
- firecrawl-rabbitmq
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
|
|
firecrawl-playwright:
|
|
build:
|
|
context: ./firecrawl/apps/playwright-service-ts
|
|
# context: https://github.com/firecrawl/firecrawl.git#main&context=apps/playwright-service-ts
|
|
container_name: firecrawl-playwright
|
|
profiles: ["firecrawl"]
|
|
environment:
|
|
- PORT=3000
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
mem_limit: 4g
|
|
|
|
# ── Opt-in only — excluded from a plain `docker compose up -d` ────────
|
|
# Started with `docker compose --profile with-pocketbase up -d
|
|
# pocketbase` if this local host-run instance is ever retired in
|
|
# favour of a containerized one. Per explicit instruction: defined
|
|
# here for parity with CLAUDE.md §4, but never auto-started while a
|
|
# host PocketBase is already running on localhost:8090.
|
|
pocketbase:
|
|
image: ghcr.io/muchobien/pocketbase:latest
|
|
container_name: pocketbase
|
|
profiles: ["with-pocketbase"]
|
|
volumes:
|
|
- pocketbase_data:/pb_data
|
|
- ./backend/pb_migrations:/pb_migrations
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
|
|
# ── Opt-in only — needs MAIL_FROM/SMTP config not present locally ──
|
|
freescout:
|
|
image: freescout/freescout:latest
|
|
container_name: freescout
|
|
profiles: ["support"]
|
|
environment:
|
|
- APP_URL=http://localhost:8080
|
|
- MAIL_FROM=support@bettersight.io
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|
|
|
|
# ── Opt-in only — needs Hetzner S3 credentials not present locally ──
|
|
litestream:
|
|
image: litestream/litestream:latest
|
|
container_name: litestream
|
|
profiles: ["backup"]
|
|
command: replicate
|
|
environment:
|
|
- LITESTREAM_ACCESS_KEY_ID=${HETZNER_S3_ACCESS_KEY}
|
|
- LITESTREAM_SECRET_ACCESS_KEY=${HETZNER_S3_SECRET_KEY}
|
|
networks:
|
|
- bettersight_default
|
|
restart: unless-stopped
|