[Yandex Cloud documentation](../../../index.md) > [Yandex Application Load Balancer](../../index.md) > [Tutorials](../index.md) > [Fault-tolerant website with load balancing via an Application Load Balancer](index.md) > Terraform

# Fault-tolerant website with load balancing via Yandex Application Load Balancer using Terraform


To create an infrastructure for your [website with load balancing](index.md) in three [availability zones](../../../overview/concepts/geo-scope.md) with an [Application Load Balancer](../../concepts/index.md) using Terraform:

1. [Get your cloud ready](#before-begin).
1. [Create your infrastructure](#deploy).
1. [Upload the website files](#upload-files).
1. [Test the fault tolerance](#test-ha).

If you no longer need the resources you created, [delete them](#clear-out).

## Get your cloud ready {#before-begin}

Sign up for Yandex Cloud and create a [billing account](../../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../../billing/quickstart/index.md) and [link](../../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../../resource-manager/concepts/resources-hierarchy.md).

### Required paid resources {#paid-resources}

The infrastructure support cost includes:
* Fee for continuously running [VMs](../../../compute/concepts/vm.md) (see [Yandex Compute Cloud pricing](../../../compute/pricing.md)).
* Fee for a dynamic [public IP address](../../../vpc/concepts/address.md#public-addresses) (see [Yandex Virtual Private Cloud pricing](../../../vpc/pricing.md)).
* Fee for load balancing (see [Application Load Balancer pricing](../../pricing.md)).
* Fee for public DNS queries and [DNS zones](../../../dns/concepts/dns-zone.md) if using [Yandex Cloud DNS](../../../dns/index.md) (see [Cloud DNS pricing](../../../dns/pricing.md)).

## Create an infrastructure {#deploy}

With [Terraform](https://www.terraform.io/), you can quickly create a cloud infrastructure in Yandex Cloud and manage it using configuration files. These files store the infrastructure description written in HashiCorp Configuration Language (HCL). If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.

Terraform is distributed under the [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE). The [Yandex Cloud provider for Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) is distributed under the [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/) license.

For more information about the provider resources, see the guides on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../../terraform/index.md).

To host a fault-tolerant website in an instance group with load balancing via Application Load Balancer using Terraform:
1. [Install Terraform](../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform), [get the authentication credentials](../../../tutorials/infrastructure-management/terraform-quickstart.md#get-credentials), and specify the source for installing the Yandex Cloud provider (see [Configure your provider](../../../tutorials/infrastructure-management/terraform-quickstart.md#configure-provider), step 1).
1. Prepare your infrastructure description files:

   {% list tabs group=infrastructure_description %}

   - Ready-made configuration {#ready}

     1. Clone the repository with configuration files.

        ```bash
        git clone https://github.com/yandex-cloud-examples/yc-website-high-availability-with-alb.git
        ```

     1. Navigate to the repository directory. Make sure it contains the following files:
        * `application-load-balancer-website.tf`: New infrastructure configuration.
        * `application-load-balancer-website.auto.tfvars`: User data file.

   - Manually {#manual}

     1. Create a configuration file folder.
     1. In this folder, create:
        1. `application-load-balancer-website.tf` configuration file:

           {% cut "application-load-balancer-website.tf" %}

           ```hcl
           # Declaring variables for confidential parameters
           
           variable "folder_id" {
             type = string
           }
           
           variable "vm_user" {
             type = string
           }
           
           variable "ssh_key_path" {
             type      = string
             sensitive = true
           }
           
           variable "domain" {
             type      = string
           }
           
           # Adding other variables
           
           locals {
             sa_name      = "ig-sa"
             network_name = "network1"
             subnet_name1 = "subnet-1"
             subnet_name2 = "subnet-2"
             subnet_name3 = "subnet-3"
           }
           
           # Configuring a provider
           
           terraform {
             required_providers {
               yandex = {
                 source  = "yandex-cloud/yandex"
                 version = ">= 0.47.0"
               }
             }
           }
           
           provider "yandex" {
             zone = "ru-central1-a"
           }
           
           # Creating a service account and assigning permissions
           
           resource "yandex_iam_service_account" "ig-sa" {
             name = local.sa_name
           }
           
           resource "yandex_resourcemanager_folder_iam_member" "editor" {
             folder_id = var.folder_id
             role      = "editor"
             member    = "serviceAccount:${yandex_iam_service_account.ig-sa.id}"
           }
           
           # Creating a cloud network and subnets
           
           resource "yandex_vpc_network" "network-1" {
             name = local.network_name
           }
           
           resource "yandex_vpc_subnet" "subnet-1" {
             name           = local.subnet_name1
             zone           = "ru-central1-a"
             network_id     = yandex_vpc_network.network-1.id
             v4_cidr_blocks = ["192.168.1.0/24"]
           }
           
           resource "yandex_vpc_subnet" "subnet-2" {
             name           = local.subnet_name2
             zone           = "ru-central1-b"
             network_id     = yandex_vpc_network.network-1.id
             v4_cidr_blocks = ["192.168.2.0/24"]
           }
           
           resource "yandex_vpc_subnet" "subnet-3" {
             name           = local.subnet_name3
             zone           = "ru-central1-d"
             network_id     = yandex_vpc_network.network-1.id
             v4_cidr_blocks = ["192.168.3.0/24"]
           }
           
           # Create security groups
           
           resource "yandex_vpc_security_group" "alb-sg" {
             name        = "alb-sg"
             network_id  = yandex_vpc_network.network-1.id
           
             egress {
               protocol       = "ANY"
               description    = "any"
               v4_cidr_blocks = ["0.0.0.0/0"]
               from_port      = 1
               to_port        = 65535
             }
           
             ingress {
               protocol       = "TCP"
               description    = "ext-http"
               v4_cidr_blocks = ["0.0.0.0/0"]
               port           = 80
             }
           
             ingress {
               protocol       = "TCP"
               description    = "ext-https"
               v4_cidr_blocks = ["0.0.0.0/0"]
               port           = 443
             }
           
             ingress {
               protocol          = "TCP"
               description       = "healthchecks"
               predefined_target = "loadbalancer_healthchecks"
               port              = 30080
             }
           }
           
           resource "yandex_vpc_security_group" "alb-vm-sg" {
             name        = "alb-vm-sg"
             network_id  = yandex_vpc_network.network-1.id
           
             ingress {
               protocol          = "TCP"
               description       = "balancer"
               security_group_id = yandex_vpc_security_group.alb-sg.id
               port              = 80
             }
           
             ingress {
               protocol       = "TCP"
               description    = "ssh"
               v4_cidr_blocks = ["0.0.0.0/0"]
               port           = 22
             }
           }
           
           # Creating an instance group for a website
           
           resource "yandex_compute_image" "lemp" {
             source_family = "lemp"
           }
           
           resource "yandex_compute_instance_group" "alb-vm-group" {
             name               = "alb-vm-group"
             folder_id          = var.folder_id
             service_account_id = yandex_iam_service_account.ig-sa.id
             instance_template {
               platform_id        = "standard-v2"
               service_account_id = yandex_iam_service_account.ig-sa.id
               resources {
                 core_fraction = 5
                 memory        = 1
                 cores         = 2
               }
           
               boot_disk {
                 mode = "READ_WRITE"
                 initialize_params {
                   image_id = yandex_compute_image.lemp.id
                   type     = "network-hdd"
                   size     = 3
                 }
               }
           
               network_interface {
                 network_id         = yandex_vpc_network.network-1.id
                 subnet_ids         = [yandex_vpc_subnet.subnet-1.id,yandex_vpc_subnet.subnet-2.id,yandex_vpc_subnet.subnet-3.id]
                 nat                = true
                 security_group_ids = [yandex_vpc_security_group.alb-vm-sg.id]
               }
           
               metadata = {
                 user-data = "#cloud-config\nusers:\n  - name: ${var.vm_user}\n    groups: sudo\n    shell: /bin/bash\n    sudo: ['ALL=(ALL) NOPASSWD:ALL']\n    ssh_authorized_keys:\n      - ${file("${var.ssh_key_path}")}"
               }
             }
           
             scale_policy {
               fixed_scale {
                 size = 3
               }
             }
           
             allocation_policy {
               zones = ["ru-central1-a", "ru-central1-b", "ru-central1-d"]
             }
           
             deploy_policy {
               max_unavailable = 1
               max_expansion   = 0
             }
           
             application_load_balancer {
               target_group_name = "alb-tg"
             }
           }
           
           # Creating a backend group
           
           resource "yandex_alb_backend_group" "alb-bg" {
             name                     = "alb-bg"
             http_backend {
               name                   = "backend-1"
               port                   = 80
               target_group_ids       = [yandex_compute_instance_group.alb-vm-group.application_load_balancer.0.target_group_id]
               healthcheck {
                 timeout              = "10s"
                 interval             = "2s"
                 healthcheck_port     = 80
                 http_healthcheck {
                   path               = "/"
                 }
               }
             }
           }
           
           # Creating an HTTP router and a virtual host
           
           resource "yandex_alb_http_router" "alb-router" {
             name   = "alb-router"
           }
           
           resource "yandex_alb_virtual_host" "alb-host" {
             name           = "alb-host"
             http_router_id = yandex_alb_http_router.alb-router.id
             authority      = [var.domain, "www.${var.domain}"]
             route {
               name = "route-1"
               http_route {
                 http_route_action {
                   backend_group_id = yandex_alb_backend_group.alb-bg.id
                 }
               }
             }
           }
           
           # Creating an L7 load balancer
           
           resource "yandex_alb_load_balancer" "alb-1" {
             name               = "alb-1"
             network_id         = yandex_vpc_network.network-1.id
             security_group_ids = [yandex_vpc_security_group.alb-sg.id]
           
             allocation_policy {
               location {
                 zone_id   = "ru-central1-a"
                 subnet_id = yandex_vpc_subnet.subnet-1.id
               }
           
               location {
                 zone_id   = "ru-central1-b"
                 subnet_id = yandex_vpc_subnet.subnet-2.id
               }
           
               location {
                 zone_id   = "ru-central1-d"
                 subnet_id = yandex_vpc_subnet.subnet-3.id
               }
             }
           
             listener {
               name = "alb-listener"
               endpoint {
                 address {
                   external_ipv4_address {
                   }
                 }
                 ports = [ 80 ]
               }
               http {
                 handler {
                   http_router_id = yandex_alb_http_router.alb-router.id
                 }
               }
             }
           }
           
           # Creating a DNS zone
           
           resource "yandex_dns_zone" "alb-zone" {
             name        = "alb-zone"
             description = "Public zone"
             zone        = "${var.domain}."
             public      = true
           }
           
           # Create resource records in a DNS zone
           
           resource "yandex_dns_recordset" "rs-1" {
             zone_id = yandex_dns_zone.alb-zone.id
             name    = "${var.domain}."
             ttl     = 600
             type    = "A"
             data    = [yandex_alb_load_balancer.alb-1.listener[0].endpoint[0].address[0].external_ipv4_address[0].address]
           }
           
           resource "yandex_dns_recordset" "rs-2" {
             zone_id = yandex_dns_zone.alb-zone.id
             name    = "www"
             ttl     = 600
             type    = "CNAME"
             data    = [ var.domain ]
           }
           ```

           {% endcut %}

        1. `application-load-balancer-website.auto.tfvars` user data file:

           {% cut "application-load-balancer-website.auto.tfvars" %}

           ```hcl
           folder_id    = "<folder_ID>"
           vm_user      = "<VM_user_name>"
           ssh_key_path = "<path_to_public_SSH_key>"
           domain       = "<domain>"
           ```

           {% endcut %}

   {% endlist %}

   For more information about the properties of Terraform resources, see the relevant Terraform guides:
   * [Service account](../../../iam/concepts/users/service-accounts.md): [yandex_iam_service_account](../../../terraform/resources/iam_service_account.md).
   * [Role](../../../iam/concepts/access-control/roles.md): [yandex_resourcemanager_folder_iam_member](../../../terraform/resources/resourcemanager_folder_iam_member.md).
   * [Network](../../../vpc/concepts/network.md#network): [yandex_vpc_network](../../../terraform/resources/vpc_network.md).
   * [Subnets](../../../vpc/concepts/network.md#subnet): [yandex_vpc_subnet](../../../terraform/resources/vpc_subnet.md).
   * [Security groups](../../../vpc/concepts/security-groups.md): [yandex_vpc_security_group](../../../terraform/resources/vpc_security_group.md).
   * [VM image](../../../compute/concepts/image.md): [yandex_compute_image](../../../terraform/resources/compute_image.md).
   * [Instance group](../../../compute/concepts/instance-groups/index.md): [yandex_compute_instance_group](../../../terraform/resources/compute_instance_group.md).
   * [Backend group](../../concepts/backend-group.md): [yandex_alb_backend_group](../../../terraform/resources/alb_backend_group.md).
   * [HTTP router](../../concepts/http-router.md): [yandex_alb_http_router](../../../terraform/resources/alb_http_router.md).
   * [Virtual host](../../concepts/http-router.md#virtual-host): [yandex_alb_virtual_host](../../../terraform/resources/alb_virtual_host.md).
   * [L7 load balancer](../../concepts/application-load-balancer.md): [yandex_alb_load_balancer](../../../terraform/resources/alb_load_balancer.md).
   * [DNS zone](../../../dns/concepts/dns-zone.md): [yandex_dns_zone](../../../terraform/resources/dns_zone.md).
   * [DNS resource record](../../../dns/concepts/resource-record.md): [yandex_dns_recordset](../../../terraform/resources/dns_recordset.md).

1. In the `application-load-balancer-website.auto.tfvars` file, set the following user-defined properties:
    * `folder_id`: [Folder ID](../../../resource-manager/operations/folder/get-id.md).
    * `vm_user`: VM user name.
    * `ssh_key_path`: Path to the public SSH key to authenticate the user on the VM. For more information, see [Creating an SSH key pair](../../../compute/operations/vm-connect/ssh.md#creating-ssh-keys).
    * `domain`: Domain name, e.g., `alb-example.com`.

1. Create the resources:

   1. In the terminal, navigate to the configuration file directory.
   1. Make sure the configuration is correct using this command:
   
      ```bash
      terraform validate
      ```
   
      If the configuration is valid, you will get this message:
   
      ```bash
      Success! The configuration is valid.
      ```
   
   1. Run this command:
   
      ```bash
      terraform plan
      ```
   
      You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
   1. Apply the configuration changes:
   
      ```bash
      terraform apply
      ```
   
   1. Type `yes` and press **Enter** to confirm the changes.

After creating the infrastructure, [upload the website files](#upload-files).

## Upload the website files {#upload-files}

To test the web server, upload the website files to each VM. You can use the `index.html` file from [this archive](https://storage.yandexcloud.net/doc-files/index.html.zip) as an example.

For each VM in the [created group](#create-vms), do the following:
1. On the **Virtual machines** tab, click the VM name in the list.
1. Copy **Public IPv4 address** from the **Network** section.
1. [Connect](../../../compute/operations/vm-connect/ssh.md#vm-connect) to the VM over SSH.
1. Grant your user write permissions for the `/var/www/html` directory:

   ```bash
   sudo chown -R "$USER":www-data /var/www/html
   ```

1. Upload the website files to the VM via [SCP](https://en.wikipedia.org/wiki/Secure_copy_protocol).

   {% list tabs group=operating_system %}

   - Linux/macOS {#linux-macos}

     Use the `scp` command line utility:

     ```bash
     scp -r <path_to_directory_with_files> <VM_user_name>@<VM_IP_address>:/var/www/html
     ```

   - Windows {#windows}

     Use [WinSCP](https://winscp.net/eng/download.php) to copy the local file directory to `/var/www/html` on the VM.

   {% endlist %}

## Test the fault tolerance {#test-ha}

1. Open the [management console](https://console.yandex.cloud).
1. Navigate to **Compute Cloud**.
1. Navigate to the page of the VM from the previously created group.
1. Copy **Public IPv4 address** from the **Network** section.
1. [Connect](../../../compute/operations/vm-connect/ssh.md#vm-connect) to the VM over SSH.
1. Stop the web service to simulate a failure on the web server:

   ```bash
   sudo service nginx stop
   ```

1. Open your website in a browser. The website should open, even though one of the web servers has failed.
1. After the check is complete, restart the web service:

   ```bash
   sudo service nginx start
   ```

## How to delete the resources you created {#clear-out}

To stop paying for the resources you created:

1. Open the `application-load-balancer-website.tf` configuration file and delete the description of the new infrastructure from it.
1. Apply the changes:

    1. In the terminal, navigate to the configuration file directory.
    1. Make sure the configuration is correct using this command:
    
       ```bash
       terraform validate
       ```
    
       If the configuration is valid, you will get this message:
    
       ```bash
       Success! The configuration is valid.
       ```
    
    1. Run this command:
    
       ```bash
       terraform plan
       ```
    
       You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
    1. Apply the configuration changes:
    
       ```bash
       terraform apply
       ```
    
    1. Type `yes` and press **Enter** to confirm the changes.

#### Useful links {#see-also}

* [Fault-tolerant website with load balancing via Yandex Application Load Balancer using the management console](console.md)