> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Networking and connectivity

> Configure client URLs, outbound request security, rate limits, and load balancer timeouts for a self-hosted data plane.

These settings control how traffic reaches your self-hosted data plane, where clients point, and how connections behave behind load balancers and proxies.

## Customize the webapp URL

The SDKs guide users to `https://www.braintrust.dev` (or the `BRAINTRUST_APP_URL` variable) to view their experiments. In some
advanced configurations, you can reverse proxy traffic to the `BRAINTRUST_APP_URL` from the SDKs while pointing users to a different URL.

To do this, you can set the `BRAINTRUST_APP_PUBLIC_URL` environment variable to the URL of your webapp. By default, this variable is set to the value of `BRAINTRUST_APP_URL`, but you can customize it as you wish. This variable is *only* used to display information, so even its destination does not need to be accessible from the SDK.

<Tabs>
  <Tab title="AWS">
    Set it through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later):

    ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    braintrust_api_extra_env_vars = {
      BRAINTRUST_APP_PUBLIC_URL = "https://braintrust.example.com"
    }
    ```

    Deployments still served by the API Lambda (before module v6.0.0, or v6 with `enable_ecs_api = false`) set the same variable through `service_extra_env_vars.APIHandler` instead.
  </Tab>

  <Tab title="GCP / Azure">
    Add it to `api.extraEnvVars` in your `values.yaml`:

    ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    api:
      extraEnvVars:
        - name: BRAINTRUST_APP_PUBLIC_URL
          value: "https://braintrust.example.com"
    ```
  </Tab>
</Tabs>

## Constrain SDKs to the data plane

If you're self-hosting the data plane, you can also constrain the SDKs to only communicate with your data plane. Normally, they
communicate with the control plane to:

* Get your data plane's URL
* Register and retrieve metadata (e.g. about experiments)
* Print URLs to the webapp

The data plane can proxy the endpoints that the SDKs use to communicate with the control plane, allowing your SDKs to only communicate with the data plane directly. Set the `BRAINTRUST_APP_URL` environment variable to the URL of your data plane and `BRAINTRUST_APP_PUBLIC_URL` to `https://www.braintrust.dev` (or the URL of your webapp).

<Tabs>
  <Tab title="AWS">
    ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    braintrust_api_extra_env_vars = {
      BRAINTRUST_APP_URL        = "https://dataplane.example.com"
      BRAINTRUST_APP_PUBLIC_URL = "https://www.braintrust.dev"
    }
    ```
  </Tab>

  <Tab title="GCP / Azure">
    ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    api:
      extraEnvVars:
        - name: BRAINTRUST_APP_URL
          value: "https://dataplane.example.com"
        - name: BRAINTRUST_APP_PUBLIC_URL
          value: "https://www.braintrust.dev"
    ```
  </Tab>
</Tabs>

## Secure outbound requests

The data plane makes outbound requests both to Braintrust and to URLs you or your users supply, such as webhooks, remote scorers, and integrations.

**Allow traffic to Braintrust through your firewall**

If you restrict outbound network traffic, allow the data plane to reach Braintrust at:

```
www.braintrust.dev
braintrust.dev
gateway.braintrust.dev
```

`gateway.braintrust.dev` is the Braintrust-hosted Gateway. The data plane reaches it for quarantine LLM calls from user-authored code such as custom scorers and tools.

This is firewall guidance. The data plane does not enforce a destination allowlist itself.

**Block requests to internal addresses**

To stop user-supplied URLs from reaching private or reserved IP addresses (server-side request forgery), configure URL validation. See [Configure URL security](/docs/admin/self-hosting/configure/security#configure-url-security).

## Configure rate limits

The Braintrust API server can rate-limit the outbound requests it makes to external domains, such as `BRAINTRUST_APP_URL`. Rate limiting prevents unintentionally overloading an external domain, which might otherwise block the API server's IP in response. It is disabled by default. When enabled, requests are counted per API auth token per destination domain within a rolling window.

* `OUTBOUND_RATE_LIMIT_MAX_REQUESTS`: The maximum number of requests per window. Default `0`, which disables rate limiting. Set a value greater than `0` to enable it.
* `OUTBOUND_RATE_LIMIT_WINDOW_MINUTES`: The window length in minutes before the count resets. Default `1`.

<Tabs>
  <Tab title="AWS">
    Use the dedicated variables (Terraform module v1.0.0 or later):

    ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    outbound_rate_limit_max_requests   = 100
    outbound_rate_limit_window_minutes = 1
    ```
  </Tab>

  <Tab title="GCP / Azure">
    Set the environment variables through `api.extraEnvVars`:

    ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    api:
      extraEnvVars:
        - name: OUTBOUND_RATE_LIMIT_MAX_REQUESTS
          value: "100"
        - name: OUTBOUND_RATE_LIMIT_WINDOW_MINUTES
          value: "1"
    ```
  </Tab>
</Tabs>

## Configure HTTP keep-alive timeout

When the API server runs behind a load balancer, you may need to configure the HTTP keep-alive timeout to prevent connection resets. Load balancers typically have an idle timeout for connections, and if the API server's keep-alive timeout is shorter than the load balancer's timeout, the API server closes the connection while the load balancer still considers it open. When the load balancer tries to reuse that backend connection, it encounters a closed socket, resulting in connection reset errors and 502 responses.

The API server exposes the following environment variable to configure the keep-alive timeout:

* `TS_API_KEEP_ALIVE_TIMEOUT_SECONDS`: The HTTP keep-alive timeout in seconds. Default: `65`

The default value of 65 seconds is designed to work with most load balancers, including AWS Application Load Balancer (which has a default idle timeout of 60 seconds). However, if your load balancer has a longer idle timeout, you should set this value to match or exceed your load balancer's timeout.

For example, to match an AWS ALB configured with a 300-second idle timeout:

<Tabs>
  <Tab title="AWS">
    Set it through the `braintrust_api_extra_env_vars` passthrough map (Terraform module v6.0.0 or later). This applies to the ECS API services:

    ```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    braintrust_api_extra_env_vars = {
      TS_API_KEEP_ALIVE_TIMEOUT_SECONDS = "300"
    }
    ```
  </Tab>

  <Tab title="GCP / Azure">
    Add it to `api.extraEnvVars` in your `values.yaml`:

    ```yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    api:
      extraEnvVars:
        - name: TS_API_KEEP_ALIVE_TIMEOUT_SECONDS
          value: "300"
    ```
  </Tab>
</Tabs>

## Configure CloudFront origin timeout

On AWS, requests are served through CloudFront, which closes a connection and returns `504 Gateway Timeout` if the origin takes too long to respond. Long-running scorers or tools invoked through `/function/invoke` can exceed the default 60-second origin read timeout. Raise it with the `cloudfront_origin_read_timeout` Terraform variable (available in Terraform module v5.3.0 or later):

```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
cloudfront_origin_read_timeout = 120
```

The value must be between 1 and 180 seconds. CloudFront caps the origin read timeout at 180 seconds, and values above 60 seconds can require an AWS Support request to raise the account quota.

## Configure API ALB HTTPS

On AWS with the ECS API, an internal Application Load Balancer (ALB) fronts the API services. By default, the ALB serves plain HTTP on port 80 using its AWS-assigned DNS name. To serve HTTPS on a custom domain instead, set both `braintrust_api_alb_certificate_arn` and `braintrust_api_alb_custom_domain` (available in Terraform module v6.0.0 or later):

```hcl theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
braintrust_api_alb_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/abc123"
braintrust_api_alb_custom_domain   = "braintrust.internal.example.com"
```

When both are set, the ALB serves HTTPS on port 443, plain HTTP is disabled, and all API URLs use `https://<braintrust_api_alb_custom_domain>`. The certificate must cover the custom domain, and the domain must resolve to the ALB.

<Note>
  These two variables must both be set or both be null. Setting only one fails at plan time.
</Note>

## VPC connectivity

On AWS, to connect Braintrust's VPC to other internal resources (like an LLM Gateway), use one of the following approaches:

* Create a VPC Endpoint Service for your internal resource, then create a VPC Interface Endpoint inside the Braintrust "Quarantine" VPC.
* Set up VPC peering with the Braintrust "Quarantine" VPC.
