# Assigning a domain name to a web server VM with Terraform

To create an infrastructure for [assigning a domain name to a web server VM](index.md) using Terraform:

1. [Get your cloud ready](#before-begin).
1. [Delegate your domain to Cloud DNS](#delegate-domain). 
1. [Create an infrastructure](#deploy).
1. [Test the website](#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 support cost includes:

* Fee for using a [public IP address](../../../vpc/concepts/address.md#public-addresses) (see [Yandex Virtual Private Cloud pricing](../../../vpc/pricing.md)).
* Fee for [VM](../../../compute/concepts/vm.md) computing resources and disks (see [Yandex Compute Cloud pricing](../../../compute/pricing.md)).
* Fee for using a public [DNS zone](../../concepts/dns-zone.md) and public DNS requests (see [Yandex Cloud DNS pricing](../../pricing.md)).

## Delegate your domain to Cloud DNS {#delegate-domain}

To delegate a domain to Cloud DNS, in your account on your domain registrar's website, specify the DNS server addresses in the domain settings:

* `ns1.yandexcloud.net`
* `ns2.yandexcloud.net`

Delegation does not take effect immediately. Internet provider servers normally update records within 24 hours (86,400 seconds). This depends on the TTL value which specifies how long domain records are cached.

You can check domain delegation using [Whois](https://www.reg.com/whois/check_site) or the `dig` utility:

```bash
dig +short NS example.com
```

Result:

```
ns2.yandexcloud.net.
ns1.yandexcloud.net.
```

## 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 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 the infrastructure description file:

    {% 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-compute-dns-binding
          ```

      1. Navigate to the repository directory. Make sure it contains the following files:
          * `bind-domain-to-vm.tf`: Your infrastructure configuration.
          * `bind-domain-to-vm.auto.tfvars`: User data file.

    - Manually {#manual}

      1. Create a folder for the infrastructure description file.
      1. In the folder, create:
          1. `bind-domain-to-vm.tf` configuration file:

              {% cut "bind-domain-to-vm.tf" %}

              ```hcl
              # Declaring variables for custom parameters
              
              variable "folder_id" {
                type = string
              }
              
              variable "domain_name" {
                type = string
              }
              
              variable "ssh_key_path" {
                type = string
              }
              
              # Adding other variables
              
              locals {
                zone             = "ru-central1-a"
                network_name     = "webserver-network"
                subnet_name      = "webserver-subnet-ru-central1-a"
                sg_name          = "webserver-sg"
                vm_name          = "mywebserver"
                domain_zone_name = "my-domain-zone"
              }
              
              # Configuring the provider
              
              terraform {
                required_providers {
                  yandex = {
                    source  = "yandex-cloud/yandex"
                    version = ">= 0.47.0"
                  }
                }
              }
              
              provider "yandex" {
                zone      = local.zone
                folder_id = var.folder_id
              }
              
              # Creating a cloud network
              
              resource "yandex_vpc_network" "webserver-network" {
                name = local.network_name
              }
              
              # Creating a subnet
              
              resource "yandex_vpc_subnet" "webserver-subnet-b" {
                name           = local.subnet_name
                zone           = local.zone
                network_id     = "${yandex_vpc_network.webserver-network.id}"
                v4_cidr_blocks = ["192.168.1.0/24"]
              }
              
              # Creating a security group
              
              resource "yandex_vpc_security_group" "webserver-sg" {
                name        = local.sg_name
                network_id  = "${yandex_vpc_network.webserver-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    = "ssh"
                  v4_cidr_blocks = ["0.0.0.0/0"]
                  port           = 22
                }
              
                egress {
                  protocol       = "ANY"
                  description    = "any"
                  v4_cidr_blocks = ["0.0.0.0/0"]
                  from_port      = 0
                  to_port        = 65535
                }
              }
              
              # Creating an image
              
              resource "yandex_compute_image" "osimage" {
                source_family = "lamp"
              }
              
              # Creating a disk
              
              resource "yandex_compute_disk" "boot-disk" {
                name     = "web-server-boot"
                type     = "network-hdd"
                image_id = yandex_compute_image.osimage.id
              }
              
              # Creating a VM
              
              resource "yandex_compute_instance" "mywebserver" {
                name        = local.vm_name
                platform_id = "standard-v2"
                zone        = local.zone
              
                resources {
                  cores  = "2"
                  memory = "2"
                }
              
                boot_disk {
                  disk_id = yandex_compute_disk.boot-disk.id
                }
              
                network_interface {
                  subnet_id          = "${yandex_vpc_subnet.webserver-subnet-b.id}"
                  nat                = true
                  security_group_ids = ["${yandex_vpc_security_group.webserver-sg.id}"]
                }
              
                metadata = {
                  user-data = "#cloud-config\nusers:\n  - name: yc-user\n    groups: sudo\n    shell: /bin/bash\n    sudo: 'ALL=(ALL) NOPASSWD:ALL'\n    ssh_authorized_keys:\n      - ${file("${var.ssh_key_path}")}"
                }
              }
              
              # Creating a DNS zone
              
              resource "yandex_dns_zone" "my-domain-zone" {
                name    = local.domain_zone_name
                zone    = "${var.domain_name}."
                public  = true
              }
              
              # Creating a type A resource record
              
              resource "yandex_dns_recordset" "rsA1" {
                zone_id = yandex_dns_zone.my-domain-zone.id
                name    = "${yandex_dns_zone.my-domain-zone.zone}"
                type    = "A"
                ttl     = 600
                data    = ["${yandex_compute_instance.mywebserver.network_interface.0.nat_ip_address}"]
                # description: Resource record description. This is an optional parameter.
              }
              ```

              {% endcut %}

          1. `bind-domain-to-vm.auto.tfvars` user data file:

              {% cut "bind-domain-to-vm.auto.tfvars" %}

              ```hcl
              folder_id    = "<folder_ID>"
              ssh_key_path = "<path_to_SSH_key>"
              domain_name  = "<domain_name>"
              ```

              {% endcut %}

    {% endlist %}

    For more information about the properties of Terraform resources, see the provider documentation:

    * [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)
    * [Image](../../../compute/concepts/image.md): [yandex_compute_image](../../../terraform/resources/compute_image.md)
    * [Disk](../../../compute/concepts/disk.md): [yandex_compute_disk](../../../terraform/resources/compute_disk.md)
    * [VM](../../../compute/concepts/vm.md): [yandex_compute_instance](../../../terraform/resources/compute_instance.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 `bind-domain-to-vm.auto.tfvars` file, set the following user-defined properties:

    * `folder_id`: [Folder ID](../../../resource-manager/operations/folder/get-id.md).
    * `ssh_key_path`: Path to the public SSH key file to authenticate the user on the VM, e.g., `~/.ssh/id_ed25519.pub`. For more information, see [Creating an SSH key pair](../../../compute/operations/vm-connect/ssh.md#creating-ssh-keys).
    * `domain_name`: Your domain name, e.g., `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.

1. [Get the VM public IP address](../../../compute/operations/vm-info/get-info.md#outside-instance): you will use it later [to test the hosting](#test).

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

## Test the website {#test}

The website on your web server is now accessible by its domain name. To test the site, enter its IP address or domain name in your browser:

* `http://<VM_public_IP_address>`
* `http://example.com`

## Delete the resources you created {#clear-out}

To shut down the hosting and stop paying for the resources you created:

1. Open the `bind-domain-to-vm.tf` configuration file and delete your infrastructure description.
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}

* [Assigning a domain name to a web server VM using the management console, CLI, or API](console.md)