Skip to main content
Openfuse

Azure Container Apps

Deploy Openfuse on Azure Container Apps with Azure Database for PostgreSQL, Key Vault for secrets, and hostname-based routing via custom domains.

This guide covers deploying Openfuse on Azure Container Apps. For the single-server Docker Compose setup, see Docker Compose.

Prerequisites

  • An Azure subscription with Container Apps, Azure Database for PostgreSQL, and Key Vault
  • A managed PostgreSQL 17+ flexible server with two databases: openfuse and keycloak
  • A domain with wildcard DNS records pointing to your Container Apps environment
  • A Container Apps environment with custom domain and TLS configured

Architecture

ComponentAzure ResourceNotes
APIContainer AppStateless, auto-scales
KeycloakContainer AppMin replicas: 1
UIContainer AppStatic SPA, or use Azure CDN
Config ImporterContainer App JobExecute during deployments

Custom domain routing

Azure Container Apps support custom domains with SNI-based routing. Configure each app with its hostname:

Container AppCustom domainPort
openfuse-api*.api.<ROOT_DOMAIN>3000
keycloaksso.<ROOT_DOMAIN>8080
openfuse-ui<ROOT_DOMAIN>, *.<ROOT_DOMAIN>80

TLS is handled by Azure-managed certificates or your own certificates via Key Vault.

Key Vault secrets

Store secrets in Azure Key Vault and reference them in Container Apps:

# Create secrets
az keyvault secret set --vault-name openfuse-kv --name db-password --value "your-password"
az keyvault secret set --vault-name openfuse-kv --name session-secret --value "your-session-secret"
az keyvault secret set --vault-name openfuse-kv --name kc-admin-password --value "your-kc-password"
# ... repeat for each secret

Config Importer

Run the Config Importer as a Container App Job:

az containerapp job create \
  --name openfuse-config-importer \
  --resource-group openfuse-rg \
  --environment openfuse-env \
  --image ghcr.io/openfuseio/openfuse-config-importer:1.0.0 \
  --trigger-type Manual \
  --replica-timeout 300 \
  --env-vars \
    KEYCLOAK_URL=http://keycloak IMPORT_VARSUBSTITUTION_ENABLED=true \
    IMPORT_VARSUBSTITUTION_UNDEFINEDISTERROR=true \
  --secrets \
    kc-password=keyvaultref:openfuse-kv/kc-admin-password,identityref:/subscriptions/.../identity \
  --secret-env-vars \
    KEYCLOAK_PASSWORD=kc-password

# Execute it
az containerapp job start \
  --name openfuse-config-importer \
  --resource-group openfuse-rg

The importer waits up to 120s for Keycloak to be ready. Run on first deployment and on upgrades that include realm config changes.

API container app

az containerapp create \
  --name openfuse-api \
  --resource-group openfuse-rg \
  --environment openfuse-env \
  --image ghcr.io/openfuseio/openfuse-api:1.0.0 \
  --target-port 3000 \
  --ingress external \
  --min-replicas 1 \
  --max-replicas 10 \
  --env-vars \
    ROOT_DOMAIN=openfuse.example.com \
    DATABASE_HOST=openfuse-db.postgres.database.azure.com \
    DATABASE_SSL=true \
    KEYCLOAK_URL=http://keycloak \
    KEYCLOAK_EXTERNAL_URL=https://sso.openfuse.example.com \
  --secrets \
    db-password=keyvaultref:openfuse-kv/db-password,identityref:/subscriptions/.../identity \
  --secret-env-vars \
    DATABASE_PASSWORD=db-password

The API is stateless — scale freely. All replicas must share the same SESSION_SECRET. Database migrations use an advisory lock for safe concurrent startup.

Keycloak container app

az containerapp create \
  --name keycloak \
  --resource-group openfuse-rg \
  --environment openfuse-env \
  --image ghcr.io/openfuseio/openfuse-keycloak:1.0.0 \
  --args start \
  --target-port 8080 \
  --ingress external \
  --min-replicas 1 \
  --env-vars \
    KC_DB=postgres \
    KC_HOSTNAME=sso.openfuse.example.com \
    KC_PROXY_HEADERS=xforwarded \
    KC_HTTP_ENABLED=true \
    KC_HEALTH_ENABLED=true

Set --min-replicas 1 to avoid cold start delays on the login page.

Next steps

On this page