Deploy a node on Azure
Available now
This stands up a new OHM environment on Azure Container Apps — your own resource group, storage, API, and (when you want them) background-generation workers. It does not change the public openhardwaremanager.org deployment; that stack is separate.
One option, not the default
Self-hosting does not require Azure or any cloud account.
Run your own node is the supported path everywhere,
including on a server you own — it's one docker compose up, and it's what
to use unless you specifically want managed infrastructure.
This guide exists because it's what the public instance runs, so it's the cloud path we can keep honest. There is no equivalent for AWS or Google Cloud; both are supported as storage backends, with compute via Compose on a VM.
You need the OHM source tree (the Terraform lives under
deploy/terraform/azure/), an Azure subscription you can create resources in,
and a published OHM container image.
What gets created
| Piece | Role |
|---|---|
| Resource group | Isolates the environment so you can tear it down cleanly |
| Storage account + container | Where designs, facilities, and packages live |
| Container Apps environment | Runs the API (and optional worker) |
| API Container App | The OHM service, with a random admin API_KEYS value |
| Redis + worker (optional) | Celery broker and background worker for async generate-from-url |
| Encryption secrets (production) | OHM_ENCRYPTION_SALT / OHM_ENCRYPTION_PASSWORD so admins can store LLM keys in Settings |
Prerequisites
- Azure CLI, logged in (
az login) with permission to create resource groups, Container Apps, storage, and (if you enable jobs) Azure Cache for Redis - Terraform 1.5 or newer
- A pullable image, for example
touchthesun/openhardwaremanager:<version>— pin an explicit version; don't tracklatestfor anything you depend on
Fastest path: one peer with jobs
The repository includes a minimal single-node example at
deploy/terraform/azure/examples/single-peer/. Copy that root (or the
ohm_node module usage from deploy/terraform/azure/main.tf) into a working
directory, then set at least:
environment = "production" # provisions LLM encryption secrets
enable_jobs = true # Redis + Celery worker + JOBS_ENABLED on the API
image = "touchthesun/openhardwaremanager:<version>"
Apply from that directory:
The module outputs the API hostname (fqdn) and a sensitive admin API key.
Point a reverse proxy — or the frontend image's API_UPSTREAM_URL — at that
HTTPS origin.
What enable_jobs and environment do
| Setting | Effect |
|---|---|
enable_jobs = true |
Provisions Redis and a no-ingress worker app; sets JOBS_ENABLED, JOB_BROKER_URL, and JOB_RESULT_BACKEND on the API |
enable_jobs = false |
API only (default on the multi-peer federation lab, to control cost). Generate-from-url still works synchronously, but long runs can hit proxy timeouts |
environment = "production" |
Boots with real LLM encryption secrets so Settings → LLM providers can store keys |
environment = "test" |
Fine for short-lived labs; the app will refuse to persist LLM keys against development defaults |
Async import behaviour is described in Import from a URL.
Multi-peer federation lab
If you need several regional peers to exercise federation (not a permanent
self-host), use the ephemeral lab under deploy/terraform/azure/:
cp deploy/terraform/azure/environments/federation-ephemeral.tfvars.example \
deploy/terraform/azure/environments/federation-ephemeral.tfvars
# Optional: enable_jobs = true / environment = "production" in the tfvars
# when you want the same job stack on every peer (costs more).
./deploy/terraform/azure/scripts/up.sh
up.sh runs a two-pass apply so peer URLs can be wired into
OHM_FEDERATION_MANUAL_PEERS. Tear everything down with
./deploy/terraform/azure/scripts/down.sh when finished — destroy removes the
resource group; leftover cost should be ~zero after that completes.
Federation identity for those nodes lives on ephemeral app filesystem: destroy loses it.
After the first apply
- Open
https://<fqdn>/healthand confirm the instance reports healthy storage. - Authenticate with the outputted
API_KEYSvalue (Authorization: Bearer …). - If you set
environment = "production", add an LLM provider under Settings → LLM providers (or keep using process env keys). - If you set
enable_jobs = true, run a generate-from-url import and confirm the UI shows a progress bar rather than hanging on a long request — see Import from a URL.
Day-to-day self-host expectations (storage, upgrades, access control) are in Run your own node.
What this path is not
- It is not the CD pipeline for the public OHM instance. That continues to use a separate deploy script against an existing resource group.
- Turning jobs on for that public stack requires the same Redis + worker wiring there; publishing a new API image alone does not enable background generation.
Operator detail (variable reference, CPU/memory pairs, idle cost policy) stays
in deploy/terraform/azure/README.md in the source tree.