> ## Documentation Index
> Fetch the complete documentation index at: https://test-8862363a-tembo-docs-codex-usage-reset.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# GCP

> Deploy Tembo self-hosted on Google Cloud Platform.

## Overview

The Tembo self-hosted stack runs as a single NixOS virtual machine. All services sit behind nginx on port 80:

| Service                  | Path          | Port (internal) |
| ------------------------ | ------------- | --------------- |
| Web UI                   | `/`           | 3000            |
| API                      | `/api/*`      | 3001            |
| Admin UI                 | `/admin/`     | 3002            |
| Installer / setup wizard | `/installer/` | 3999            |
| PostgreSQL 16            | —             | 5432            |
| PGAdmin Console          | —             | 5050            |
| Redis                    | —             | 6379            |
| Prometheus               | —             | 9090            |

Tembo distributes a pre-built NixOS custom image to your Google Cloud project. You create a Compute Engine VM from that image, configure VPC firewall rules, and configure a single JSON file. No OS setup or image building is required on your end.

## Prerequisites

Before you begin, you need:

* A GCP project with billing and the Compute Engine API enabled
* Permission to manage project IAM, instances, and VPC firewall rules
* The `gcloud` CLI authenticated to your project, or equivalent access in Cloud Shell
* The trusted public IP ranges that need browser or SSH access

***

## Step 1: Request Access

To get started with Tembo self-hosted, you need a license key and access to the Tembo custom image. Book a demo with the Tembo team to get set up:

<a href="https://book.avoma.com/tembo/tembo-demo/" target="_blank">
  <button>Book a Demo</button>
</a>

Once you have a license key, contact Tembo to have the image shared with your Google Cloud project. You will need to provide:

* Your **license key**
* Your **Google Cloud project ID**
* Your preferred **region** (for example, `us-central1`)

Tembo will grant your project access to the custom image. You will receive the image name and the Tembo image project ID once sharing is confirmed.

<Note>
  The image contains no embedded secrets. Initial configuration is written to `/var/lib/tembo/config.json` at first boot by the `tembo-config-seed` service.
</Note>

***

## Step 2: Configure OS Login

The Tembo image uses [OS Login](https://cloud.google.com/compute/docs/oslogin). Enable it before connecting to the VM and grant operators OS administrator access. This role permits SSH access and `sudo`.

Prefer granting access to a group:

```bash theme={null}
gcloud projects add-iam-policy-binding <your-project-id> \
  --member='group:<operator-group@example.com>' \
  --role='roles/compute.osAdminLogin'
```

Enable OS Login for every VM in the project:

```bash theme={null}
gcloud compute project-info add-metadata \
  --project=<your-project-id> \
  --metadata=enable-oslogin=TRUE
```

If you cannot enable OS Login project-wide, add `enable-oslogin=TRUE` to each VM's metadata, as shown in the launch command below.

<Note>
  IAM changes can take several minutes to propagate. If your first SSH or `sudo` attempt fails immediately after granting the role, wait briefly and retry.
</Note>

***

## Step 3: Create a Compute Engine VM

### VM requirements

| Resource | Minimum | Recommended |
| -------- | ------- | ----------- |
| vCPUs    | 4       | 8           |
| RAM      | 16 GB   | 32 GB       |
| Disk     | 128 GB  | 256 GB      |

<Note>
  For the best sandbox performance, use an Intel machine type that supports nested virtualization, such as **`n2-standard-8`** or **`c3-standard-22`**. Avoid E2, AMD (N2D/C2D/T2D), and Arm machine types. The Tembo image includes the `enable-vmx` license, so `/dev/kvm` is available automatically on compatible machine types.
</Note>

### Via the Google Cloud CLI

Set the project and zone you will use:

```bash theme={null}
gcloud config set project <your-project-id>
gcloud config set compute/zone us-central1-a
```

Create the VM from the image shared by Tembo:

```bash theme={null}
gcloud compute instances create tembo-self-hosted \
  --machine-type=n2-standard-8 \
  --image-family=tembo-base \
  --image-project=<tembo-image-project-id> \
  --boot-disk-size=256GB \
  --boot-disk-type=pd-balanced \
  --metadata=enable-oslogin=TRUE \
  --tags=tembo-self-hosted
```

Replace the placeholders with values provided by Tembo. The command creates an external IP address by default; you will use it in the next steps. You do not need to pass `--enable-nested-virtualization` because it is enabled by the image.

### Via the Google Cloud console

1. Go to **Compute Engine > VM instances** and select **Create instance**
2. Choose your preferred region and zone
3. Under **Machine configuration**, select the **N2** series and choose **n2-standard-8** or larger
4. Under **Boot disk**, select **Change**, then choose **Custom images** and select the Tembo image shared with your project
5. Set the boot disk size to at least **256 GB** and select **Balanced persistent disk**
6. Under **Advanced options > Metadata**, add `enable-oslogin` with the value `TRUE`
7. Under **Networking**, add the network tag `tembo-self-hosted` and ensure the VM has an external IPv4 address
8. Select **Create**

<Tip>
  A `ZONE_RESOURCE_POOL_EXHAUSTED` error means the selected zone currently lacks capacity for that machine type; it is not a quota error. Try another zone in the same region, another compatible Intel machine type, or retry later.
</Tip>

***

## Step 4: Configure VPC Firewall Rules

VPC firewall rules control inbound traffic to Compute Engine VMs. Create rules that target the `tembo-self-hosted` network tag:

| Port | Protocol | Source                  | Purpose                         |
| ---- | -------- | ----------------------- | ------------------------------- |
| 80   | TCP      | Your preferred IP range | Tembo web UI and API            |
| 3999 | TCP      | Your IP                 | Installer / setup wizard        |
| 8888 | TCP      | Your IP                 | VS Code server (config editing) |
| 22   | TCP      | Your IP                 | SSH access                      |

Ports 3999 and 8888 are only needed during initial setup. You can remove those rules after configuration is complete.

### Via the Google Cloud CLI

```bash theme={null}
# Allow HTTP on port 80
gcloud compute firewall-rules create tembo-allow-http \
  --network=default \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:80 \
  --source-ranges=<your-ip-range> \
  --target-tags=tembo-self-hosted

# Allow the installer, VS Code server, and SSH — restrict to your IP
gcloud compute firewall-rules create tembo-allow-installer \
  --network=default \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:3999 \
  --source-ranges=<your-ip>/32 \
  --target-tags=tembo-self-hosted

gcloud compute firewall-rules create tembo-allow-vscode \
  --network=default \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:8888 \
  --source-ranges=<your-ip>/32 \
  --target-tags=tembo-self-hosted

gcloud compute firewall-rules create tembo-allow-ssh \
  --network=default \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:22 \
  --source-ranges=<your-ip>/32 \
  --target-tags=tembo-self-hosted
```

If you use a VPC other than `default`, replace `default` with its name. You can also create these rules in the console under **VPC network > Firewall**.

<Warning>
  Tembo services route through nginx on port 80. Do **not** open ports 3000, 3001, or 3002 publicly — those are internal-only ports. Accessing the app directly on port 3000 bypasses nginx and will break authentication.
  The configuration editor on port 8888 does not provide its own authentication. Never expose ports 3999 or 8888 to `0.0.0.0/0`.
</Warning>

***

## Step 5: Connect and Validate the VM

Connect using OS Login:

```bash theme={null}
gcloud compute ssh tembo-self-hosted \
  --project=<your-project-id> \
  --zone=<zone>
```

Confirm that OS Login administrator access and nested virtualization work:

```bash theme={null}
sudo -n id
ls -l /dev/kvm
```

`sudo -n id` should report `uid=0(root)`, and `/dev/kvm` should exist.

***

## Step 6: Run the Installer and Configure the VM

### 6a: Run the install workflow

Find the VM's external IP address:

```bash theme={null}
gcloud compute instances describe tembo-self-hosted \
  --format='get(networkInterfaces[0].accessConfigs[0].natIP)'
```

Once the VM is running, open the installer in your browser:

```text theme={null}
http://<vm-external-ip>:3999
```

Follow the on-screen steps to complete the install workflow. This provisions the Tembo services and prepares the VM for use. The initial install can take up to an hour; subsequent updates are faster.

### 6b: Configure `/var/lib/tembo/config.json`

After the installer finishes, open the VS Code server to edit the configuration file:

```text theme={null}
http://<vm-external-ip>:8888
```

The VS Code server opens directly to `/var/lib/tembo/config.json`. Ensure these keys are present and correct:

```json theme={null}
{
  "betterAuth.secret": "<random string, at least 32 characters>",
  "api.base": "http://<vm-external-ip>/api/",
  "frontend.url": "http://<vm-external-ip>"
}
```

| Key                 | Notes                                                                                                                   |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `betterAuth.secret` | Auto-generated on first boot if missing. Leave it if it is already set.                                                 |
| `api.base`          | Must match the public URL of the API. **Must end with a trailing `/`**.                                                 |
| `frontend.url`      | Defaults to `http://localhost:3000`, which breaks auth on a remote VM. Set this to the external IP address or hostname. |

Use the exact origin that users will enter in their browsers. Do not use a Tailscale address, an internal service port, or a VS Code forwarded URL such as `http://<vm-external-ip>:8888/proxy/...`.

After saving, restart the application services:

```bash theme={null}
sudo systemctl restart tembo-ts-api tembo-web nginx
```

The config seed runs before `tembo-ts-api`, `tembo-ts-cron`, and agent workers on every boot. Manual edits are preserved—the seed writes only values that are missing or empty.

<Tip>
  If you have a domain name, set both `api.base` and `frontend.url` to the domain (for example, `https://tembo.example.com/api/` and `https://tembo.example.com`) rather than the raw IP address. This makes it easier to rotate VMs or add a load balancer later.
</Tip>

***

## Step 7: Verify the Install

Open a browser and navigate to:

```text theme={null}
http://<vm-external-ip>
```

You should see the Tembo sign-up or sign-in screen.

Check service status on the VM:

```bash theme={null}
systemctl status tembo-ts-api
systemctl status tembo-ts-agent-X
systemctl status tembo-web
systemctl status nginx
```

For `tembo-ts-agent-X`, `X` is the number of the agent you chose to provision during installation. For example, three agents create `tembo-ts-agent-1`, `tembo-ts-agent-2`, and `tembo-ts-agent-3`.

***

## Troubleshooting

### SSH connects and immediately closes

Confirm that OS Login is enabled on the project or VM and that your identity has `roles/compute.osAdminLogin`:

```bash theme={null}
gcloud compute ssh tembo-self-hosted \
  --project=<your-project-id> \
  --zone=<zone> \
  --troubleshoot
```

If you just changed IAM, allow time for propagation and retry.

### A port is unreachable

Confirm that the VM has the `tembo-self-hosted` network tag and that the matching firewall rule includes your current public IP. From the VM, confirm that the service is listening locally:

```bash theme={null}
sudo ss -lntp | grep -E ':(80|3999|8888)\b'
```

### Auth 404 on sign-up

**Symptom:** `POST http://<vm-external-ip>:3000/api/auth/sign-up/email` returns 404.

**Cause:** You are reaching the Next.js frontend directly on port 3000 and bypassing nginx. The `/api/auth/*` handler does not exist at that port.

**Fix:** Access the app through nginx on port 80:

```text theme={null}
http://<vm-external-ip>       # correct
http://<vm-external-ip>:3000  # wrong — internal port only
```

If port 80 is blocked, check the VPC firewall rule and its `tembo-self-hosted` target tag.

### 401 after sign-up

**Symptom:** Sign-up succeeds but all subsequent API requests return 401.

**Cause:** Billing is enabled by default. Without Stripe configured, organization creation fails silently, leaving the user with no active organization.

**Fix:** Confirm `billing.enabled: false` is set in the API environment in `config.json`. Contact Tembo support if this was not set in the distributed image.

### Sign-in loops or cookie issues

**Symptom:** Sign-in redirects back to the login page, or cookies are not set.

**Cause:** `api.base` or `frontend.url` in `config.json` does not match the URL you are accessing in the browser. Better Auth uses these values for trusted origins and cookie domain validation.

**Fix:** Edit `/var/lib/tembo/config.json` and set both keys to the exact origin you are using in the browser. Do not use links from the VS Code **Ports** panel; those links route through port 8888. Restart the application services:

```bash theme={null}
sudo systemctl restart tembo-ts-api tembo-web nginx
```

### `/dev/kvm` is missing

Recreate the VM using a compatible Intel machine type such as N2 or C3. The image already enables nested virtualization; unsupported E2, AMD, and Arm machine types cannot expose KVM.

### Services not starting

```bash theme={null}
# Check all Tembo services at once
systemctl list-units 'tembo-*'

# View logs for a specific service
journalctl -u tembo-ts-api -n 100
journalctl -u tembo-web -n 100
```

The `tembo-config-seed` service must complete before the API and agents start. If the API fails immediately at boot, check:

```bash theme={null}
journalctl -u tembo-config-seed
cat /var/lib/tembo/config.json
```

### VM not reachable after launch

* Confirm the VM is in a **Running** state in the Google Cloud console.
* Verify the VM has an external IPv4 address.
* Verify the VPC firewall rules allow port 80 and target the `tembo-self-hosted` network tag.

***

## Need Help?

If you run into any issues, contact [support@tembo.io](mailto:support@tembo.io).
