Deploying Braintrust with Docker

This guide walks through the process of deploying Braintrust through Docker. Broadly, we support two configurations:

  • API (recommended): deploys the data plane through docker. If you choose this option, then all of your data will be stored in the docker containers, and our servers will never be able to access it. However, you'll still be able to visit Braintrust through https://braintrustdata.com, and your browser will communicate with the API server running in docker directly. This is analogous to the self-hosted AWS configuration.
  • Full: a heavier-weight configuration that deploys the entire Braintrust application (data plane and control plane) in a standalone fashion, including the API, web app, and auxiliary services. Choose the full configuration if you do not wish to rely on any centrally hosted components. If you plan to run this configuration in production, please reach out to us so we can work out how to best support you.

The files necessary for launching these deployments are hosted on GitHub. The repository contains a docker compose configuration file for each deployment. If needed, you may customize the environment variables in each compose file to suit your deployment needs. The environment variables are documented in each compose file.

To get started, just pull down the deployment repo, pick a docker-compose file, and launch Braintrust! The rest of this guide walks through the details of each configuration.

API vs. Full configuration

The primary difference between the two options is that the API configuration allows you to host the most sensitive data in docker, behind an API which changes infrequently (you need to update roughly 1-2 times per month), while allowing the Braintrust team to host the web app and metadata database which are updated multiple times per day. On the other hand, the full configuration allows you to host the webserver and metadata database in your own environment, ensuring total isolation, but with additional maintenance overhead.

To see more about which data is stored in which location, see the advanced guide.

API configuration

To launch the API configuration:

git clone git@github.com:braintrustdata/braintrust-deployment.git
cd braintrust-deployment/docker
docker compose -f docker-compose.api.yml pull
docker compose -f docker-compose.api.yml up -d --remove-orphans

The services can be shutdown with docker compose as well:

docker compose -f docker-compose.api.yml down

Once you have started the docker containers, navigate to the API URL section of the settings page. Enter the URL of your server in the "API URL" section. The docker server defaults to http://localhost:8000, which will work as long as the browser is running on the same machine as the API server. The external port can be configured by adjusting the first value of the port mapping in the compose file.

API URL settings page

If the browser is successfully able to connect to your server, you should see the message "API ping successful". At this point, you should be able to use Braintrust as usual!

If this is your first time using Braintrust, you may want to go through the quickstart guide next.

Setting up HTTPS

If you wish to deploy the API server to a non-localhost URL, it will need to be exposed on an HTTPS endpoint. A common way to accomplish this is to obtain an SSL certificate for your domain, and forward traffic to your API server using a reverse proxy, such as nginx.

Deploying other services

In addition to the API server, you may also deploy the proxy and realtime services through docker. The realtime server transfers end-to-end encrypted user data using a key that's only available to the data plane. The proxy end-to-end encrypts and stores cached completions using your API key. Self-hosting may be desirable to have complete control over these services and ensure that sensitive data in any form goes through only your own servers.

The proxy and realtime services are bundled in the full configuration, and we can add them into the API configuration, with minor modifications. The modified docker-compose.api.yml might look as follows:

services:
  braintrust-redis:
    # Same as before.
  braintrust-postgres:
    # Same as before.
  braintrust-standalone-api:
    # Same as before, except we add environment variables pointing the API
    # server to our deployed proxy and realtime services.
    environment:
      # We use `host.docker.internal` here because the docker container can only
      # access other services on the same host network through this domain.
      PROXY_URL: http://host.docker.internal:8787/v1
      REALTIME_URL: http://host.docker.internal:8788
      # Make sure to leave the other environment variables in.
  braintrust-standalone-proxy:
    # Uncomment the `braintrust-standalone-proxy` block.
  braintrust-standalone-realtime:
    # Uncomment the `braintrust-standalone-realtime` block.

If you are deploying the proxy and/or realtime services on different machines, make sure to adjust the URLs set on the braintrust-standalone-api service accordingly. Finally, point the webapp to your proxy and realtime URLs in the API URLs page .

You will want to use the publicly-accessible form of the URL, rather than the docker-accessible form, so make sure to substitute host.docker.internal with localhost if that applies.

Make sure to include a /v1 suffix in the Proxy URL.

All URL settings page

If you wish to deploy more services yourself, such as the webapp, you will likely want to switch to the full configuration.

Full configuration

To run the full stack in Docker, in addition to the API, you need to run the Braintrust web servers and the metadata database. The web servers run in docker containers managed in docker-compose.full.yml, while the metadata database uses Supabase, which is launched as a separate set of containers. To download and launch the full configuration:

# Launch Braintrust containers.
git clone git@github.com:braintrustdata/braintrust-deployment.git
cd braintrust-deployment/docker
docker compose -f docker-compose.full.yml pull
docker compose -f docker-compose.full.yml up -d --remove-orphans
 
# Launch Supabase.
cd ../..
wget https://braintrust-supabase.s3.amazonaws.com/braintrust-supabase-latest.zip
unzip braintrust-supabase-latest.zip
cd braintrust-supabase
npm install
npx supabase start
npx supabase migration up

Launching supabase requires having NodeJS and npm installed (version >= 18). See the NodeJS docs for installation instructions. Alternatively, see the Supabase CLI docs for instructions on how to install the CLI as a standalone binary.

The braintrust cluster can be shutdown with docker compose, and the supabase cluster can be shutdown with npx:

# Shutdown Braintrust.
cd braintrust-deployment/docker
docker compose -f docker-compose.full.yml down
 
# Shutdown Supabase.
cd ../../braintrust-supabase
npx supabase stop

The repository includes a Makefile in the braintrust-supabase directory for starting and stopping Supabase. You can run make up to start Supabase and make down to stop it.

At this point, the app should be accessible at the BRAINTRUST_APP_PUBLIC_URL set in your docker-compose.full.yml file (defaults to http://localhost:3000). When you navigate to the sign-in page, instead of the normal third-party authentication workflow, you should see a field to provide an API key:

API Key Signin Page

To create the very first API key, you can curl a webserver in the Braintrust Docker cluster (specifically the braintrust-standalone-app-bootstrap service). The webserver is listening on port 8100 and is password-protected by the CONTAINER_SERVER_SECRET environment variable defined in your docker-compose.full.yml To create an API key, simply curl the webserver, with a JSON payload describing the org and user the key is associated with:

curl "http://localhost:8100/create-api-key" -H "Authorization: Bearer [CONTAINER_SERVER_SECRET]" -d '{"org_name": "[YOUR_ORG_NAME]", "user_email": "[YOUR_USER_EMAIL]"}'

You can edit the environment variables in docker-compose.full.yml. Just make sure to restart the Braintrust Docker cluster for the changes to take effect.

The server should respond with an API key, that you can copy-paste into the sign-in page. Once you have logged in, you can create further API keys using the Settings page, or continue to use the webserver if you need to create new organizations or users.

The standard google auth signin workflow is not enabled for the local fullstack deployment because the authentication redirect URLs are externally fixed. Make sure to keep track of the API key you created above for future logins.

At this point, you should be able to use the full Braintrust application as usual! If this is your first time using Braintrust, you may want to go through the quickstart guide next.

Troubleshooting

The state of the Braintrust deployment is fully managed on docker. Therefore, if something is not running as expected, you should be able to inspect the container, either by dumping its logs or opening up a shell inside the container to poke around. For instance, after launching the API configuration, you should see three containers:

% docker ps
CONTAINER ID   IMAGE                                             COMMAND                  CREATED          STATUS                    PORTS                    NAMES
c67b49727823   public.ecr.aws/braintrust/standalone-api:latest   "python entrypoint_a…"   16 minutes ago   Up 16 minutes             0.0.0.0:8000->8000/tcp   bt-docker-braintrust-standalone-api-1
6ed70334c6cf   public.ecr.aws/braintrust/postgres:latest         "docker-entrypoint.s…"   16 minutes ago   Up 16 minutes (healthy)   0.0.0.0:5532->5432/tcp   bt-docker-braintrust-postgres-1
37840f55bfd5   public.ecr.aws/braintrust/redis:latest            "docker-entrypoint.s…"   16 minutes ago   Up 16 minutes (healthy)   0.0.0.0:6479->6379/tcp   bt-docker-braintrust-redis-1

You can dump the logs of the API container using docker logs [CONTAINER ID], or spawn a shell inside the container using docker exec -it [CONTAINER ID] bash. For further questions, feel free to reach out at support@braintrustdata.com.

On this page