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

# Azure

> Deploy Tembo self-hosted on Microsoft Azure.

## Overview

The Tembo self-hosted stack runs as a single NixOS 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 image via an Azure Compute Gallery shared to your subscription. You create a VM from that image, open the required ports, and configure a single JSON file. No OS setup or image building is required on your end.

***

## Step 1: Request Access

To get started with Tembo self-hosted, you will need a license key and access to the Tembo Azure Compute Gallery 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 Azure subscription. You will need to provide:

* Your **license key**
* Your **Azure Subscription ID**
* Your preferred **Azure region** (e.g. `eastus`)

Tembo will share the Compute Gallery image with your subscription. You will receive the gallery details (subscription ID, resource group, and gallery name) 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: Create a Resource Group

```bash theme={null}
az group create \
  --name tembo-self-hosted-rg \
  --location eastus
```

***

## Step 3: Create the VM from the Gallery Image

### 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 a VM size that supports **nested virtualization** (e.g. `Standard_D8s_v3`, `Standard_D16s_v3`, or any v3/v4/v5 D-series or E-series). This allows sandbox VMs to run with hardware acceleration via KVM.
</Note>

### Via the Azure CLI

```bash theme={null}
az vm create \
  --resource-group tembo-self-hosted-rg \
  --name tembo-self-hosted \
  --image "/subscriptions/<tembo-subscription-id>/resourceGroups/<tembo-resource-group>/providers/Microsoft.Compute/galleries/<tembo-gallery-name>/images/tembo-self-hosted/versions/latest" \
  --size Standard_D8s_v3 \
  --os-disk-size-gb 128 \
  --admin-username eng \
  --generate-ssh-keys \
  --public-ip-sku Standard
```

Replace the placeholders with values provided by Tembo:

| Placeholder               | Description                            |
| ------------------------- | -------------------------------------- |
| `<tembo-subscription-id>` | Tembo's Azure subscription ID          |
| `<tembo-resource-group>`  | Resource group where the gallery lives |
| `<tembo-gallery-name>`    | Name of the Azure Compute Gallery      |

Note the `IpAddress` in the output — you will need it in later steps.

### Via the Azure Portal

1. Go to **Virtual machines > Create**
2. Select your resource group and region
3. Under **Image**, click **See all images**, then **Shared images** and select the Tembo image
4. Choose a VM size (`Standard_D8s_v3` or larger recommended)
5. Under **Disks**, set the OS disk size to at least **256 GiB**
6. Under **Networking**, select or create a virtual network
7. Create the VM

***

## Step 4: Configure the Network Security Group

By default, Azure VMs block all inbound traffic except SSH. Add inbound rules to allow access to Tembo:

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

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

### Via the Azure CLI

```bash theme={null}
# Allow HTTP on port 80
az network nsg rule create \
  --resource-group tembo-self-hosted-rg \
  --nsg-name tembo-self-hostedNSG \
  --name AllowHTTP \
  --priority 100 \
  --protocol Tcp \
  --destination-port-ranges 80 \
  --access Allow

# Allow installer — restrict to your IP
az network nsg rule create \
  --resource-group tembo-self-hosted-rg \
  --nsg-name tembo-self-hostedNSG \
  --name AllowInstaller \
  --priority 110 \
  --protocol Tcp \
  --destination-port-ranges 3999 \
  --source-address-prefixes <your-ip>/32 \
  --access Allow

# Allow VS Code server — restrict to your IP
az network nsg rule create \
  --resource-group tembo-self-hosted-rg \
  --nsg-name tembo-self-hostedNSG \
  --name AllowVSCode \
  --priority 120 \
  --protocol Tcp \
  --destination-port-ranges 8888 \
  --source-address-prefixes <your-ip>/32 \
  --access Allow

# Allow SSH — restrict to your IP
az network nsg rule create \
  --resource-group tembo-self-hosted-rg \
  --nsg-name tembo-self-hostedNSG \
  --name AllowSSH \
  --priority 130 \
  --protocol Tcp \
  --destination-port-ranges 22 \
  --source-address-prefixes <your-ip>/32 \
  --access Allow
```

Or in the portal: **VM > Networking > Add inbound port rule**.

<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.
</Warning>

***

## Step 5: Run the Installer and Configure the Instance

### 5a: Run the install workflow

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

```
http://<vm-public-ip>:3999
```

Follow the on-screen steps to complete the install workflow. This provisions the Tembo services and prepares the instance for use. This install can take up to an hour to fully complete. Subsequent updates will be faster.

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

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

```
http://<vm-public-ip>:8888
```

The VS Code server opens directly to `/var/lib/tembo/config.json`. You can also see it in the VS Code file explorer on the right as `config.json`. A few values must be set correctly for the install to work.

Ensure these keys are present and correct:

```json theme={null}
{
  "betterAuth.secret": "<random string, at least 32 characters>",
  "api.base": "http://<vm-ip>/api/",
  "frontend.url": "http://<vm-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 actual IP or hostname. |

After saving, restart the API. There is a background service that should restart the API for you on finishing edits, but you can also do this from a terminal in the VS Code server, or via SSH:

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

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

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

***

## Step 6: Verify the Install

Open a browser and navigate to:

```
http://<vm-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 the `tembo-ts-agent-X`, depending on how many agents you chose to provision in the install step, X will be that number. (Eg. 3 agents make tembo-ts-agent-1, tembo-ts-agent-2, tembo-ts-agent-3)

***

## Troubleshooting

### Auth 404 on sign-up

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

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

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

```
http://<vm-ip>       # correct
http://<vm-ip>:3000  # wrong — internal port only
```

If port 80 is blocked, check the Azure NSG inbound rules.

### 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 org.

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

### Sign-in loops / 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 the app from. Better Auth uses these 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. Restart the API:

```bash theme={null}
sudo nano /var/lib/tembo/config.json
sudo systemctl restart tembo-ts-api
```

### 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 Azure portal
* Verify the NSG has an inbound rule for port 80 (and port 22 for SSH)
* If using a virtual network, confirm the subnet has a route to the internet

***

## Need Help?

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