[Yandex Cloud documentation](../../../index.md) > [Yandex Application Load Balancer](../../index.md) > [Tutorials](../index.md) > [Integrating an L7 load balancer with a CDN and Object Storage](index.md) > Terraform

# Integrating an L7 load balancer with Cloud CDN and Object Storage using Terraform


{% note info %}

To implement this solution, you will need a domain. We will use the `example.com` domain name as an example.

{% endnote %}

To create an infrastructure to [integrate](index.md) an L7 load balancer with Yandex Cloud CDN and Yandex Object Storage using [Terraform](../../../terraform/index.md):

1. [Get your cloud ready](#before-you-begin).
1. [Deploy the infrastructure for integration of an L7 load balancer with Cloud CDN and Object Storage](#deploy).
1. [Test the solution](#test).

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

## Get your cloud ready {#before-you-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 costs include:

* Fee for data storage in Object Storage, data operations, and outbound traffic (see [Object Storage pricing](../../../storage/pricing.md)).
* Fee for using the L7 load balancer’s computing resources (see [Application Load Balancer pricing](../../pricing.md)).
* A fee for outgoing traffic from CDN servers (see [Cloud CDN pricing](../../../cdn/pricing.md)).
* Fee for public DNS requests and DNS zones if using Yandex Cloud DNS (see [Cloud DNS pricing](../../../dns/pricing.md)).

## Deploying the infrastructure for integration of an L7 load balancer with Cloud CDN and Object Storage {#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 relevant documentation on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../../terraform/index.md).

To create your infrastructure via Terraform:
1. [Install Terraform](../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform), [obtain authentication credentials](../../../tutorials/infrastructure-management/terraform-quickstart.md#get-credentials), and specify the source for installing the Yandex Cloud provider. For details, see [Configure your provider](../../../tutorials/infrastructure-management/terraform-quickstart.md#configure-provider), step 1.
1. Set up your infrastructure description files:

    {% list tabs group=infrastructure_description %}

    - Ready-made configuration {#ready}

      1. Clone the repository containing the configuration files:

         ```bash
         git clone https://github.com/yandex-cloud-examples/cdn-storage-integration-config
         ```

      1. Navigate to the repository directory. It should now contain the following files:
          * `cdn-storage-integration-config.tf`: New infrastructure configuration file.
          * `cdn-storage-integration.auto.tfvars`: File with the values of user-defined variables.
          * `index.html`: Test file of your service, used to health-check the solution.

    - Manually {#manual}

      1. Create a folder for configuration files. In this folder:

          1. Create a file named `index.html` with the following contents:
             
             ```html
             <!DOCTYPE html>
             <html>
               <head>
                 <title>My service</title>
               </head>
               <body>
                 <p>The service is working</p>
               </body>
             </html>
             ```
          1. Create a configuration file named `cdn-storage-integration-config.tf`:

              {% cut "**cdn-storage-integration-config.tf**" %}

              ```hcl
              # Declaring variables
              
              variable "folder_id" {
                type = string
              }
              
              variable "domain_name" {
                type = string
              }
              
              variable "bucket_name" {
                type = string
              }
              
              variable "index_file_path" {
                type = string
              }
              
              locals {
                network_name     = "example-network"
                subneta_name     = "example-subnet-ru-central1-a"
                subnetb_name     = "example-subnet-ru-central1-b"
                subnetd_name     = "example-subnet-ru-central1-d"
                sg_name          = "example-sg"
                object_key       = "index.html"
                domain_zone_name = "my-domain-zone"
                cert_name        = "mymanagedcert"
                origin_gp_name   = "example-origin-group"
                bg_name          = "example-bg"
                backend_name     = "example-backend"
                router_name      = "example-router"
                vh_name          = "example-vh"
                route_name       = "example-route"   
                alb_name         = "example-balancer"
                listener_name    = "example-listener"
              }
              
              # Configuring the provider
              
              terraform {
                required_providers {
                  yandex = {
                    source = "yandex-cloud/yandex"
                  }
                }
                required_version = ">= 0.13"
              }
              
              provider "yandex" {
                folder_id = var.folder_id
              }
              
              # Creating a public DNS zone
              
              resource "yandex_dns_zone" "my-domain-zone" {
                name    = local.domain_zone_name
                zone    = "${var.domain_name}."
                public  = true
              }
              
              # Adding a Let's Encrypt certificate
              
              resource "yandex_cm_certificate" "le-certificate" {
                name    = local.cert_name
                domains = [var.domain_name]
              
                managed {
                challenge_type = "DNS_CNAME"
                challenge_count = 1
                }
              }
              
              # Creating a CNAME record for domain validation when issuing a certificate
              
              resource "yandex_dns_recordset" "validation-record" {
                count   = yandex_cm_certificate.le-certificate.managed[0].challenge_count
                zone_id = yandex_dns_zone.my-domain-zone.id
                name    = yandex_cm_certificate.le-certificate.challenges[count.index].dns_name
                type    = yandex_cm_certificate.le-certificate.challenges[count.index].dns_type
                ttl     = 600
                data    = [yandex_cm_certificate.le-certificate.challenges[count.index].dns_value]
              }
              
              # Waiting for domain validation and the issue of a Let's Encrypt certificate
              
              data "yandex_cm_certificate" "example-com" {
                depends_on      = [yandex_dns_recordset.validation-record]
                certificate_id  = yandex_cm_certificate.le-certificate.id
                wait_validation = true
              }
              
              # Creating a network
              
              resource "yandex_vpc_network" "my-network" {
                name = local.network_name
              }
              
              # Creating subnets
              
              resource "yandex_vpc_subnet" "my-subnet-a" {
                name           = local.subneta_name
                zone           = "ru-central1-a"
                network_id     = yandex_vpc_network.my-network.id
                v4_cidr_blocks = ["192.168.1.0/24"]
              }
              
              resource "yandex_vpc_subnet" "my-subnet-b" {
                name           = local.subnetb_name
                zone           = "ru-central1-b"
                network_id     = yandex_vpc_network.my-network.id
                v4_cidr_blocks = ["192.168.2.0/24"]
              }
              
              resource "yandex_vpc_subnet" "my-subnet-d" {
                name           = local.subnetd_name
                zone           = "ru-central1-d"
                network_id     = yandex_vpc_network.my-network.id
                v4_cidr_blocks = ["192.168.3.0/24"]
              }
              
              # Creating a security group
              
              resource "yandex_vpc_security_group" "my-sg" {
                name        = local.sg_name
                network_id  = yandex_vpc_network.my-network.id
              
                ingress {
                  protocol       = "TCP"
                  description    = "http"
                  v4_cidr_blocks = ["0.0.0.0/0"]
                  port           = 80
                }
              
                ingress {
                  protocol       = "TCP"
                  description    = "https"
                  v4_cidr_blocks = ["0.0.0.0/0"]
                  port           = 443
                }
              
                ingress {
                  protocol          = "TCP"
                  description       = "healthchecks"
                  predefined_target = "loadbalancer_healthchecks"
                  port              = 30080
                }
              
                egress {
                  protocol       = "ANY"
                  description    = "any"
                  v4_cidr_blocks = ["0.0.0.0/0"]
                  from_port      = 0
                  to_port        = 65535
                }
              }
              
              # Creating a bucket
              
              resource "yandex_storage_bucket" "cdn-source-bucket" {
                bucket      = var.bucket_name
                folder_id   = var.folder_id
              
                anonymous_access_flags {
                  read = true
                  list = true
                }
              }
              
              # Uploading the main page of the test service to the bucket
              
              resource "yandex_storage_object" "index-object" {
                bucket        = yandex_storage_bucket.cdn-source-bucket.bucket
                key           = local.object_key
                source        = var.index_file_path
                content_type  = "text/html"
              }
              
              # Creating a backend group
              
              resource "yandex_alb_backend_group" "test-backend-group" {
                name                     = local.bg_name
                http_backend {
                  name                   = local.backend_name
                  weight                 = 100
                  port                   = 80
                  storage_bucket         = var.bucket_name
                }
              }
              
              # Creating an HTTP router
              
              resource "yandex_alb_http_router" "my-router" {
                name          = local.router_name
              }
              
              # Creating a virtual host
              
              resource "yandex_alb_virtual_host" "my-virtual-host" {
                name           = local.vh_name
                http_router_id = yandex_alb_http_router.my-router.id
              
                route {
                  name = local.route_name
              
                  http_route {
                    http_match {
                      http_method = ["GET"]
                      path {
                        prefix = "/"
                      }
                    }
              
                    http_route_action {
                      backend_group_id = yandex_alb_backend_group.test-backend-group.id
                    }
                  }
                }
              
                authority = [var.domain_name]
              }
              
              # Creating an L7 load balancer
              
              resource "yandex_alb_load_balancer" "my-balancer" {
                name               = local.alb_name
                network_id         = yandex_vpc_network.my-network.id
                security_group_ids = [yandex_vpc_security_group.my-sg.id]
              
                allocation_policy {
                  location {
                    zone_id   = "ru-central1-a"
                    subnet_id = yandex_vpc_subnet.my-subnet-a.id
                  }
              
                  location {
                    zone_id   = "ru-central1-b"
                    subnet_id = yandex_vpc_subnet.my-subnet-b.id
                  }
              
                  location {
                    zone_id   = "ru-central1-d"
                    subnet_id = yandex_vpc_subnet.my-subnet-d.id
                  }
                }
              
                listener {
                  name = local.listener_name
                  endpoint {
                    address {
                      external_ipv4_address {
                      }
                    }
                    ports = [80]
                  }
                  http {
                    handler {
                      http_router_id = yandex_alb_http_router.my-router.id
                    }
                  }
                }
              }
              
              # Creating a CDN origin group
              
              resource "yandex_cdn_origin_group" "my-origin-group" {
                name = local.origin_gp_name
                origin {
                  source = yandex_alb_load_balancer.my-balancer.listener[0].endpoint[0].address[0].external_ipv4_address[0].address
                }
              }
              
              # Creating a CDN resource
              
              resource "yandex_cdn_resource" "my-resource" {
                cname               = var.domain_name
                active              = true
                origin_protocol     = "http"
                origin_group_id     = yandex_cdn_origin_group.my-origin-group.id
                ssl_certificate {
                  type = "certificate_manager"
                  certificate_manager_id = data.yandex_cm_certificate.example-com.id
                }
                options {
                  redirect_http_to_https = true
                  forward_host_header    = true
                }
              }
              
              # Creating a CNAME record for the CDN resource
              
              resource "yandex_dns_recordset" "cdn-cname" {
                zone_id = yandex_dns_zone.my-domain-zone.id
                name    = "${var.domain_name}."
                type    = "CNAME"
                ttl     = 600
                data    = [yandex_cdn_resource.my-resource.provider_cname]
              }
              ```

              {% endcut %}

          1. Create a file with user data named `cdn-storage-integration.auto.tfvars`:

              **cdn-storage-integration.auto.tfvars**

              ```hcl
              folder_id       = "<folder_ID>"
              bucket_name     = "<bucket_name>"
              domain_name     = "<domain_name>"
              index_file_path = "<local_filepath_to_index.html>"
              ```

    {% endlist %}

    For more information about Terraform resource properties, see the relevant provider guides:

    * [Network](../../../vpc/concepts/network.md#network): [yandex_vpc_network](../../../terraform/resources/vpc_network.md).
    * [Subnet](../../../vpc/concepts/network.md#subnet): [yandex_vpc_subnet](../../../terraform/resources/vpc_subnet.md).
    * [Security group](../../../vpc/concepts/security-groups.md): [yandex_vpc_security_group](../../../terraform/resources/vpc_security_group.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).
    * [TLS certificate](../../../certificate-manager/concepts/managed-certificate.md): [yandex_cm_certificate](../../../terraform/resources/cm_certificate.md).
    * [Bucket](../../../storage/concepts/bucket.md): [yandex_storage_bucket](../../../terraform/resources/storage_bucket.md).
    * [Object](../../../storage/concepts/object.md): [yandex_storage_object](../../../terraform/resources/storage_object.md).
    * [Origin group](../../../cdn/concepts/origins.md#groups): [yandex_cdn_origin_group](../../../terraform/resources/cdn_origin_group.md).
    * [CDN resource](../../../cdn/concepts/resource.md): [yandex_cdn_resource](../../../terraform/resources/cdn_resource.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).

1. In the `cdn-storage-integration.auto.tfvars` file, set the values of the user-defined variables:
    * `folder_id`: [Folder ID](../../../resource-manager/operations/folder/get-id.md).
    * `bucket_name`: Bucket name consistent with the [naming conventions](../../../storage/concepts/bucket.md#naming).
    * `domain_name`: Name of the domain to host the test service.

        To use domain names in the public DNS zone, you need to delegate it to authoritative name servers. Specify the addresses of the `ns1.yandexcloud.net` and `ns2.yandexcloud.net` servers in your account on your domain name registrar's website.
    * `index_file_path`: Local path to the `index.html` file that contains your test service contents. Here is an example: `/Users/MyUser/Repos/cdn-storage-integration/index.html`.

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.

This will create and configure all the required infrastructure in the folder you selected.

## Test the solution {#test}

To test the service, open `https://example.com/index.html` in your browser (with your domain name in place of `example.com`). If everything is configured correctly, you should see a page with the following content:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My service</title>
  </head>
  <body>
    <p>The service is working</p>
  </body>
</html>
```

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

{% note warning %}

Before deleting the infrastructure, [delete](../../../storage/operations/objects/delete.md) all objects in the created bucket.

{% endnote %}

To stop paying for the resources you created:

1. Open the `cdn-storage-integration-config.tf` file and delete your infrastructure description 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.

#### See also {#see-also}

* [Integrating an L7 load balancer with Cloud CDN and Object Storage using the management console](console.md)