Back to Blog
DevOps
2 min read

Configuring Linux Web Apps in Terraform - Python and Node.js Stacks

AzureTerraformApp ServicePythonNode.js

Azure Linux Web Apps are great for Python and Node.js applications, but the Terraform configuration has some gotchas. Here's how to get it right.

Python with Gunicorn

For a Python Flask/FastAPI app:

resource "azurerm_linux_web_app" "python_app" {
  name                = "app-python-example"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location
  service_plan_id     = azurerm_service_plan.this.id

  site_config {
    application_stack {
      python_version = "3.11"
    }

    app_command_line = "gunicorn --workers 4 --threads 2 --bind 0.0.0.0:8000 app:app"
  }

  app_settings = {
    "SCM_DO_BUILD_DURING_DEPLOYMENT" = "true"
    "WEBSITES_PORT"                   = "8000"
  }
}

Key Points

app_command_line - This is your startup command. For Gunicorn:

  • --workers 4 - Number of worker processes (adjust based on plan size)
  • --threads 2 - Threads per worker
  • --bind 0.0.0.0:8000 - Listen on all interfaces, port 8000
  • app:app - Module:application (your Flask/FastAPI app object)

WEBSITES_PORT - Must match the port in your startup command.

SCM_DO_BUILD_DURING_DEPLOYMENT - Runs pip install -r requirements.txt during deployment.

Python with Uvicorn (FastAPI)

For async FastAPI apps, use Uvicorn:

site_config {
  application_stack {
    python_version = "3.11"
  }

  app_command_line = "uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4"
}

Or combine with Gunicorn for better process management:

app_command_line = "gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000"

Node.js Configuration

resource "azurerm_linux_web_app" "node_app" {
  name                = "app-node-example"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location
  service_plan_id     = azurerm_service_plan.this.id

  site_config {
    application_stack {
      node_version = "18-lts"
    }

    app_command_line = "npm start"
  }

  app_settings = {
    "WEBSITE_NODE_DEFAULT_VERSION" = "~18"
    "SCM_DO_BUILD_DURING_DEPLOYMENT" = "true"
  }
}

For PM2 process management:

app_command_line = "pm2 start ecosystem.config.js --no-daemon"

Common Issues

App not starting - Check the startup command matches your application structure. Use Log Stream in the portal to see errors.

Port mismatch - Ensure WEBSITES_PORT matches your app's listen port.

Dependencies not installed - Set SCM_DO_BUILD_DURING_DEPLOYMENT to true, or use a deployment slot with build enabled.

Wrong Python/Node version - Check available versions with az webapp list-runtimes --os linux.

VNET Integration

If your app needs to access private resources:

resource "azurerm_app_service_virtual_network_swift_connection" "this" {
  app_service_id = azurerm_linux_web_app.python_app.id
  subnet_id      = azurerm_subnet.app_integration.id
}

The subnet must be delegated to Microsoft.Web/serverFarms.


Need help deploying web applications to Azure? Get in touch - we help teams build and deploy cloud applications.

Need help with your Azure environment?

Get in touch for a free consultation.

Get in Touch