How to create a Telegram bot using Serverless and Terraform
To create a Telegram bot using Serverless and Terraform:
If you no longer need the resources you created, delete them.
Get your cloud ready
Sign up for Yandex Cloud and create a billing account:
- Navigate to the management console
and log in to Yandex Cloud or create a new account. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVEorTRIAL_ACTIVEstatus. If you do not have a billing account, create one and link a cloud to it.
If you have an active billing account, you can create or select a folder for your infrastructure on the cloud page
Learn more about clouds and folders here.
Required paid resources
The cost of supporting the Telegram bot infrastructure includes:
- Fee for function calls, computing resources allocated for the function, and outgoing traffic (see Cloud Functions pricing).
- Fee for data storage in Object Storage, operations with data, and outgoing traffic (see Object Storage pricing).
- Fee for the number of requests to the API gateway and outgoing traffic (see Yandex API Gateway pricing).
Create a Telegram bot
Create a bot in Telegram and get a token.
-
To register a new bot, start BotFather
and run the below command./newbot -
In the
namefield, enter a name for the bot, e.g.,Serverless Hello Telegram Bot. This is the name users will see when chatting with the bot. -
In the
usernamefield, specify a username for the bot, e.g.,ServerlessHelloTelegramBot. You can use it to find the bot in Telegram. The username must end with...Botor..._bot.As a result, you will get a token. Save it, as you will need it later.
-
Set an icon for the bot using
sayhello.pngfrom the saved archive. Send this command to BotFather:/setuserpic
Create the infrastructure
With Terraform
Terraform is distributed under the Business Source License
For more information about the provider resources, see the relevant documentation on the Terraform
To create your infrastructure via Terraform:
-
Install Terraform, obtain authentication credentials, and specify the source for installing the Yandex Cloud provider. For details, see Configure your provider, step 1.
-
Prepare your infrastructure description files:
Ready-made configurationManually-
Clone the repository
with the configuration files required to create the bot. Do it by running this git command in the terminal:git clone https://git@git.sourcecraft.dev/yandex-cloud-examples/yc-telegram-bot-serverless.git -
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.
-
Create a folder for configuration files.
-
In the folder, create:
-
telegram-bot.tfconfiguration file:telegram-bot.tf
# 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 }) } -
telegram-bot-function.tpltemplate for creating a function in Yandex Cloud Functions:telegram-bot-function.tpl
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: '', }; }; -
telegram-bot-gw-spec.tplAPI gateway specification template:telegram-bot-gw-spec.tpl
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 -
telegram-bot.auto.tfvarsuser data file:bot_token = "<Telegram_bot_token>" bucket_name = "<bucket_name>" cloud_id = "<cloud_ID>" folder_id = "<folder_ID>" -
package.jsonmanifest for the Node.js function:{ "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" } }
-
For more information about Terraform resource properties, see the relevant provider guides:
- Service account: yandex_iam_service_account.
- Assigning a role to a service account: yandex_resourcemanager_folder_iam_member.
- Static access key: yandex_iam_service_account_static_access_key.
- Bucket: yandex_storage_bucket
- Object: yandex_storage_object
- API gateway: yandex_api_gateway.
- Function: yandex_function.
- Assigning roles for a function: yandex_function_iam_binding.
-
-
In the
telegram-bot.auto.tfvarsfile, specify these custom settings:bot_token: Telegram bot token.bucket_name: Bucket name.cloud_id: Cloud ID.folder_id: Folder ID.
-
Create the resources:
-
In the terminal, navigate to the configuration file directory.
-
Make sure the configuration is correct using this command:
terraform validateIf the configuration is valid, you will get this message:
Success! The configuration is valid. -
Run this command:
terraform planYou 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.
-
Apply the configuration changes:
terraform apply -
Type
yesand press Enter to confirm the changes.
-
-
Configure a link between the function and the Telegram bot.
-
Update the API gateway specification by adding the
fshtb-functionsection at the end of the code:/fshtb-function: post: x-yc-apigateway-integration: type: cloud_functions function_id: <function_ID> operationId: fshtb-functionWhere
function_idis thefshtb-functionID. -
Apply the configuration changes:
terraform apply -
Type
yesand press Enter to confirm the changes. -
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:
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):
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):
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:
{"ok":true,"result":true,"description":"Webhook was set"} -
-
Test your Telegram bot
Chat with the bot:
-
Open Telegram and search for the bot using the previously created
username. -
Send
/startto the chat.The bot should respond with:
Hello. My name Serverless Hello Telegram Bot I'm working on Cloud Function in the Yandex Cloud. -
Send
/helpto the chat.The bot should respond with:
Hello, <username>. I can say Hello and nothing more -
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
To stop paying for the resources you created:
-
Open the
telegram-bot.tffile and delete your infrastructure description from it. -
Apply the changes:
-
In the terminal, navigate to the configuration file directory.
-
Make sure the configuration is correct using this command:
terraform validateIf the configuration is valid, you will get this message:
Success! The configuration is valid. -
Run this command:
terraform planYou 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.
-
Apply the configuration changes:
terraform apply -
Type
yesand press Enter to confirm the changes.
-