# Managed BYOC Setup

Managed BYOC is in beta. [Contact us](/contact) to get started.

This guide takes you from an empty cloud account to a running
[Managed BYOC](/docs/byoc#managed-byoc) cluster. Work through the runlist in
order and check off each step as you go. Before you start, check the
[requirements](/docs/byoc/requirements) and [size your cluster](/docs/byoc/sizing).

For each cluster, turbopuffer provides a managed BYOC kit. You apply a small
bootstrap, and a jump host in your account then builds the cluster for you. The
turbopuffer team reaches the jump host over outbound-only SSH through Teleport,
and all access is logged and audited.

## Your kit contents

```txt
byoc-managed-kit
├── README.md
├── cosign.pub
├── aws
│   ├── README.md
│   ├── bootstrap                       # phase 1, applied by you
│   │   ├── main.tf
│   │   ├── iam_*.tf                    # roles turbopuffer works under
│   │   ├── backend.hcl
│   │   └── turbopuffer.tfvars
│   ├── cluster                         # phase 2, applied by turbopuffer
│   │   ├── main.tf
│   │   ├── byoc-provision.sh
│   │   ├── policies
│   │   ├── metrics-keys.yaml           # configuration file provided by turbopuffer
│   │   ├── turbopuffer.tfvars.json     # configuration file provided by turbopuffer
│   │   └── values.secret.yaml (generated) # sensitive configuration file generated by generate-secrets.py
│   └── cluster-core
├── gcp
│   ├── bootstrap
│   └── cluster
├── azure
│   ├── bootstrap
│   └── cluster
└── scripts
    ├── apikey.py
    ├── generate-secrets.py
    └── sanity.sh
```

## Runlist

1. [ ] **Prerequisites:** Check you have everything you need:
    - [ ] Verify you have `terraform`, `python3`, and the **GCP:** `gcloud`
          **AWS:** `aws`
          **Azure:** `az` CLI installed.
    - [ ] Provision a **fresh sub-account / project** for your new cluster, with administrator access to it.
    - [ ] **GCP:** Provide us with your **project ID**. We use it to scope the jump host's SSH enrollment.
          **AWS:** Provide us with your **AWS account ID**. We use it to scope the jump host's SSH enrollment and to allow image pulls from our registry.
          **Azure:** Provide us with your **subscription ID** and the **resource group** you will deploy into. We use them to scope the jump host's SSH enrollment.
2. [ ] **Bootstrap configuration:** Fill in the required values in **GCP:** `gcp/bootstrap/turbopuffer.tfvars`
       **AWS:** `aws/bootstrap/turbopuffer.tfvars`
       **Azure:** `azure/bootstrap/turbopuffer.tfvars`. The Teleport values are pre-filled by turbopuffer.
3. [ ] **Generate API keys:** **GCP:** `cd gcp/cluster`
       **AWS:** `cd aws/cluster`
       **Azure:** `cd azure/cluster`, then run `python3 ../../scripts/generate-secrets.py` to generate `values.secret.yaml`. The script will generate an org ID and API key, along with a token for intra-cluster communication.
    - The API key is printed once. Save it. Only its hash is written to disk, so turbopuffer never sees the key.
    - [ ] Return to the kit root: `cd ../..`
4. [ ] **Create the state bucket:** Create the **GCP:** bucket
       **AWS:** bucket
       **Azure:** storage account and container that holds the bootstrap Terraform state and the staged kit. See [creating the state bucket](#creating-the-state-bucket). It stays yours, and every turbopuffer role is denied access to the state object.
    - [ ] Fill in **GCP:** `gcp/bootstrap/backend.hcl`
          **AWS:** `aws/bootstrap/backend.hcl`
          **Azure:** `azure/bootstrap/backend.hcl` to point the bootstrap at it.
5. [ ] **Apply the bootstrap:** As an account administrator, **GCP:** `cd gcp/bootstrap`
       **AWS:** `cd aws/bootstrap`
       **Azure:** `cd azure/bootstrap`, then run `terraform init -backend-config=backend.hcl` and `terraform apply -var-file=turbopuffer.tfvars`.
    - This builds the network, the roles turbopuffer works under, the data bucket, and the jump host. It also opens the install window so the cluster can install without further input.
    - [ ] Save the Terraform outputs. They include the commands to close and reopen the install window.
    - [ ] Return to the kit root: `cd ../..`
6. [ ] **Tell turbopuffer the bootstrap is applied.** The jump host registers with turbopuffer and builds the cluster automatically, which takes about 20 to 30 minutes. The turbopuffer team monitors the provisioning and confirms when the cluster is healthy.
7. [ ] **Run post-deployment sanity checks:** `TURBOPUFFER_API_KEY=<your_api_key> scripts/sanity.sh` will query your turbopuffer cluster directly, verifying that core operations function.
8. [ ] **Close the install window:** Once turbopuffer confirms the cluster is healthy, run the `install_window_close` command from the bootstrap outputs. The window stays closed until you reopen it with `install_window_open`, and nothing turbopuffer runs can reopen it.
9. [ ] **Get access to monitoring:** Ask the turbopuffer team for access to your cluster's Datadog dashboard. See [Monitoring](/docs/byoc/operations#monitoring).

Your cluster is now running. turbopuffer operates it and applies configuration
changes for you. [Operations](/docs/byoc/operations) covers monitoring and
day-to-day tasks, and [Configuration](/docs/byoc/configuration) lists the
settings you can ask us to change.

## Creating the state bucket

#### GCP

Create the state bucket with versioning and public access prevention. Replace `<state_bucket_name>`, `<project_id>`, and `<region>` with the values from your `turbopuffer.tfvars`.

```bash
gcloud storage buckets create gs://<state_bucket_name> --project <project_id> \
  --location <region> --uniform-bucket-level-access --public-access-prevention
gcloud storage buckets update gs://<state_bucket_name> --versioning
```

Then point the bootstrap at it in `gcp/bootstrap/backend.hcl`:

```hcl
bucket = "<state_bucket_name>"
prefix = "bootstrap"
```
#### AWS

Create the state bucket with versioning, public access blocked, and encryption enabled. Replace `<state_bucket_name>` and `<region>` with the values from your `turbopuffer.tfvars`.

```bash
aws s3api create-bucket --bucket <state_bucket_name> --region <region> \
  --create-bucket-configuration LocationConstraint=<region>   # omit in us-east-1
aws s3api put-bucket-versioning --bucket <state_bucket_name> \
  --versioning-configuration Status=Enabled
aws s3api put-public-access-block --bucket <state_bucket_name> \
  --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-encryption --bucket <state_bucket_name> \
  --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"},"BucketKeyEnabled":true}]}'
```

Then point the bootstrap at it in `aws/bootstrap/backend.hcl`:

```hcl
bucket       = "<state_bucket_name>"
key          = "bootstrap.tfstate"
region       = "<region>"
use_lockfile = true
encrypt      = true
```
#### Azure

Create a storage account and container for the state, with versioning enabled and public blob access disabled. Replace `<resource_group>`, `<state_storage_account_name>`, and `<location>` with the values from your `turbopuffer.tfvars`.

```bash
az group create --name <resource_group> --location <location>
az storage account create --name <state_storage_account_name> --resource-group <resource_group> \
  --location <location> --sku Standard_LRS --kind StorageV2 --allow-blob-public-access false
az storage account blob-service-properties update --account-name <state_storage_account_name> \
  --resource-group <resource_group> --enable-versioning true
az storage container create --name tfstate --account-name <state_storage_account_name>
```

Then point the bootstrap at it in `azure/bootstrap/backend.hcl`:

```hcl
resource_group_name  = "<resource_group>"
storage_account_name = "<state_storage_account_name>"
container_name       = "tfstate"
key                  = "bootstrap.tfstate"
```


---

This page: [/docs/byoc/managed.md](https://turbopuffer.com/docs/byoc/managed.md)

All documentation pages: [/llms.txt](https://turbopuffer.com/llms.txt)

All documentation in one file: [/llms-full.txt](https://turbopuffer.com/llms-full.txt)
