Org in a Box
Deployment

Azure Deployment

Deploy Org in a Box to Azure Container Apps using Bicep IaC and GitHub Actions CI/CD.

Preview status: the checked-in Azure path now provisions api, worker, sandbox, web, platform-web, and tenant-web, plus the shared runtime volume those services need. Public docs are expected to live on Vercel and be injected into the app via ORGINABOX_DOCS_URL.

Prerequisites

  • Azure CLI (az) installed and authenticated: az login
  • Azure subscription with Contributor role
  • GitHub repository with Actions enabled
  • Docker installed locally (for building images)

1. Create a Resource Group

az group create \
  --name oiab-prod-rg \
  --location eastus

2. Deploy Infrastructure (Bicep)

First-time deployment provisions all Azure resources:

OPENCODE_SERVER_PASSWORD="$(openssl rand -base64 48 | tr -d '\n' | tr '+/' '-_')"

az deployment group create \
  --resource-group oiab-prod-rg \
  --template-file infra/main.bicep \
  --parameters infra/parameters/prod.bicepparam \
  --parameters \
    azureClientId="$AZURE_ENTRA_CLIENT_ID" \
    azureTenantId="$AZURE_TENANT_ID" \
    postgresAdminPassword="$AZURE_POSTGRES_ADMIN_PASSWORD" \
    orginaboxApiKey="$ORGINABOX_API_KEY" \
    opencodeServerPassword="$OPENCODE_SERVER_PASSWORD"

This creates:

  • Azure Container Registry (Premium SKU in prod)
  • Key Vault with soft-delete + purge protection
  • Log Analytics Workspace + Application Insights
  • PostgreSQL Flexible Server with pgvector extension
  • Container Apps Environment
  • Azure Files-backed runtime storage mounted into the API, worker, and sandbox
  • 6 Container Apps in the selected environment: api, worker, sandbox, web, platform-web, and tenant-web
  • Managed identities for ACR pulls plus Key Vault-backed core-service secrets
  • A persisted opencode-server-password Key Vault secret used by the API, worker, and sandbox

3. Configure GitHub Actions

Add these secrets to your GitHub repository (Settings → Secrets):

SecretValue
AZURE_CLIENT_IDService principal / managed identity client ID
AZURE_TENANT_IDAzure AD tenant ID
AZURE_SUBSCRIPTION_IDAzure subscription ID
AZURE_ENTRA_CLIENT_IDOptional Entra ID app registration for SSO
AZURE_POSTGRES_ADMIN_PASSWORDPostgreSQL admin password used by the Bicep deployment
ORGINABOX_API_KEYAPI bearer token

Add these variables (Settings → Variables):

VariableValue
ACR_LOGIN_SERVERoiabprodacr.azurecr.io
ACR_NAMEoiabprodacr
AZURE_RESOURCE_GROUPoiab-prod-rg
ORGINABOX_WEB_URLOptional override for backend auth redirects and deep links
ORGINABOX_PLATFORM_WEB_URLOptional override for platform-admin redirects and platform SSO flows
AZURE_REDIRECT_URIOptional override for the Entra callback URL used by the API update step
ORGINABOX_TENANT_WEB_URLOptional override for tenant-admin links in the promoted web image
ORGINABOX_DOCS_URLPublic docs base URL, typically the Vercel docs hostname

4. CI/CD Pipeline

The .github/workflows/deploy-azure.yml pipeline:

  1. On every PR: runs bun test and bunx tsc --noEmit
  2. On merge to main: builds the core, web, platform-web, tenant-web, and sandbox images once and pushes them to ACR with a unique git-SHA tag only
  3. On merge to main: pulls those exact published images back from ACR and smoke-tests the production containers before deployment
  4. On merge to main: resolves the shared sandbox password by reusing the persisted Key Vault secret or generating one on first deploy
  5. Manual infra reconcile: workflow_dispatch can optionally reconcile Bicep infrastructure before rollout, but push-to-main deploys do not run infra by default
  6. On merge to main: deploys that same immutable tag to Azure staging, waits for each Container App revision (api, worker, sandbox, web, platform-web, tenant-web) to report ready, and runs smoke tests
  7. Manual promotion: workflow_dispatch can target dev or prod, but non-dev promotion requires an explicit image_tag so those environments consume a staging-proven artifact instead of rebuilding

To trigger a deployment manually with infrastructure update:

Actions → Deploy to Azure → Run workflow → environment: staging|prod → image_tag: <dev tag> → deploy_infra: true|false

Docs on Vercel

The public docs site is no longer part of the Azure Container Apps rollout.

  • Create a separate Vercel project rooted at packages/docs
  • Set Framework Preset to Next.js
  • Set Root Directory to packages/docs
  • Leave the build/install/dev overrides blank unless Vercel fails to auto-detect them
  • Point ORGINABOX_DOCS_URL in each GitHub Environment at the final docs hostname, for example https://docs.orginabox.com

The effective Vercel config for the docs app lives in packages/docs/vercel.json. The repo-root vercel.json is intentionally minimal and not the authoritative docs deployment file.

Current Limitations

These are the current known gaps for the Azure path:

  • Local Docker Compose is still the primary contributor dev path, but the checked-in GitHub Actions workflow now deploys Azure staging automatically from main.
  • dev and prod promotion still depend on a human choosing the staging-proven image_tag.
  • Custom domain, DNS, and secret wiring are still manual steps in the portal or via CLI.
  • Key Vault is still deployed with public networking in this preview path; private-endpoint-only secret access is not wired yet.
  • Workflow concurrency is isolated by environment so manual non-staging promotions do not cancel the automatic staging rollout on main.
  • There is no blue/green or canary promotion story documented in the checked-in workflow yet.
  • This page reflects the checked-in IaC and workflow path from this repo snapshot; it does not claim a full live validation of every production dependency.

What Azure Does Today

  • Hosts the browser-facing web app, platform admin app, tenant admin app, API, worker, and sandbox
  • Stores secrets in Key Vault and application telemetry in Azure monitoring services
  • Provides a shared runtime volume for the API, worker, and sandbox
  • Supports Entra-based auth configuration plus build-once staging deploy and manual non-staging promotion in GitHub Actions

What Azure Does Not Yet Do

  • Deliver the warm sandbox pool and multi-VM dispatch topology described in experimental docs
  • Replace a real first-pass validation in your target Azure subscription

5. Failed-run autofix PRs

When Deploy to Azure fails on main, .github/workflows/provision-ci-fix-pr.yml provisions a background GitHub agent task instead of leaving the failure as a dead end.

That workflow:

  1. Watches failed workflow_run completions for Deploy to Azure
  2. Dedupes by source commit SHA so one broken commit does not spawn multiple fix PRs
  3. Launches gh agent-task create with the repo-scoped custom agent in .github/agents/ci-fix-pr.md
  4. Asks the agent to inspect the failing logs, make the smallest safe fix, and open a draft PR

Operational notes:

  • The workflow depends on repo secret GH_AGENT_TOKEN
  • The draft PR body includes Autofix source workflow, Autofix source sha, and Autofix source run markers for traceability and dedupe
  • The intended operator loop is: wait for the background agent task to finish, review the draft PR, then merge or request changes

6. Custom Domains

In the Azure Portal → Container Apps → oiab-prod-api → Custom domains:

az containerapp hostname add \
  --name oiab-prod-api \
  --resource-group oiab-prod-rg \
  --hostname api.yourcompany.com

Scaling

Container Apps auto-scale on HTTP concurrency:

  • API: 1–10 replicas (scales at 50 concurrent requests per replica)
  • Worker: 1–3 replicas (production), 1 replica (staging)
  • Web: 1–5 replicas
  • Platform web: 1–3 replicas
  • Tenant web: 1–3 replicas

Monitoring

After deployment, Application Insights receives:

  • OpenTelemetry traces from all services
  • Container logs via Log Analytics
  • Custom metrics from the analytics plugin

View in Azure Portal → Application Insights → oiab-prod-ai.

On this page