A robust and scalable template for creating Telegram bots deployed on AWS Lambda using aiogram. This template provides a solid foundation with a clean project structure, local development support, and a flexible, automated deployment pipeline.
- Asynchronous with
aiogram3.x - Serverless on AWS Lambda (API Gateway webhook)
- Clean project structure (
core,handlers,utils) - Local development via polling (
main.py) - Automated deployment script with optional manual upload (
deploy.sh) - Secure webhook management via Lambda "Test" or deploy script
- Environment-based configuration (
.env.dev,.env.prod) - Makefile shortcuts for common tasks
.
βββ core/ # Core application logic (bot instance, config)
βββ handlers/ # Message and command handlers
βββ states/ # FSM states (if used)
βββ keyboards/ # Reply/inline keyboards
βββ utils/ # Utility functions (e.g., logging)
βββ docs/imgs/ # Documentation images
βββ .env.example # Example environment file
βββ .gitignore
βββ README.md
βββ deploy.sh # Automated deployment script
βββ lambda_function.py # AWS Lambda handler entry point
βββ main.py # Local development (polling)
βββ makefile # Makefile for common commands
βββ requirements.txt
- Python 3.11+ (Lambda runtime 3.11 or 3.13)
- AWS account with the AWS CLI configured
- A Telegram Bot Token from @BotFather
- Local dev (polling):
python -m venv .venv && source .venv/bin/activate make install-req cp .env.example .env.dev # fill BOT_TOKEN for dev make run # starts bot locally
- Deploy to Lambda (interactive):
cp .env.example .env.prod # fill BOT_TOKEN, LAMBDA_URL, SECRET_KEY make deploy # choose auto or manual upload
This template uses separate env files for dev and prod.
.env.dev(local polling):BOT_TOKEN="your_development_bot_token"
.env.prod(deployed Lambda):BOT_TOKEN="your_production_bot_token" LAMBDA_URL="https://<api-id>.execute-api.<region>.amazonaws.com/<stage>/webhook" SECRET_KEY="a_very_long_and_random_secret"
- LAMBDA_URL must be the full public API Gateway URL that maps to your Lambda webhook route, including
/webhook. - SECRET_KEY is used to authorize management commands (e.g., set/delete webhook) via Lambda.
- LAMBDA_URL must be the full public API Gateway URL that maps to your Lambda webhook route, including
To run the bot locally using long polling, simply run:
make runThis uses .env.dev and starts polling via main.py.
The deploy.sh script handles packaging and (optionally) deployment.
- Run the script:
make deploy
- The script will create
deployment.zip, then ask: "Do you want to deploy to AWS now? (y/n)"- Press
yfor automated deployment:- Uploads code to Lambda
- Updates Lambda environment variables using prod
.envcredentials - Prompts to set the webhook via a secure Lambda invocation
- Press
nfor manual deployment:deployment.zipis left in the project directory for manual upload in the AWS Console
- Press
- Go to Lambda Functions and click Create function
- https://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/functions
- Give the function a name and choose Python 3.11+ (e.g., Python 3.13)

- Increase timeout and memory in Configuration if needed
- Add a trigger: API Gateway β Create new API
- In API Gateway, create a route
/webhook - Attach the Lambda integration to that route
- Copy the final webhook URL from API Gateway triggers
- Add environment variables to Lambda β Configuration β Environment variables
- Upload the deployment package
- Set the webhook (two options):
- Wait up to a few minutes for the webhook to propagate, then send
/startto your bot.
You can also manage the webhook at any time via the Lambda Test tab using the same JSON payload as above, or via the AWS CLI:
aws lambda invoke \
--function-name <your-function-name> \
--payload '{"command":"set_webhook","secret":"<SECRET_KEY>"}' \
--cli-binary-format raw-in-base64-out \
--region <region> \
response.jsonTo delete the webhook, use "command":"delete_webhook".
- Event loop is closed (Lambda):
- The template uses a safe pattern that closes the bot session after each invocation in
lambda_function.py. Ensure your deployment uses the latest version.
- The template uses a safe pattern that closes the bot session after each invocation in
- 401 Unauthorized from Telegram:
- Check
BOT_TOKENin Lambda env vars (Configuration β Environment variables).
- Check
- 403 when setting webhook:
- Ensure
LAMBDA_URLis the full API Gateway URL including/webhookand that API Gateway route is deployed.
- Ensure
- 502/Integration errors in API Gateway:
- Re-check that the route is integrated with the correct Lambda in the same region and stage is deployed.
- No messages arriving:
- Confirm webhook is set (
getWebhookInfovia Bot API), and view CloudWatch logs (Lambda β Monitor β Logs).
- Confirm webhook is set (
- Never commit secrets.
.gitignoreexcludes.envfiles and build artifacts (build,deployment.zip). - Rotate your
BOT_TOKENif it is ever exposed. - Choose a strong, random
SECRET_KEYand keep it only in Lambda env or.env.prodlocally.
make install-reqβ Installs dependencies fromrequirements.txtmake runβ Runs the bot locally via pollingmake deployβ Buildsdeployment.zipand interactively deploys/sets webhook







