Deployment Walkthrough#
Twisted now deploys as one VPS Compose stack defined by
docker-compose.prod.yaml. Coolify can still host that stack, but the Compose
file is the source of truth.
Services#
postgres: primary database onpgvector/pgvector:pg17migrate: one-shot schema bootstrap viatwister migrateapi: public HTTP serviceindexer: private Tap consumertap: private Indigo Tap servicellama-embeddings: private llama.cpp server for future embedding work
Prerequisites#
- one VPS or Coolify host with Docker Compose
- this repo available to the host
- explicit
INDEXED_COLLECTIONSandREAD_THROUGH_COLLECTIONS - one shared
TAP_AUTH_PASSWORD - a production
POSTGRES_PASSWORD
Use explicit search collections. Do not use sh.tangled.* in production.
Environment#
Required:
POSTGRES_PASSWORDTAP_AUTH_PASSWORDINDEXED_COLLECTIONS
Common overrides:
POSTGRES_USERdefaulttwistedPOSTGRES_DBdefaulttwistedLOG_LEVEL=infoLOG_FORMAT=jsonREAD_THROUGH_MODE=missingREAD_THROUGH_COLLECTIONS=<explicit CSV>READ_THROUGH_MAX_ATTEMPTS=5HTTP_BIND_ADDR=:8080INDEXER_HEALTH_ADDR=:9090LLAMA_MODEL_REPO=nomic-ai/nomic-embed-text-v1.5-GGUFLLAMA_MODEL_FILE=nomic-embed-text-v1.5.Q8_0.gguf
llama-embeddings is private and not part of search yet. It only keeps the
model warm and cached for later adapter work.
Bootstrap#
From the repo root:
just vps-up
That sequence:
- starts PostgreSQL and Tap
- runs
migrate - starts
api,indexer, andllama-embeddings
Clean Reset#
For a fresh VM or full reset:
just vps-reset
This removes named volumes, recreates PostgreSQL, reapplies migrations, and starts the full stack from zero.
Coolify Notes#
If you run this through Coolify:
- create one Docker Compose application
- point it at
/docker-compose.prod.yaml - set the env vars above in Coolify
- expose only the
apiservice through Traefik
Do not add a separate PostgreSQL resource for this stack.
Checks#
api:GET /readyzreturns200indexer:GET /healthreturns200indexercan reachws://tap:2480/channelllama-embeddingsserves embeddings on its internal port
Then rebuild the serving dataset:
docker compose -f docker-compose.prod.yaml exec indexer twister backfill
docker compose -f docker-compose.prod.yaml exec indexer twister enrich
docker compose -f docker-compose.prod.yaml exec indexer twister reindex
Do not import old Turso data as the default migration path.
App Target#
For local app builds:
VITE_TWISTER_API_BASE_URL=https://<your-api-domain>
Rollback#
- PostgreSQL restore is the rollback primitive
- keep
--localonly as a temporary development fallback
Post-Deploy Checklist#
After a fresh deploy or indexer recovery:
- confirm
migrateexited successfully - confirm
apireturns200from/readyz - confirm
indexerreturns200from/health - in the
indexercontainer run the following- run
twister backfill - run
twister enrich - run
twister reindex
- run
- watch
indexerlogs and confirm the Tap cursor keeps moving forward