[Yandex Cloud documentation](../../../index.md) > [Yandex API Gateway](../../index.md) > [Tutorials](../index.md) > Serverless-based bots > [Developing a Telegram bot](index.md) > Terraform

# How to create a Telegram bot using Serverless and Terraform


To [create a Telegram bot](index.md) using Serverless and Terraform:

1. [Get your cloud ready](#before-you-begin).
1. [Create a Telegram bot](#create-bot).
1. [Create the infrastructure](#deploy).
1. [Test your Telegram bot](#test-bot).

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 Telegram bot infrastructure includes:
* Fee for [function calls](../../../functions/concepts/function.md), computing resources allocated for the function, and outgoing traffic (see [Cloud Functions pricing](../../../functions/pricing.md)).
* Fee for [storing data](../../../storage/concepts/bucket.md) in Object Storage, [operations](../../../storage/operations/index.md) with it, and outgoing traffic (see [Object Storage pricing](../../../storage/pricing.md)).
* Fee for the number of requests to the [API gateway](../../concepts/index.md) and outgoing traffic (see [Yandex API Gateway pricing](../../pricing.md)).


## Create a Telegram bot {#create-bot}

Create a bot in Telegram and get a token.

1. To register a new bot, start [BotFather](https://t.me/BotFather) and run the below command.

    ```text
    /newbot
    ```

1. In the `name` field, enter a name for the bot, e.g., `Serverless Hello Telegram Bot`. This is the name users will see when chatting with the bot.
1. In the `username` field, specify a username for the bot, e.g., `ServerlessHelloTelegramBot`. You can use it to find the bot in Telegram. The username must end with `...Bot` or `..._bot`.

   As a result, you will get a token. Save it, as you will need it later.

1. Set an icon for the bot using `sayhello.png` from the saved archive. Send this command to BotFather:

    ```text
    /setuserpic
    ```


## Create the 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 create your infrastructure via Terraform:
1. [Install Terraform](../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform), [get 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. Prepare your infrastructure description files:

    {% list tabs group=infrastructure_description %}

    - Ready-made configuration {#ready}

      1. Clone the [repository](https://sourcecraft.dev/yandex-cloud-examples/yc-telegram-bot-serverless) with the configuration files required to create the bot. Do it by running this [git](https://git-scm.com/) command in the terminal:

          ```bash
          git clone https://git@git.sourcecraft.dev/yandex-cloud-examples/yc-telegram-bot-serverless.git
          ```

      1. Navigate to the repository directory. It should now contain the following files:
          * `telegram-bot.tf`: New infrastructure configuration.
          * `telegram-bot.auto.tfvars`: User data file.
          * `telegram-bot-function.tpl`: Template for creating a function in Yandex Cloud Functions.
          * `telegram-bot-gw-spec.tpl`: API gateway specification template.
          * `sayhello.png`: Your bot image.
          * `package.json`: Manifest for the Node.js function.

    - Manually {#manual}

      1. Create a folder for configuration files.

      1. In the folder, create:

          1. `telegram-bot.tf` configuration file:

              {% cut "telegram-bot.tf" %}

              ```hcl
              # Declaring variables with sensitive data
              
              variable "cloud_id" {
                type = string
              }
              
              variable "folder_id" {
                type = string
              }
              
              variable "bucket_name" {
                type = string
              }
              
              variable "bot_token" {
                type      = string
                sensitive = true
              }
              
              # Configuring the provider
              
              terraform {
                required_providers {
                  yandex = {
                    source = "yandex-cloud/yandex"
                  }
                }
              }
              
              provider "yandex" {
                cloud_id  = var.cloud_id
                folder_id = var.folder_id
              }
              
              # Creating a service account
              
              resource "yandex_iam_service_account" "bot_sa" {
                name        = "telegram-bot-sa"
                description = "Service Account for Telegram bot"
              }
              
              # Assigning roles to a service account
              
              resource "yandex_resourcemanager_folder_iam_member" "sa_editor" {
                folder_id = var.folder_id
                role      = "editor"
                member    = "serviceAccount:${yandex_iam_service_account.bot_sa.id}"
              
                depends_on = [yandex_iam_service_account.bot_sa]
              }
              
              resource "yandex_resourcemanager_folder_iam_member" "sa_invoker" {
                folder_id = var.folder_id
                role      = "functions.functionInvoker"
                member    = "serviceAccount:${yandex_iam_service_account.bot_sa.id}"
              
                depends_on = [yandex_iam_service_account.bot_sa]
              }
              
              # Creating static access keys
              
              resource "yandex_iam_service_account_static_access_key" "bot_sa_key" {
                service_account_id = yandex_iam_service_account.bot_sa.id
                description        = "Static key for bot service account"
              
                depends_on = [
                  yandex_resourcemanager_folder_iam_member.sa_editor
                ]
              }
              
              # Creating a bucket
              
              resource "yandex_storage_bucket" "bot_bucket" {
                bucket     = var.bucket_name
                access_key = yandex_iam_service_account_static_access_key.bot_sa_key.access_key
                secret_key = yandex_iam_service_account_static_access_key.bot_sa_key.secret_key
                anonymous_access_flags {
                  read = true
                }
              
                depends_on = [
                  yandex_iam_service_account_static_access_key.bot_sa_key
                ]
              }
              
              # Uploading an image to a bucket
              
              resource "yandex_storage_object" "sayhello_png" {
                bucket       = yandex_storage_bucket.bot_bucket.bucket
                key          = "sayhello.png"
                source       = "sayhello.png"
                acl          = "public-read"
                access_key   = yandex_iam_service_account_static_access_key.bot_sa_key.access_key
                secret_key   = yandex_iam_service_account_static_access_key.bot_sa_key.secret_key
                content_type = "image/png"
              
                depends_on = [yandex_storage_bucket.bot_bucket]
              }
              
              # Creating a zip archive for a function
              
              data "archive_file" "function" {
                type        = "zip"
                source {
                  content  = templatefile("telegram-bot-function.tpl", {
                    API_GW_URL = yandex_api_gateway.bot_gateway.domain
                  })
                  filename = "index.js"
                }
                source {
                  content  = "${file("package.json")}"
                  filename = "package.json"
                }
                output_path = "function.zip"
              
                depends_on = [yandex_api_gateway.bot_gateway]
              }
              
              # Creating a public function
              
              resource "yandex_function" "telegram_bot_function" {
                name               = "fshtb-function"
                description        = "Serverless Telegram bot on Node.js"
                runtime            = "nodejs22"
                entrypoint         = "index.handler"
                memory             = 256
                execution_timeout  = 5
                service_account_id = yandex_iam_service_account.bot_sa.id
              
                environment = {
                  BOT_TOKEN = var.bot_token
                }
              
                content {
                  zip_filename = "function.zip"
                }
              
                user_hash = filesha256("telegram-bot-function.tpl")
              
                depends_on = [
                  yandex_resourcemanager_folder_iam_member.sa_editor,
                  yandex_resourcemanager_folder_iam_member.sa_invoker,
                  data.archive_file.function
                ]
              }
              
              resource "yandex_function_iam_binding" "public_invoker" {
                function_id = yandex_function.telegram_bot_function.id
                role        = "functions.functionInvoker"
                members     = ["system:allUsers"]
              }
              
              # Creating an API gateway
              
              resource "yandex_api_gateway" "bot_gateway" {
                name        = "forserverless-hello-telegram-bot"
                description = "API gateway for telegram bot"
              
                spec = templatefile("telegram-bot-gw-spec.tpl", {
                  BUCKET_NAME = yandex_storage_bucket.bot_bucket.id
                  OBJECT_NAME = yandex_storage_object.sayhello_png.key
                  SA_ID       = yandex_iam_service_account.bot_sa.id
                })
              }
              ```

              {% endcut %}

          1. `telegram-bot-function.tpl` template for creating a function in Yandex Cloud Functions:

              {% cut "telegram-bot-function.tpl" %}

              ```js
              const { Telegraf } = require('telegraf');
              
              const bot = new Telegraf(process.env.BOT_TOKEN);
              bot.start((ctx) => ctx.reply(`Hello. \nMy name Serverless Hello Telegram Bot \nI'm working on Cloud Function in the Yandex.Cloud.`))
              bot.help((ctx) => ctx.reply(`Hello, ${ctx.message.from.username}.\nI can say Hello and nothing more`))
              bot.on('text', (ctx) => {
                  ctx.replyWithPhoto({url: 'https://${API_GW_URL}/sayhello.png'});
                  ctx.reply(`Hello, ${ctx.message.from.username}`);
              });
              
              module.exports.handler = async function (event, context) {
                  const message = JSON.parse(event.body);
                  await bot.handleUpdate(message);
                  return {
                      statusCode: 200,
                      body: '',
                  };
              }; 
              ```

              {% endcut %}

          1. `telegram-bot-gw-spec.tpl` API gateway specification template:

              {% cut "telegram-bot-gw-spec.tpl" %}

              ```yaml
              openapi: 3.0.0
              info:
                title: for-serverless-hello-telegram-bot
                version: 1.0.0
              paths:
                /sayhello.png:
                  get:
                    x-yc-apigateway-integration:
                      type: object-storage
                      bucket: ${BUCKET_NAME}
                      object: ${OBJECT_NAME}
                      presigned_redirect: false
                      service_account: ${SA_ID}
                    operationId: static
              ```

              {% endcut %}

          1. `telegram-bot.auto.tfvars` user data file:

              ```text
              bot_token   = "<Telegram_bot_token>"
              bucket_name = "<bucket_name>"
              cloud_id    = "<cloud_ID>"
              folder_id   = "<folder_ID>"
              ```

          1. `package.json` manifest for the Node.js function:

              ```json
              {
                "name": "ycf-telegram-example",
                "version": "1.0.0",
                "description": "",
                "main": "index.js",
                "scripts": {
                  "test": "echo \"Error: no test specified\" && exit 1"
                },
                "author": "",
                "license": "MIT",
                "dependencies": {
                  "telegraf": "^4.12.0"
                }
              }
              ```

    {% endlist %}

    For more on the properties of resources used in Terraform, see these provider guides:
    * [Service account](../../../iam/concepts/users/service-accounts.md): [yandex_iam_service_account](../../../terraform/resources/iam_service_account.md).
    * Assigning a [role](../../../iam/concepts/access-control/roles.md) to a service account: [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)
    * [Object](../../../storage/concepts/object.md): [yandex_storage_object](../../../terraform/resources/storage_object.md)
    * [API gateway](../../concepts/index.md): [yandex_api_gateway](../../../terraform/resources/api_gateway.md).
    * [Function](../../../functions/concepts/index.md): [yandex_function](../../../terraform/resources/function.md).
    * Assigning [roles for a function](../../../functions/security/index.md): [yandex_function_iam_binding](../../../terraform/resources/function_iam_binding.md).

1. In the `telegram-bot.auto.tfvars` file, set the following user-defined properties:
   * `bot_token`: Telegram bot token.
   * `bucket_name`: Bucket name.
   * `cloud_id`: Cloud ID.
   * `folder_id`: [Folder ID](../../../resource-manager/operations/folder/get-id.md).

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. Configure a link between the function and the Telegram bot.

    1. Update the API gateway specification by adding the `fshtb-function` section at the end of the code:

        ```yaml
          /fshtb-function:
            post:
              x-yc-apigateway-integration:
                type: cloud_functions
                function_id: <function_ID>
              operationId: fshtb-function
        ```
        
        Where `function_id` is the `fshtb-function` ID.

    1. Apply the configuration changes:

        ```bash
        terraform apply
        ```

    1. Type `yes` and press **Enter** to confirm the changes.

    1. In the terminal, run the following command, with `<bot_token>` replaced with your Telegram bot token, and `<API_gateway_domain>`, with a link to your API gateway's service domain:
       
       * Linux, macOS:
       
          ```bash
          curl \
            --request POST \
            --url https://api.telegram.org/bot<bot_token>/setWebhook \
            --header 'content-type: application/json' \
            --data '{"url": "<API_gateway_domain>/fshtb-function"}'
          ```
       
       * Windows (cmd):
       
          ```bash
          curl ^
            --request POST ^
            --url https://api.telegram.org/bot<bot_token>/setWebhook ^
            --header "content-type: application/json" ^
            --data "{\"url\": \"<API_gateway_domain>/fshtb-function\"}"
          ```
       
       * Windows (PowerShell):
       
          ```powershell
          curl.exe `
            --request POST `
            --url https://api.telegram.org/bot<bot_token>/setWebhook `
            --header '"content-type: application/json"' `
            --data '"{ \"url\": \"<API_gateway_domain>/fshtb-function\" }"'
          ```
       
       Result:
       
       ```text
       {"ok":true,"result":true,"description":"Webhook was set"}
       ```


## Test your Telegram bot {#test-bot}

Chat with the bot:

1. Open Telegram and search for the bot using the previously created `username`.
1. Send `/start` to the chat.

    The bot should respond with:
    
    ```text
    Hello.
    My name Serverless Hello Telegram Bot
    I'm working on Cloud Function in the Yandex Cloud.
    ```

1. Send `/help` to the chat.
    
    The bot should respond with:
    
    ```text
    Hello, <username>.
    I can say Hello and nothing more
    ```

1. Send a text message to the chat. The bot should respond with an image and this message: `Hello, <username>`.


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

To stop paying for the resources you created:
1. Open the `telegram-bot.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.


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

* [How to create a Telegram bot using Serverless in the management console](console.md)