Skip to main content

Azure

The Django backend and both PostgreSQL databases live in Azure under nonprofit credits. Everything else is in Cloudflare.

Resource groups​

EMAW-Development​

ResourceTypePurposeAccess
development-django-vmLinux VMRuns the backend compose stack from /opt/emaw/emaw-django-appSSH over Tailscale with a key
development-database-vmLinux VMPostgreSQL (behind pgbouncer) for devOnly over Tailscale or from vnet-emaw-dev; no public endpoint
vnet-emaw-devVirtual networkConnects the two VMs so the stack reaches the DB privately

The dev Django VM connects to the database over the vnet. A developer's laptop running the stack connects to the same database over Tailscale (DB_HOST in .env is a Tailscale IP).

EMAW-APP-RG (production)​

ResourceTypePurposeAccess
DockerAppLinux VMRuns the production compose stack, deployed through PortainerSSH with a key from an allow-listed IP; Portainer UI from an allow-listed IP
emawweb-serverAzure Database for PostgreSQL flexible serverProduction databaseEMAWWebVnet only; the Django app is the only client. SSH is blocked.
EMAWWebVnetVirtual networkLinks the VM and the database
emawblobStorage account, container mediaDjango default file storage for both environments: resource cover images, generated verse audio, the Bible embeddings parquetKey in AZURE_BLOB_KEY; SAS token in AZURE_BLOB_SAT for audio
emaw-appKey VaultHolds the emaw-app-salt secret the production backend reads for username hashing (EMAW/utils.py); dev uses EMAW_SALT from .envManaged identity on the VM
EMAWWebApp Service (legacy)The pre-Docker deployment target of the main_emawweb.yml workflow and azure-pipelines.yml. Not the live backend.See Backend deployment

Other Azure services the backend uses​

ServiceUsed byEnv vars
Azure Communication Services (Email)Marketing campaigns (campaigns/acs.py), delivery and engagement events via Event Grid webhookACS_CONNECTION_STRING, ACS_SENDER_ADDRESS, ACS_SENDER_NAME, ACS_REPLY_TO, ACS_EVENTGRID_WEBHOOK_KEY
Azure Maps (Search)Geocoding contacts and event venues (crm/geocoding.py)AZURE_MAPS_KEY, GEOCODING_ENABLED
Microsoft Graph (Entra app registration)Transactional email: verification codes, password resets, receipts (EMAW/backends/graph_email.py)MS_TENANT_ID, MS_CLIENT_ID, MS_CLIENT_SECRET, MS_SENDER_UPN

Portainer​

Production deploys are done through Portainer at https://52.234.34.217:9443/. Your public IP must be allow-listed (ask Matt Birne). Portainer manages the compose stack on the DockerApp VM: pull the new image or git pull, then redeploy the stack. See Backend deployment.

Nonprofit credits​

EMAW receives Microsoft nonprofit Azure credits that cover these resources. Keep an eye on the credit balance in the portal; if credits lapsed, the server and database environment would cost roughly $150 a month.

Things to know​

  • Both environments write to the same blob container. Do not delete or overwrite blobs casually; prod cover images and audio live next to dev's.
  • The production VM and database are not on Tailscale yet. That migration is planned; until then the IP whitelist is the control.
  • The legacy EMAWWeb App Service and its workflows still exist. A push to main on the backend triggers them. They do not affect the Docker deployment, but they are a trap for anyone expecting main to deploy the real backend.