Skip to content

Click on each book below to review & buy on Amazon.

As an Amazon Associate, I earn from qualifying purchases.


Terraform - Azure Linux Web App - Custom Domain - Zip Deployment

This guide provides detailed instructions for deploying an Azure Linux Web App using a zip file, configuring a custom domain, and securing it with SSL, all orchestrated through Terraform. It is designed for those looking to automate the deployment and management of Azure web applications with custom domain names.

The versions used during testing this process were:

Terraform Version1.7.3
Azurerm Version3.91.0

Prerequisites

Before beginning this Terraform guide, certain prerequisites must be met to ensure a smooth deployment process:

  • Local Zip File of Your Website: The website you intend to deploy should be packaged as a zip file and stored locally. This zip file should contain all necessary files for your website to run. Terraform will deploy this zip file to your Azure Linux Web App.
  • Domain Name Configuration Capability: You must have the ability to add CNAME records to your domain. This is essential for mapping your custom domain to the Azure Web App. A CNAME record will be used to point your domain to the Azure Web App's default hostname, enabling the use of your custom domain.
  • Azure Authentication: Authentication with Azure is required to provision resources through Terraform. This can typically be achieved by executing the az login command in your terminal, which signs you into Azure CLI (Command Line Interface). This step ensures that Terraform has the necessary permissions to create and manage resources within your Azure subscription.

Here is an example command to authenticate with Azure:

az login

After running this command, your default web browser will open and prompt you to enter your Azure credentials. Upon successful authentication, the Azure CLI will be connected to your account, granting Terraform the access it needs.

Terraform Block

In a Terraform configuration, the terraform block is used to specify the required version of Terraform and the providers necessary for the infrastructure deployment. This block ensures that the Terraform code is executed with a compatible version and that the correct providers are utilized to manage resources in the target environment, such as Azure in this guide.

Here's a detailed look at the terraform block:

terraform {
  required_version = "=1.7.3"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.91.0"
    }
  }
}
  • required_version: This attribute specifies the exact version of Terraform that this configuration is designed for, which is 1.7.3 in this case. Using the exact version ensures consistency across different environments and among team members, preventing potential discrepancies that could arise from using different Terraform versions.
  • required_providers: This section lists the providers that your Terraform configuration will use. Providers are plugins Terraform uses to interact with cloud providers, SaaS providers, and other APIs.
    • azurerm: This is the provider used for managing resources in Microsoft Azure. The azurerm provider block contains two attributes:
      • source: This indicates where Terraform can find the provider. The standard format is <NAMESPACE>/<PROVIDER>, with hashicorp/azurerm specifying the official HashiCorp namespace for the Azure provider.
      • version: Similar to required_version for Terraform, this specifies the exact version of the azurerm provider to use, 3.91.0 in this case. Pinning the provider version is essential for maintaining consistency and reliability in your infrastructure management practices.

Variable Block

In Terraform, variables allow parameterization of configurations, making them more dynamic and reusable. The variable block defines a variable that can be referenced throughout the Terraform configuration, enabling customization of deployments without altering the main codebase.

Below is an example of the required variable block:

variable "subscription_id" {
  type        = string
  default     = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  description = "Subscription ID that should match the environment"
}
  • variable "subscription_id": This declares a new variable named subscription_id. The name of the variable is used to reference its value within the Terraform configuration.
  • type: This attribute specifies the data type of the variable. In this case, it's a string, indicating the variable value will be a sequence of characters.
  • default: The default attribute provides a default value for the variable, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in this example. This default value is used if no explicit value is provided for the variable when Terraform is run. While the default value is optional, it can be helpful for setting a common or fallback value.
  • description: This attribute offers a description of what the variable is used for, aiding anyone who uses the Terraform configuration in understanding its purpose. In this case, it explains that the variable should hold the Azure subscription ID that matches the target environment for the deployment.

Terraform Provider Block

The provider block in this Terraform code configures the Azure provider, which is responsible for managing resources in the Azure cloud. The azurerm provider is used in this code, and it is defined with the subscription ID variable provided as input.

provider "azurerm" {
  subscription_id = var.subscription_id
  features {
    resource_group {
      prevent_deletion_if_contains_resources = true
    }
  }
}
  • subscription_id: This variable specifies the ID of the Azure subscription where the resources will be provisioned. This variable is defined in the variables section of the code and can be overridden with a value at runtime.
  • features: This block enables specific features of the Azure provider. In this case, the resource_group feature has setting prevent_deletion_if_contains_resources set to true to prevent the resource group from being deleted if it contains resources. This is a safety feature to prevent accidental deletion of resources.

Resource Group

The azurerm_resource_group resource block is pivotal for defining an Azure Resource Group that Terraform will manage. This block outlines the initial step in resource organization, setting the stage for deploying and managing Azure resources within a structured and named container.

resource "azurerm_resource_group" "rg-webapp-001" {
  name     = "rg-webapp-prod-001"
  location = "ukwest"
}
  • name: This attribute designates the unique name of the Resource Group within Azure. It is a key identifier for managing and organizing your Azure resources. In this example, the Resource Group is named rg-webapp-prod-001, suggesting a naming convention that could include the application name, environment, and a sequence number for easy identification.

  • location: This specifies the geographic region where the Resource Group will be located. The choice of location can affect the latency, availability, and pricing of the resources deployed within the group. Here, ukwest is selected, indicating the UK West region as the deployment target.

App Service Plan

The azurerm_service_plan resource block defines the characteristics and capabilities of an Azure App Service Plan. This plan is a container for web apps, specifying the set of compute resources allocated to them. It determines not just the performance and scalability of the apps, but also their cost.

Here's a detailed breakdown of each attribute within the azurerm_service_plan resource block:

resource "azurerm_service_plan" "asp-example-001" {
  name                = "asp-example-prod-001"
  resource_group_name = azurerm_resource_group.rg-webapp-001.name
  location            = "ukwest"
  os_type             = "Linux"
  sku_name            = "B1"
}
  • name: This is the unique identifier of the App Service Plan within the Azure subscription. It's vital for resource identification and management within Azure.
  • resource_group_name: Indicates the Resource Group under which the App Service Plan is categorized, tying it to a logical grouping of related Azure resources for easier management and billing.
  • location: Defines the geographic region where the App Service Plan is hosted. The choice of location impacts the latency for end-users and can be important for compliance with data residency regulations. Azure offers multiple regions worldwide to host your service plan.
  • os_type: Specifies the operating system that will run on the App Service Plan. Valid options include Linux and Windows. This choice should align with the technology stack of your web applications. Linux is often chosen for open-source stacks, while Windows is necessary for .NET or other Windows-specific technologies.
  • sku_name: Determines the pricing tier of the App Service Plan, which directly impacts the available features, performance, and cost. The SKU name consists of two parts: a tier and an instance size (e.g., B1, S1, P1v2):
    • B*: Basic tier, offering cost-effective options for development or low-traffic websites, with limited auto-scaling capabilities.
    • S*: Standard tier, suitable for production websites, supporting auto-scaling, custom domain names, and SSL certificates.
    • P*: Premium tier, providing high-performance options for high-traffic websites and applications, with advanced capabilities like VNet integration and private endpoints.
    • I*: Designed for apps requiring high levels of scale, isolation, and security.

Linux Web App

The azurerm_linux_web_app resource block deploys a Linux-based web application in Azure, providing a detailed configuration that tailors the web app's environment, security, and deployment method. This configuration ensures that your web application is deployed with specific performance, security, and operational settings in Azure App Service, a managed service for hosting web apps.

resource "azurerm_linux_web_app" "app-example-001" {
  name                                           = "app-example-prod-001"
  resource_group_name                            = azurerm_resource_group.rg-webapp-001.name
  location                                       = "ukwest"
  service_plan_id                                = azurerm_service_plan.asp-example-001.id
  https_only                                     = false
  zip_deploy_file                                = "${path.cwd}/files/web_app/site.zip"
  ftp_publish_basic_authentication_enabled       = false
  webdeploy_publish_basic_authentication_enabled = false

  app_settings = {
    WEBSITE_RUN_FROM_PACKAGE = 1
  }

  site_config {
    always_on           = true
    ftps_state          = "Disabled"
    minimum_tls_version = 1.2
    application_stack {
      php_version = 8.2
    }
  }
}
  • name: The unique name assigned to the web app within Azure, serving as its identifier.
  • resource_group_name: Determines the Resource Group under which the web app is categorized, facilitating resource organization and management.
  • location: Defines the geographic region of the web app's deployment, affecting latency and availability.
  • service_plan_id: Links the web app to a specific App Service Plan, which outlines the compute resources allocated to the app.
  • https_only: Enforces HTTPS for the web app, enhancing security by ensuring all communications are encrypted. Setting this to false allows HTTP traffic, but it's recommended to enable HTTPS in production environments.
  • zip_deploy_file: Specifies the local path to the ZIP file containing the web app's code, enabling straightforward deployment from a compressed archive.
  • ftp_publish_basic_authentication_enabled, webdeploy_publish_basic_authentication_enabled: These settings control the authentication methods for FTP and web deployment, respectively. Disabling them (false) enhances security by preventing basic authentication.
  • app_settings: Custom application settings, such as WEBSITE_RUN_FROM_PACKAGE, which configures the app to run directly from a package i.e Zip Deployment.
  • site_config:
    • always_on: Keeps the web app loaded, preventing idle shutdown. This is important for apps that require constant readiness or have background tasks.
    • ftps_state: Configures FTPS access for the web app. Disabling it ("Disabled") increases security by limiting deployment access methods.
    • minimum_tls_version: Sets the minimum TLS version to be accepted, with 1.2 enhancing security by using modern encryption standards.
    • application_stack: Defines the runtime stack of the web app, such as php_version = 8.2, ensuring compatibility with specific application requirements.

App Service Custom Hostname Binding

The azurerm_app_service_custom_hostname_binding resource integrates a custom domain with an Azure Web App, establishing a professional and recognizable URL for your application.

This resource links your chosen domain name to the web app, enabling users to access the app through the custom domain.

resource "azurerm_app_service_custom_hostname_binding" "chb-example-001" {
  hostname            = "www.example.com"
  app_service_name    = azurerm_linux_web_app.app-example-001.name
  resource_group_name = azurerm_resource_group.rg-webapp-001.name
}
  • hostname: This attribute designates the custom domain name you wish to bind to your web app.
  • app_service_name: Identifies the Azure Web App to which the custom domain will be linked. This ensures that requests to the specified hostname are routed to the correct web application.
  • resource_group_name: Specifies the Resource Group that contains the web app. This helps Azure organize and manage related resources efficiently.

DNS configuration is not managed by Terraform and must be performed separately to ensure the custom hostname can be resolved to the web app's IP address. On your first terraform deployment this resource will fail, however you will now have your web app built which gives you the details you need for performing your DNS configuration

App Service Managed Certificate

The azurerm_app_service_managed_certificate resource is an essential tool for securing your Azure Web App with SSL/TLS encryption. By generating a managed certificate, it automates the process of encrypting traffic for your custom domain, enhancing security and trustworthiness without the complexity of manual certificate management.

resource "azurerm_app_service_managed_certificate" "mc-example-001" {
  custom_hostname_binding_id = azurerm_app_service_custom_hostname_binding.chb-example-001.id
}
  • custom_hostname_binding_id: This attribute links the managed certificate to a specific custom hostname binding. By specifying the ID of the azurerm_app_service_custom_hostname_binding resource, it ensures that the certificate is applied to the correct custom domain associated with your web app.

App Service Certificate Binding

The azurerm_app_service_certificate_binding resource is the final step of securing your Azure Web App with SSL/TLS, linking the managed certificate directly to the web app's custom domain. This resource ensures that the web application uses the specified certificate for HTTPS encryption, safeguarding data in transit between the web server and its users.

resource "azurerm_app_service_certificate_binding" "cb-example-001" {
  hostname_binding_id = azurerm_app_service_custom_hostname_binding.chb-example-001.id
  certificate_id      = azurerm_app_service_managed_certificate.mc-example-001.id
  ssl_state           = "SniEnabled"
}
  • hostname_binding_id: This field is essential for identifying the custom hostname binding that the certificate will secure. It ensures that the HTTPS encryption is applied specifically to the web app's custom domain.
  • certificate_id: Indicates the managed certificate to be used for the custom hostname. This linkage automates the process of securing your web app with a valid SSL/TLS certificate.
  • ssl_state: Defines how SSL is configured for the web app. The below available options influence the security and compatibility of your web application:
    • SniEnabled: Server Name Indication (SNI) SSL type, where multiple SSL certificates can be hosted on a single IP address, with the server serving the correct certificate based on the domain requested. This is the most common and cost-effective option, suitable for most applications.
    • IpBasedEnabled: Assigns a dedicated IP address for the SSL certificate, ensuring the web app is accessible via both its custom domain and the IP address. This option is typically used for legacy browsers and systems that do not support SNI.
    • Disabled: Disables SSL for the custom domain, not recommended for production environments due to security concerns.

Redeploying site.zip

Redeploying your web application's content, especially for quick updates or fixes, is a streamlined process with the Azure CLI. The az webapp deploy command is specifically designed for this purpose, allowing you to upload a ZIP archive containing your web app's files directly to Azure App Service. This method is ideal for deploying web applications or updates without going through continuous integration and deployment pipelines.

To redeploy or update your web application using a ZIP file, the az webapp deploy command is used. This command simplifies the deployment process, making it accessible and efficient for developers and administrators.

Below is an example of running the az webapp deploy command:

az webapp deploy --name app-example-prod-001 --resource-group rg-webapp-prod-001 --type zip --src-path ./files/web_app/site.zip
  • --name: Specifies the name of the web app you are targeting for deployment. It should match the name of the web app created within Azure App Service.
  • --resource-group: Identifies the resource group where your web app resides.
  • --type zip: Indicates the deployment source type. In this case, zip specifies that the source files are packaged in a ZIP archive.
  • --src-path: Defines the local path to the ZIP file containing your web application's content. This path points to the archive that will be uploaded and deployed to your web app.

Ensure that your ZIP archive's structure matches the expected layout of your web application. The root of the ZIP file should contain the files and directories intended to be at the root of your web app.

Conclusion

This Terraform code creates a web app in Azure with a managed certificate for a custom hostname binding. The code provisions a resource group, a service plan, a Linux web app, a custom hostname binding, a managed certificate, and a certificate binding.

The azurerm_resource_group resource block creates a resource group to contain the web app resources. The azurerm_service_plan resource block provisions the service plan, which specifies the compute resources and operating system for the web app. The azurerm_linux_web_app resource block creates the web app and configures its settings. The azurerm_app_service_custom_hostname_binding and azurerm_app_service_managed_certificate resource blocks create a custom hostname binding and a managed certificate for the web app. Finally, the azurerm_app_service_certificate_binding resource block binds the managed certificate to the custom hostname binding.

How to redeploy you website as a zip archive was explained, providing a useful reference for quick redeployment's.

The Code

I have put all the Terraform code into one block below for easy copying. If you would like to use the code as a starting point for your own deployments, feel free to do so!

# This block specifies the version of Terraform and the required providers
terraform {
  required_version = "=1.7.3"
  required_providers {
    azurerm = {
      source  = "azurerm"
      version = "=3.91.0"
    }
  }
}

# This block specifies the Azure provider configuration
provider "azurerm" {
  subscription_id = var.subscription_id

  # This block enables a feature that prevents the resource group from being deleted if it contains resources
  features {
    resource_group {
      prevent_deletion_if_contains_resources = true
    }
  }
}

# This block defines a variable that can be used throughout the configuration
variable "subscription_id" {
  type        = string
  default     = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  description = "Subscription ID that should match the environment"
}

# This block creates an Azure resource group
resource "azurerm_resource_group" "rg-webapp-001" {
  name     = "rg-webapp-prod-001"
  location = "ukwest"
}

# This block creates an Azure service plan
resource "azurerm_service_plan" "asp-example-001" {
  name                = "asp-example-prod-001"
  resource_group_name = azurerm_resource_group.rg-webapp-001.name
  location            = "ukwest"
  os_type             = "Linux"
  sku_name            = "B1"
}

# This block creates an Azure Linux web app
resource "azurerm_linux_web_app" "app-example-001" {
  name                                           = "app-example-prod-001"
  resource_group_name                            = azurerm_resource_group.rg-webapp-001.name
  location                                       = "ukwest"
  service_plan_id                                = azurerm_service_plan.asp-example-001.id
  https_only                                     = false
  zip_deploy_file                                = "${path.cwd}/files/web_app/site.zip"
  ftp_publish_basic_authentication_enabled       = false
  webdeploy_publish_basic_authentication_enabled = false

  # This block sets the app settings for the web app
  app_settings = {
    WEBSITE_RUN_FROM_PACKAGE = 1
  }

  # This block sets the configuration for the web app
  site_config {
    always_on           = true
    ftps_state          = "Disabled"
    minimum_tls_version = 1.2

    application_stack {
      php_version = 8.2
    }
  }
}

# This block creates an Azure app service custom hostname binding
resource "azurerm_app_service_custom_hostname_binding" "chb-example-001" {
  hostname            = "www.example.com"
  app_service_name    = azurerm_linux_web_app.app-example-001.name
  resource_group_name = azurerm_resource_group.rg-webapp-001.name
}

# This block creates an Azure app service managed certificate
resource "azurerm_app_service_managed_certificate" "mc-example-001" {
  custom_hostname_binding_id = azurerm_app_service_custom_hostname_binding.chb-example-001.id
}

# This block creates an Azure app service certificate binding
resource "azurerm_app_service_certificate_binding" "cb-example-001" {
  hostname_binding_id = azurerm_app_service_custom_hostname_binding.chb-example-001.id
  certificate_id      = azurerm_app_service_managed_certificate.mc-example-001.id
  ssl_state           = "SniEnabled"
}

Support DTV Linux

Click on each book below to review & buy on Amazon. As an Amazon Associate, I earn from qualifying purchases.

NordVPN ®: Elevate your online privacy and security. Grab our Special Offer to safeguard your data on public Wi-Fi and secure your devices. I may earn a commission on purchases made through this link.