# Static website in Yandex Object Storage using Terraform

To host a [static website in Object Storage](index.md) using Terraform:

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

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 cost of hosting a static website includes:
* Fee for storing data for a static website (see [Object Storage pricing](../../../storage/pricing.md#prices-storage)).
* Fee for data operations (see [Object Storage pricing](../../../storage/pricing.md#prices-operations)).
* Fee for outgoing traffic from Yandex Cloud to the internet (see [Object Storage pricing](../../../storage/pricing.md#prices-traffic)).
* Fee for public DNS queries and [zones](../../../dns/concepts/dns-zone.md) (see [Yandex 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 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 for a static website in Object Storage using Terraform:
1. [Install Terraform](../../infrastructure-management/terraform-quickstart.md#install-terraform), [get the authentication credentials](../../infrastructure-management/terraform-quickstart.md#get-credentials), and specify the source for installing the Yandex Cloud provider (see [Configure your provider](../../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 with configuration files.

        ```bash
        git clone https://github.com/yandex-cloud-examples/yc-s3-static-website.git
        ```

     1. Navigate to the repository directory. It should now contain the following files:
        * `static.tf`: New infrastructure configuration.
        * `index.html` and `error.html`: Website's main page and error page.

   - Manually {#manual}

     1. Create a folder for configuration files.
     1. In the folder, create:
        1. `static.tf` configuration file:

           {% cut "static.tf" %}

           ```hcl
           locals {
             folder_id = "<folder_ID>"
             domain    = "<domain>"
           }
           
           terraform {
             required_providers {
               yandex = {
                 source  = "yandex-cloud/yandex"
                 version = ">= 0.47.0"
               }
             }
           }
           
           provider "yandex" {
             folder_id = local.folder_id
           }
           
           resource "yandex_iam_service_account" "sa" {
             name      = "my-sa"
           }
           
           resource "yandex_resourcemanager_folder_iam_member" "sa-editor" {
             folder_id = local.folder_id
             role      = "storage.editor"
             member    = "serviceAccount:${yandex_iam_service_account.sa.id}"
           }
           
           resource "yandex_iam_service_account_static_access_key" "sa-static-key" {
             service_account_id = yandex_iam_service_account.sa.id
             description        = "static access key for object storage"
           }
           
           resource "yandex_storage_bucket" "test" {
             access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key
             secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
             bucket     = local.domain
             max_size   = 1073741824  
           
             website {
               index_document = "index.html"
               error_document = "error.html"
             }
           
             # Certificate Manager certificate
             https {
               certificate_id = data.yandex_cm_certificate.example.id
             }
           }
           
           resource "yandex_storage_bucket_iam_binding" "storage_admin" {
             bucket = local.domain
             role   = "storage.admin"
           
             members = [
               "serviceAccount:${yandex_iam_service_account.sa.id}",
             ]
             depends_on = [yandex_storage_bucket.test]
           }
           
           resource "yandex_storage_bucket_grant" "public_read" {
             bucket = local.domain
             access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key
             secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
             acl        = "public-read"
             depends_on = [yandex_storage_bucket_iam_binding.storage_admin]
           }
           
           resource "yandex_cm_certificate" "le-certificate" {
             name    = "my-le-cert"
             domains = ["${local.domain}"]
           
             managed {
             challenge_type = "DNS_CNAME"
             }
           }
           
           resource "yandex_dns_recordset" "validation-record" {
             zone_id = yandex_dns_zone.zone1.id
             name    = yandex_cm_certificate.le-certificate.challenges[0].dns_name
             type    = yandex_cm_certificate.le-certificate.challenges[0].dns_type
             data    = [yandex_cm_certificate.le-certificate.challenges[0].dns_value]
             ttl     = 600
           }
           
           data "yandex_cm_certificate" "example" {
             depends_on      = [yandex_dns_recordset.validation-record]
             certificate_id  = yandex_cm_certificate.le-certificate.id
             #wait_validation = true
           }
           
           resource "yandex_storage_object" "index-html" {
             access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key
             secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
             bucket     = yandex_storage_bucket.test.id
             key        = "index.html"
             source     = "index.html"
           }
           
           resource "yandex_storage_object" "error-html" {
             access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key
             secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
             bucket     = yandex_storage_bucket.test.id
             key        = "error.html"
             source     = "error.html"
           }
           
           resource "yandex_dns_zone" "zone1" {
             name        = "example-zone-1"
             description = "Public zone"
             zone        = "${local.domain}."
             public      = true
           }
           
           resource "yandex_dns_recordset" "rs2" {
             zone_id = yandex_dns_zone.zone1.id
             name    = "${local.domain}."
             type    = "ANAME"
             ttl     = 600
             data    = ["${local.domain}.website.yandexcloud.net"]
           }
           ```

           {% endcut %}

        1. `index.html` file containing the text `Hello world!`:

           {% cut "index.html" %}

           ```html
           <!doctype html>
           <html>
             <head>
               <title>Hello, world!</title>
             </head>
             <body>
               <p>Hello, world!</p>
             </body>
           </html>
           ```

           {% endcut %}

        1. `error.html` file containing the text `Error!`:

           {% cut "error.html" %}

           ```html
           <!doctype html>
           <html>
             <head>
               <title>Error!</title>
             </head>
             <body>
               <p>Error!</p>
             </body>
           </html>
           ```

           {% endcut %}

   {% endlist %}

   Learn more about the properties of Terraform resources in the relevant provider guides:
    * [Service account](../../../iam/concepts/users/service-accounts.md): [yandex_iam_service_account](../../../terraform/resources/iam_service_account.md).
    * [Configuring](../../../iam/concepts/access-control/roles.md) access permissions for a folder: [yandex_resourcemanager_folder_iam_member](../../../terraform/resources/resourcemanager_folder_iam_member.md).
    * [Static access key](../../../iam/concepts/authorization/access-key.md): [yandex_iam_service_account_static_access_key](../../../terraform/resources/iam_service_account_static_access_key.md).
    * [Bucket](../../../storage/concepts/bucket.md): [yandex_storage_bucket](../../../terraform/resources/storage_bucket.md).
    * [Configuring](../../../storage/operations/buckets/iam-access.md) access permissions for a bucket using Identity and Access Management: [yandex_storage_bucket_iam_binding](../../../terraform/resources/storage_bucket_iam_binding.md).
    * [Configuring](../../../storage/operations/buckets/edit-acl.md) access permissions for a bucket using the [Object Storage ACL](../../../storage/concepts/acl.md): [yandex_storage_bucket_grant](../../../terraform/resources/storage_bucket_grant.md).
    * [TLS certificate](../../../certificate-manager/concepts/imported-certificate.md) data source: [yandex_cm_certificate](../../../terraform/data-sources/cm_certificate.md).
    * Bucket [object](../../../storage/concepts/object.md): [yandex_storage_object](../../../terraform/resources/storage_object.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. Under `locals` in the `static.tf` file, set the following user-defined properties:
   * `folder_id`: [ID of the folder](../../../resource-manager/operations/folder/get-id.md) to create the resources in.
   * `domain`: Domain name in `example.com` format, without a trailing dot.

1. Create 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, [test the website](#test-site).

## Test the website {#test-site}

To check that the website is running, use one of the standard Object Storage addresses:
* `http://<bucket_name>.website.yandexcloud.net`
* `http://website.yandexcloud.net/<bucket_name>`

If you have configured your own domain for a website, use its address, e.g., `example.com`.

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

To stop paying for the resources you created:

1. Open the `static.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}

* [Static website in Yandex Object Storage using the management console](console.md).