Docker Setup
Running answerLoops with Docker Compose.
This page shows how to run answerLoops with Docker Compose: which compose file to use, what each one starts, and the day-to-day commands for stopping, watching logs, and looking inside the database. When you are done, you will have the app and the bot running and know how to operate them.
It assumes you have cloned the repository and created a .env file with real values. See the self-host quickstart if you have not. Docker Compose reads .env; it does not generate secrets or register sign-in clients for you.
Choose a compose file
The repository ships three compose files. Pick the one that matches what you are doing.
| File | Use it for | Builds | Includes Postgres |
|---|---|---|---|
docker-compose.yml | Trying answerLoops locally and development | Source is mounted into the container and runs in dev mode | Yes |
docker-compose.ghcr.yml | Self-hosting without a build | Pulls a published image | No, you bring your own |
docker-compose.prod.yml | Self-hosting from source | Builds the production image locally | No, you bring your own |
The published-image and from-source files leave Postgres out on purpose. A database inside the same compose project is convenient for a trial and the wrong default for data you care about. Point DATABASE_URL in .env at a Postgres you run.
What docker compose up starts
Running docker compose up --build with the default file starts three containers: the app, the bot, and Postgres.
- app serves the dashboard and API on
http://localhost:3000. It applies database migrations itself when it starts. - bot is the background worker. It listens to Discord, polls Slack where that is configured, and hands what it hears to the app at
BOT_TARGET_URL. It also runs the knowledge-base sync and re-index jobs. - postgres is
pgvector/pgvector:pg16on port5432, with its data in thepostgres-datavolume.
In this default file the app and bot get their database address from the compose file, so a DATABASE_URL in .env does not redirect them. The bot starts only after Postgres is healthy and the app has started.
Start answerLoops
Official images are published to the GitHub Container Registry, so nothing has to be built:
docker compose -f docker-compose.ghcr.yml up -dThis pulls ghcr.io/answerloops/answerloops:latest and starts the app and the bot from it. The first run takes as long as the download rather than a build. Images are built for linux/amd64 and linux/arm64, so Apple Silicon runs natively.
latest moves when a release is published. To stay on a version you have tested, pin it:
ANSWERLOOPS_IMAGE=ghcr.io/answerloops/answerloops:<version> \
docker compose -f docker-compose.ghcr.yml up -dTags are listed on the package page. Besides release versions there is a main tag built from the tip of the default branch and a sha-<commit> tag for an exact commit.
Both services run the same image and differ only in their start command, so there is nothing to keep in step between them.
The app applies database migrations every time it starts, so there is no separate migration step with any of the three files.
Stop without losing data
docker compose downFor the published-image or from-source stack, add -f docker-compose.ghcr.yml or -f docker-compose.prod.yml.
Never run docker compose down -v. The -v flag deletes named volumes, including your Postgres data in the default stack. Your articles, tickets, and workspace settings would be lost, and there is no recovery without a backup.
View logs
# All services
docker compose logs -f
# One service
docker compose logs app -f
docker compose logs bot -f
docker compose logs postgres -fThe postgres service exists only in the default file. Add -f <file> for the other two.
Look inside the database
With the default stack, open a Postgres shell in the container:
docker compose exec postgres psql -U community -d communitySome useful commands once you are in:
-- List all tables
\dt
-- Check whether a workspace finished onboarding
SELECT id, name, onboarded_at FROM orgs;
-- See who has signed in
SELECT id, email, provider FROM users;
-- Exit
\qIf you run your own Postgres, connect with psql and your DATABASE_URL instead.
Named volumes
The default file creates these volumes:
| Volume | Contents | Safe to delete? |
|---|---|---|
postgres-data | All database data | No |
app_node_modules | The app's installed packages | Yes, they are reinstalled |
bot_node_modules | The bot's installed packages | Yes, they are reinstalled |
Environment variables in Docker
Every compose file reads .env and passes its values into the containers. To confirm a value reached the app:
docker compose exec app printenv AUTH_URLAvoid printing secret values in shared terminals or logs.