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, andtenant-web, plus the shared runtime volume those services need. Public docs are expected to live on Vercel and be injected into the app viaORGINABOX_DOCS_URL.
Prerequisites
- Azure CLI (
az) installed and authenticated:az login - Azure subscription with
Contributorrole - 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, andtenant-web - Managed identities for ACR pulls plus Key Vault-backed core-service secrets
- A persisted
opencode-server-passwordKey Vault secret used by the API, worker, and sandbox
3. Configure GitHub Actions
Add these secrets to your GitHub repository (Settings → Secrets):
| Secret | Value |
|---|---|
AZURE_CLIENT_ID | Service principal / managed identity client ID |
AZURE_TENANT_ID | Azure AD tenant ID |
AZURE_SUBSCRIPTION_ID | Azure subscription ID |
AZURE_ENTRA_CLIENT_ID | Optional Entra ID app registration for SSO |
AZURE_POSTGRES_ADMIN_PASSWORD | PostgreSQL admin password used by the Bicep deployment |
ORGINABOX_API_KEY | API bearer token |
Add these variables (Settings → Variables):
| Variable | Value |
|---|---|
ACR_LOGIN_SERVER | oiabprodacr.azurecr.io |
ACR_NAME | oiabprodacr |
AZURE_RESOURCE_GROUP | oiab-prod-rg |
ORGINABOX_WEB_URL | Optional override for backend auth redirects and deep links |
ORGINABOX_PLATFORM_WEB_URL | Optional override for platform-admin redirects and platform SSO flows |
AZURE_REDIRECT_URI | Optional override for the Entra callback URL used by the API update step |
ORGINABOX_TENANT_WEB_URL | Optional override for tenant-admin links in the promoted web image |
ORGINABOX_DOCS_URL | Public docs base URL, typically the Vercel docs hostname |
4. CI/CD Pipeline
The .github/workflows/deploy-azure.yml pipeline:
- On every PR: runs
bun testandbunx tsc --noEmit - 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 - On merge to
main: pulls those exact published images back from ACR and smoke-tests the production containers before deployment - On merge to
main: resolves the shared sandbox password by reusing the persisted Key Vault secret or generating one on first deploy - Manual infra reconcile:
workflow_dispatchcan optionally reconcile Bicep infrastructure before rollout, but push-to-maindeploys do not run infra by default - On merge to
main: deploys that same immutable tag to Azurestaging, waits for each Container App revision (api,worker,sandbox,web,platform-web,tenant-web) to report ready, and runs smoke tests - Manual promotion:
workflow_dispatchcan targetdevorprod, but non-devpromotion requires an explicitimage_tagso 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 PresettoNext.js - Set
Root Directorytopackages/docs - Leave the build/install/dev overrides blank unless Vercel fails to auto-detect them
- Point
ORGINABOX_DOCS_URLin each GitHub Environment at the final docs hostname, for examplehttps://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
stagingautomatically frommain. devandprodpromotion still depend on a human choosing the staging-provenimage_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-
stagingpromotions do not cancel the automaticstagingrollout onmain. - 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:
- Watches failed
workflow_runcompletions forDeploy to Azure - Dedupes by source commit SHA so one broken commit does not spawn multiple fix PRs
- Launches
gh agent-task createwith the repo-scoped custom agent in.github/agents/ci-fix-pr.md - 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, andAutofix source runmarkers 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.
