# Terminating TLS connections using Terraform

To create the infrastructure for [terminating TLS connections](index.md) using Terraform:

1. [Get your cloud ready](#before-begin).
1. [Create your infrastructure](#deploy).
1. [Test the hosting](#test).

We will use the `my-site.com` domain name as an example.

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 cost of supporting the infrastructure for terminating TLS connections includes:
* Fee for continuously running [VMs](../../../compute/concepts/vm.md) (see [Yandex Compute Cloud pricing](../../../compute/pricing.md)).
* Fee for using a [public static IP address](../../../vpc/concepts/address.md#public-addresses) (see [Yandex Virtual Private Cloud pricing](../../../vpc/pricing.md)).
* Fee for using computing resources of the [L7 load balancer](../../../application-load-balancer/concepts/index.md) (see [Application Load Balancer pricing](../../../application-load-balancer/pricing.md)).
* Fee for public DNS queries and [DNS zones](../../concepts/dns-zone.md) if using [Yandex Cloud DNS](../../index.md) (see [Cloud DNS pricing](../../pricing.md)).

## Create your 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 relevant documentation on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../../terraform/index.md).

To create an infrastructure 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-alb-tls-termination.git
        ```

     1. Go to the directory with the repository. Make sure it contains the following files:
        * `tls-termination-config.tf`: New infrastructure configuration.
        * `tls-terminationg.auto.tfvars`: User data file.

   - Manually {#manual}

     1. Create a folder for configuration files.
     1. In this folder, create:
        1. `tls-termination-config.tf` configuration file:

           {% cut "tls-termination-config.tf" %}

           ```hcl
           # Declaring variables with sensitive data
           
           variable "folder_id" {
             type = string
           }
           
           variable "vm_user" {
             type = string
           }
           
           variable "ssh_key_path" {
             type = string
           }
           
           variable "domain" {
             type = string
           }
           
           variable "certificate" {
             type = string
           }
           
           variable "private_key" {
             type = string
           }
           
           # Adding other variables
           
           locals {
             sa_name          = "ig-sa"
             network_name     = "network-1"
             subnet_name_a    = "subnet-a"
             subnet_name_b    = "subnet-b"
             sg_name_balancer = "sg-balancer"
             sg_name_vms      = "sg-vms"
             cert_name        = "imported-cert"
             site_ig_name     = "site-ig"
             alb_bg_name      = "alb-bg"
             alb_host_name    = "alb-host"
             alb_router_name  = "alb-router"
             alb_name         = "alb"
             alb_zone_name    = "alb-zone"
           }
           
           # Configuring the provider
           
           terraform {
             required_providers {
               yandex = {
                 source  = "yandex-cloud/yandex"
                 version = ">= 0.47.0"
               }
             }
           }
           
           provider "yandex" {
             folder_id = var.folder_id
           }
           
           # Creating a service account for an instance group
           
           resource "yandex_iam_service_account" "ig-sa" {
             name        = local.sa_name
             description = "service account to manage IG"
           }
           
           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
           
           resource "yandex_vpc_network" "network-1" {
             name = local.network_name
           }
           
           resource "yandex_vpc_subnet" "subnet-a" {
             name           = local.subnet_name_a
             zone           = "ru-central1-a"
             v4_cidr_blocks = ["192.168.1.0/24"]
             network_id     = yandex_vpc_network.network-1.id
           }
           
           resource "yandex_vpc_subnet" "subnet-b" {
             name           = local.subnet_name_b
             zone           = "ru-central1-b"
             v4_cidr_blocks = ["192.168.2.0/24"]
             network_id     = yandex_vpc_network.network-1.id
           }
           
           # Creating a static public IP address
           
           resource "yandex_vpc_address" "stat_address" {
             name = "alb-static-address"
             external_ipv4_address {
               zone_id = "ru-central1-a"
             }
           }
           
           # Creating security groups
           
           resource "yandex_vpc_security_group" "sg-balancer" {
             name        = local.sg_name_balancer
             network_id  = yandex_vpc_network.network-1.id
           
             egress {
               protocol       = "ANY"
               description    = "any"
               v4_cidr_blocks = ["0.0.0.0/0"]
               from_port = 0
               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" "sg-vms" {
             name        = local.sg_name_vms
             network_id  = yandex_vpc_network.network-1.id
           
             ingress {
               protocol          = "TCP"
               description       = "balancer"
               security_group_id = yandex_vpc_security_group.sg-balancer.id
               port              = 80
               }
           
             ingress {
               protocol       = "TCP"
               description    = "ssh"
               v4_cidr_blocks = ["0.0.0.0/0"]
               port           = 22
             }
           }
           
           # Importing the website’s TLS certificate
           
           resource "yandex_cm_certificate" "imported-cert" {
             name    = local.cert_name
           
             self_managed {
               certificate = "${file("${var.certificate}")}"
               private_key = "${file("${var.private_key}")}"
             }
           }
           
           # Creating an instance group for a website
           
           resource "yandex_compute_image" "lemp-image" {
             source_family = "lemp"
           }
           
           resource "yandex_compute_instance_group" "site-ig" {
             name                = local.site_ig_name
             folder_id           = var.folder_id
             service_account_id  = "${yandex_iam_service_account.ig-sa.id}"
             instance_template {
               platform_id = "standard-v2"
               resources {
                 memory        = 1
                 cores         = 2
                 core_fraction = 5
               }
           
               boot_disk {
                 mode = "READ_WRITE"
                 initialize_params {
                   image_id = yandex_compute_image.lemp-image.id
                 }
               }
           
               network_interface {
                 network_id         = yandex_vpc_network.network-1.id
                 subnet_ids         = [yandex_vpc_subnet.subnet-a.id,yandex_vpc_subnet.subnet-b.id]
                 security_group_ids = [yandex_vpc_security_group.sg-vms.id]
                 nat                = true
               }
           
               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 = 2
               }
             }
           
             allocation_policy {
               zones = ["ru-central1-a","ru-central1-b"]
             }
           
             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                     = local.alb_bg_name
           
             http_backend {
               name                   = "alb-backend"
               weight                 = 1
               port                   = 80
               target_group_ids       = [yandex_compute_instance_group.site-ig.application_load_balancer[0].target_group_id]
               healthcheck {
                 timeout              = "10s"
                 interval             = "2s"
                 healthcheck_port     = 80
                 http_healthcheck {
                   path               = "/"
                 }
               }
             }
           }
           
           # Creating an HTTP router
           
           resource "yandex_alb_http_router" "alb-router" {
             name          = local.alb_router_name
           }
           
           resource "yandex_alb_virtual_host" "alb-host" {
             name                    = local.alb_host_name
             authority               = ["${var.domain}"]
             http_router_id          = yandex_alb_http_router.alb-router.id
             route {
               name                  = "alb-route"
               http_route {
                 http_route_action {
                   backend_group_id  = yandex_alb_backend_group.alb-bg.id
                   timeout           = "60s"
                 }
               }
             }
           }    
           
           # Creating an L7 load balancer
           
           resource "yandex_alb_load_balancer" "alb" {
             name        = local.alb_name
             network_id  = yandex_vpc_network.network-1.id
             security_group_ids = [yandex_vpc_security_group.sg-balancer.id]
           
             allocation_policy {
               location {
                 zone_id   = "ru-central1-a"
                 subnet_id = yandex_vpc_subnet.subnet-a.id
               }
               location {
                 zone_id   = "ru-central1-b"
                 subnet_id = yandex_vpc_subnet.subnet-b.id
               }
             }
           
             listener {
               name = "list-http"
               endpoint {
                 address {
                   external_ipv4_address {
                     address = yandex_vpc_address.stat_address.external_ipv4_address[0].address
                   }
                 }
               ports = [ 80 ]
               }
               http {
                 redirects {
                   http_to_https = true
                 }
               }
             }
           
             listener {
               name = "listener-http"
               endpoint {
                 address {
                   external_ipv4_address {
                     address = yandex_vpc_address.stat_address.external_ipv4_address[0].address
                   }
                 }
                 ports = [ 443 ]
               }
               tls {
                 default_handler {
                   http_handler {
                     http_router_id = yandex_alb_http_router.alb-router.id
                   }
                   certificate_ids = [yandex_cm_certificate.imported-cert.id]
                 }
                 sni_handler {
                   name         = "mysite-sni"
                   server_names = ["${var.domain}"]
                   handler {
                     http_handler {
                       http_router_id = yandex_alb_http_router.alb-router.id
                     }
                     certificate_ids = [yandex_cm_certificate.imported-cert.id]
                   }
                 }
               }
             }
           }
           
           # Creating a DNS zone
           
           resource "yandex_dns_zone" "alb-zone" {
             name        = local.alb_zone_name
             description = "Public zone"
             zone        = "${var.domain}."
             public      = true
           }
           
           # Creating a DNS zone resource record
           
           resource "yandex_dns_recordset" "alb-record" {
             zone_id = yandex_dns_zone.alb-zone.id
             name    = "${var.domain}."
             ttl     = 600
             type    = "A"
             data    = [yandex_alb_load_balancer.alb.listener[0].endpoint[0].address[0].external_ipv4_address[0].address]
             # description: Resource record description. This is an optional parameter.
           }
           ```

           {% endcut %}

        1. `tls-termination.auto.tfvars` user data file:

           {% cut "tls-termination.auto.tfvars" %}

           ```hcl
           folder_id    = "<folder_ID>"
           vm_user      = "<VM_user_name>"
           ssh_key_path = "<path_to_public_SSH_key>"
           domain       = "<domain>"
           certificate  = "<certificate_file_path>"
           private_key  = "<private_key_file_path>"
           ```

           {% endcut %}

   {% endlist %}

   Learn more about the properties of Terraform resources in the relevant Terraform guides:
   * [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).
   * [Static public IP address](../../../vpc/concepts/address.md#public-addresses): [yandex_vpc_address](../../../terraform/resources/vpc_address.md).
   * [Security groups](../../../vpc/concepts/security-groups.md): [yandex_vpc_security_group](../../../terraform/resources/vpc_security_group.md).
   * [TLS certificate](../../../certificate-manager/concepts/imported-certificate.md): [yandex_cm_certificate](../../../terraform/resources/cm_certificate.md).
   * [VM image](../../../compute/concepts/image.md): [yandex_compute_image](../../../terraform/resources/compute_image.md).
   * [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).
   * [Instance group](../../../compute/concepts/instance-groups/index.md): [yandex_compute_instance_group](../../../terraform/resources/compute_instance_group.md).
   * [Backend group](../../../application-load-balancer/concepts/backend-group.md): [yandex_alb_backend_group](../../../terraform/resources/alb_backend_group.md).
   * [HTTP router](../../../application-load-balancer/concepts/http-router.md): [yandex_alb_http_router](../../../terraform/resources/alb_http_router.md).
   * [Virtual host](../../../application-load-balancer/concepts/http-router.md#virtual-host): [yandex_alb_virtual_host](../../../terraform/resources/alb_virtual_host.md).
   * [L7 load balancer](../../../application-load-balancer/concepts/application-load-balancer.md): [yandex_alb_load_balancer](../../../terraform/resources/alb_load_balancer.md).
   * [DNS zone](../../concepts/dns-zone.md): [yandex_dns_zone](../../../terraform/resources/dns_zone.md).
   * [DNS resource record](../../concepts/resource-record.md): [yandex_dns_recordset](../../../terraform/resources/dns_recordset.md).

1. In the `tls-termination.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 file with the public SSH key. For more information, see [Creating an SSH key pair](../../../compute/operations/vm-connect/ssh.md#creating-ssh-keys).
   * `domain`: Domain to host the website. 
       To get access to public zone domain names, you need to delegate the domain. Specify the addresses of the `ns1.yandexcloud.net` and `ns2.yandexcloud.net` servers in your account on your registrar's website.
   * `certificate`: Path to the file with the [user certificate](../../../certificate-manager/operations/import/cert-create.md#create-file).
   * `private_key`: Path to the file with the user certificate's private key.
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.

1. [Get the public IP addresses](../../../compute/operations/instance-groups/get-info.md): you will need them later to [test the hosting](#test).

After creating the infrastructure, [test the hosting](#test).

## Test the hosting {#test}

To test the hosting:

1. Create the website home page, i.e., the `index.html` file.

   {% cut "Example of the index.html file" %}

   ```html
   <!DOCTYPE html>
   <html>
     <head>
       <title>My site</title>
     </head>
     <body>
       <h1>This is my site</h1>
     </body>
   </html>
   ```

   {% endcut %}

1. Upload the `index.html` file to each VM:

   1. On the VM page of the [management console](https://console.yandex.cloud), under **Network**, find the VM's public IP address.
   1. [Connect](../../../compute/operations/vm-connect/ssh.md) to the VM over SSH.
   1. Grant your user write permissions for the `/var/www/html` directory:
   
      {% list tabs group=operating_system %}
   
      - Ubuntu {#ubuntu}
   
        ```bash
        sudo chown -R "$USER":www-data /var/www/html
        ```
   
      - CentOS {#centos}
   
        ```bash
        sudo chown -R "$USER":apache /var/www/html
        ```
   
      {% endlist %}
   
   
   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 %}

1. Open the website at `http://my-site.com` in your browser. A redirect to `https://my-site.com` should occur with the TLS certificate from Certificate Manager already enabled.

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

To stop paying for the resources you created:

1. Open the `tls-termination-config.tf` configuration 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}

* [Terminating TLS connections using the management console](console.md)