answerLoopsanswerLoopsDocs
Self-hosting guide

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.

FileUse it forBuildsIncludes Postgres
docker-compose.ymlTrying answerLoops locally and developmentSource is mounted into the container and runs in dev modeYes
docker-compose.ghcr.ymlSelf-hosting without a buildPulls a published imageNo, you bring your own
docker-compose.prod.ymlSelf-hosting from sourceBuilds the production image locallyNo, 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.

The three containers the default compose file starts and how they connect. The bot and the app both use the Postgres container, and the bot sends what it hears to the app.
  • 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:pg16 on port 5432, with its data in the postgres-data volume.

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 -d

This 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 -d

Tags 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 down

For 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 -f

The 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 community

Some 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
\q

If you run your own Postgres, connect with psql and your DATABASE_URL instead.

Named volumes

The default file creates these volumes:

VolumeContentsSafe to delete?
postgres-dataAll database dataNo
app_node_modulesThe app's installed packagesYes, they are reinstalled
bot_node_modulesThe bot's installed packagesYes, 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_URL

Avoid printing secret values in shared terminals or logs.

Where to go next

On this page