Интеграция Telegram-бота с веб-приложением на Flask: деплой и безопасность

Интеграция Telegram-бота с веб-приложением на Flask: деплой и безопасность

Мы уже рассказывали, как создать простого бота для сайта на Python/Flask, теперь пришло время интегрировать код бота с веб приложением. В статье — подготовка окружения, деплой бота на сервер, интеграция с сервисами сайта и советы по безопасности.

Введение

Внешние чат-боты часто ограничивают кастомизацию, навязывают платные тарифы и создают зависимость от чужого API, в то время как самописное решение на Flask даёт полный контроль над данными, глубокую интеграцию с внутренними системами вашего сайта и значительно экономит бюджет. Рассказываем, как развернуть и встроить на сайт Python-бота, используя Flask для бэкенда и HTML/JS для фронтенда, на хостинге с Ubuntu 24.04.

Аренда VPS/VDS — от ₽219/месяц

Почему выбирают VPS от AdminVPS:

✓ Дешевле физического сервера

✓ Более гибкий и мощный, чем обычный хостинг

✓ Бесплатная защита от DDoS и техподдержка 24/7

✓ Масштабируется под любые задачи

Виртуальный сервер VPS/VDS — ваш личный сервер для сайтов, магазинов, ботов и других проектов.

Архитектура решения: как всё работает вместе

Когда пользователь открывает ваш сайт, встроенный JavaScript-виджет чата загружается как часть страницы — это фронтенд-компонент, отвечающий за отображение диалога и кнопок. При отправке сообщения фронтенд автоматически передаёт запрос через AJAX на ваш бэкенд — Flask-приложение, развёрнутое на сервере.

Flask анализирует текст через шаблоны или NLP-движок, интегрируется с базой данных (например, Redis для кеширования частых ответов) и внешними API, после чего формирует ответ. Этот ответ возвращается фронтенду, который мгновенно отображает его пользователю.

Критически важная часть инфраструктуры — веб-сервер Nginx, который принимает входящие запросы, обслуживает статику (CSS/JS), балансирует нагрузку и проксирует динамические запросы через WSGI-сервер Gunicorn к Flask-приложению. Такая архитектура обеспечивает отказоустойчивость и высокую производительность под нагрузкой.

Подготовка продакшен-окружения на Ubuntu 24.04

Перед запуском бота подготовьте сервер. Начните с базовых команд:

sudo apt update && sudo apt upgrade -y  # Обновление индексов пакетов и системы
sudo apt install python3-pip python3-venv nginx git -y  # Установка ключевых компонентов

Пояснение:

  • python3-venv создаёт изолированные окружения для зависимостей,
  • nginx работает как обратный прокси и файрвол приложения,
  • git необходим для деплоя кода.

Flask требует секретный ключ для подписи сессий и токенов. Сгенерируйте его и сохраните в защищённом файле:

SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
sudo mkdir -p /etc/chatbot
echo "FLASK_SECRET=$SECRET_KEY" | sudo tee /etc/chatbot/.env
sudo chmod 600 /etc/chatbot/.env 

Этот ключ понадобится при настройке systemd-сервиса. Никогда не публикуйте его в открытом доступе.

Клонируйте репозиторий с ботом:

git clone https://ваш_репозиторий.git /opt/chatbot

Перейдите в директорию проекта и создайте виртуальное окружение:

cd /opt/chatbot
python3 -m venv venv  # Создаёт каталог venv с изолированным Python

Активируйте окружение и установите зависимости:

source venv/bin/activate
pip install -r requirements.txt  # Flask, Gunicorn и другие библиотеки

Для работы в фоне используйте tmux или systemd-сервис (об этом — в следующем разделе). Если требования отсутствуют, соберите их командой:

pip freeze > requirements.txt  # Фиксирует версии пакетов

Запуск бота через Gunicorn + Nginx

Встроенный сервер Flask не предназначен для работы в продакшене: он медленный, не поддерживает многопоточность и уязвим к атакам, поэтому обычно используют связку Gunicorn (WSGI-сервер) и Nginx (файрвол + прокси).

Установите Gunicorn:

pip install gunicorn

Запустите приложение:

gunicorn --workers 4 --bind 127.0.0.1:8000 app:app

Здесь:

  • --workers 4 — 4 воркера (оптимальное — 2 Х количество ядер CPU + 1),
  • --bind 127.0.0.1:8000 — порт для внутренней коммуникации с Nginx,
  • app:app — имя модуля (app.py) и экземпляр Flask (app).

Затем настройте Nginx. Создайте файл /etc/nginx/sites-available/chatbot.conf:

server {
    listen 80;
    server_name bot.yoursite.com;  # Ваш домен   
    return 301 https://$host$request_uri;  # Принудительный HTTPS
}
server {
    listen 443 ssl;
    server_name bot.yoursite.com;
    ssl_certificate /etc/letsencrypt/live/bot.yoursite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bot.yoursite.com/privkey.pem;
    location / {
        proxy_pass http://localhost:8000;  # Прокси к Gunicorn
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;  # Реальный IP клиента
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }   
    location ^~ /static/ {
        alias /opt/chatbot/static/;  # Путь к статике фронтенда
        try_files $uri =404;  # Защита от перебора путей
        expires 30d;  # Кеширование в браузере
    }
}

SSL-блок должен быть добавлен после выполнения sudo certbot --nginx -d bot.yoursite.com.

Активация и проверка:

sudo ln -s /etc/nginx/sites-available/chatbot.conf /etc/nginx/sites-enabled/
sudo nginx -t  # Проверка конфига
sudo systemctl reload nginx  # Применение изменений

Настройте автозапуск через Systemd. Создайте сервис /etc/systemd/system/chatbot.service:

[Unit]

Description=Gunicorn для чат-бота
After=network.target

[Service]

User=ubuntu  # Ваш пользователь
Group=www-data
WorkingDirectory=/opt/chatbot
Environment="PATH=/opt/chatbot/venv/bin"
EnvironmentFile=/etc/chatbot/.env
ExecStart=/opt/chatbot/venv/bin/gunicorn --workers 4 --bind 127.0.0.1:8000 app:app

[Install]

WantedBy=multi-user.target

Запустите:

sudo systemctl start chatbot
sudo systemctl enable chatbot  # Автозапуск при загрузке

Для HTTPS добавьте сертификат Let's Encrypt:

sudo apt install certbot python3-certbot-nginx  # Если не установлены
sudo certbot --nginx -d bot.yoursite.com

Как встроить чат-бота на сайт: 2 метода

Первый метод — через Iframe. Добавьте на страницу сайта код:

<iframe src="https://bot.yoursite.com" width="350" height="500" frameborder="0"></iframe>  

Это простой в реализации метод, но он недостаточно гибок для продакшена. Его минусы: фиксированные размеры, сложная адаптация под мобильные устройства, ограниченное взаимодействие с контентом сайта (например, нельзя передать данные авторизации). Поэтому он больше подходит для быстрых тестов или простых ботов без интеграции с сайтом.

Второй метод — JavaScript-виджет, он и является рекомендуемым для большинства случаев. Сначала подготовьте фронтенд — создайте файл static/chat-widget.js:

// Инициализация виджета 
function initChatWidget() { 
  const widgetHTML = ` 
    <div id="chat-container"> 
      <div id="chat-messages"></div> 
      <input type="text" id="chat-input" placeholder="Введите сообщение..."> 
      <button onclick="sendMessage()">Отправить</button> 
    </div> 
  `; 
  document.body.insertAdjacentHTML('beforeend', widgetHTML); 

// Отправка сообщения на бэкенд 
async function sendMessage() { 
  const input = document.getElementById('chat-input'); 
  const message = input.value.trim(); 
  if (!message) return; 
  const response = await fetch('https://bot.yoursite.com/chat', { 
    method: 'POST', 
    headers: { 'Content-Type': 'application/json' }, 
    body: JSON.stringify({ message }) 
  }); 
  const data = await response.json(); 
  displayMessage(data.reply, 'bot'); 
  input.value = ''; 

// Отображение сообщений 
function displayMessage(text, sender) {
  const messagesDiv = document.getElementById('chat-messages');
  const messageEl = document.createElement('div');
  const contentEl = document.createElement('div');
  messageEl.classList.add('message', sender);
  contentEl.textContent = text;
  messageEl.appendChild(contentEl);
  messagesDiv.appendChild(messageEl);
  messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
// Запуск при загрузке страницы 
window.addEventListener('DOMContentLoaded', initChatWidget);  

Добавьте стили (файл static/style.css), например:

#chat-container { 
  position: fixed; 
  bottom: 20px; 
  right: 20px; 
  width: 300px; 
  border: 1px solid #ddd; 
  padding: 10px; 
  background: white; 
  z-index: 1000; 

.message { margin: 5px 0; } 
.message.bot { color: #1e88e5; }  

Вставьте на сайт — добавьте перед </body> в HTML:

<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> 
<script src="{{ url_for('static', filename='chat-widget.js') }}"></script>  

Чтобы бот подстраивался под ширину экрана, добавьте медиа-запрос в CSS, например:

@media (max-width: 768px) { #chat-container { width: 90%; } } 

Преимущества этого метода:

  • полная интеграция с дизайном сайта;
  • возможность передавать данные сессии (корзина, история заказов),
  • адаптивность под мобильные устройства,
  • гибкая настройка логики (например, запуск при прокрутке страницы).

Для защиты от XSS-атак всегда сканируйте пользовательский ввод:

from flask import escape 
user_message = escape(request.json.get('message', ''))  

Защита бота и пользователей

Без шифрования данные пользователей, включая сообщения, передаются открытым текстом, поэтому обязательно настройте HTTPS  для бота, если вы не сделали этого раньше:

sudo apt install certbot python3-certbot-nginx 
sudo certbot --nginx -d bot.yoursite.com  

Чтобы защититься от DDoS и брутфорса, ограничьте запросы к /chat в Nginx. В /etc/nginx/nginx.conf:

http { 
    limit_req_zone $binary_remote_addr zone=chatlimit:10m rate=5r/s; 

В etc/nginx/sites-available/chatbot.conf:

server { 
    ... 
    location /chat { 
        limit_req zone=chatlimit burst=10 nodelay; 
        proxy_pass http://localhost:8000; 
    } 
}  

Пояснение:

  • rate=5r/s — 5 запросов в секунду с одного IP,
  • burst=10 — кратковременные всплески до 10 запросов,
  • Nodelay — немедленная обработка без задержки в очереди.

Валидация входных данных:

from flask import request, escape, jsonify, make_response
import re
@app.route('/chat', methods=['POST', 'OPTIONS'])
def chat_handler():
    # Обработка CORS для предварительных запросов
    if request.method == 'OPTIONS':
        response = make_response()
        response.headers.add("Access-Control-Allow-Origin", "https://yoursite.com")
        response.headers.add("Access-Control-Allow-Headers", "Content-Type")
        response.headers.add("Access-Control-Allow-Methods", "POST")
        return response
    # Обработка основного запроса
    raw_message = request.json.get('message', '')
    # Санация HTML/JS
    clean_message = escape(raw_message)
    # Ваша основная логика обработки сообщения
    return jsonify({"reply": "Ответ бота"})

Настройка CORS (рекомендуемый способ с Flask-CORS):

from flask_cors import CORS
# Разрешить запросы только с yoursite.com
CORS(app, resources={r"/chat": {"origins": "https://yoursite.com"}})

Дополнительные меры

  • Защита паролей:
# Вместо хранения в коде 
import os 
SECRET_KEY = os.environ.get("FLASK_SECRET")  
  • Безопасные куки:
app.config.update( 
  SESSION_COOKIE_HTTPONLY=True, 
  SESSION_COOKIE_SECURE=True, 
  SESSION_COOKIE_SAMESITE='Lax' 
)  
  • Настройте файрвол, например, если используете ufw:
sudo ufw allow 'Nginx Full'  # HTTP/HTTPS 
sudo ufw deny 8000  # Закрыть прямой доступ к Gunicorn  
  • Регулярно обновляйте зависимости:
pip list --outdated  # Просмотр устаревших пакетов 
pip install -U flask gunicorn  # Обновление  

Интеграция с сервисами сайта (практические примеры)

Через REST API

Пример интеграции с внутренним API сайта для получения данных пользователя:

import requests
from flask import current_app
def get_user_data(user_id):
    try:
        # Используем ключ API из переменных окружения
        api_key = current_app.config["INTERNAL_API_KEY"]
        headers = {"Authorization": f"Bearer {api_key}"}
        response = requests.get(
            f"https://api.yoursite.com/users/{user_id}",
            headers=headers,
            timeout=3  # Таймаут для безопасности
        )
        response.raise_for_status()  # Проверка на ошибки HTTP
        return response.json()
    except requests.exceptions.RequestException as e:
        current_app.logger.error(f"API Error: {e}")
        return None
# В обработчике чата
if "мой профиль" in user_message:
    user_data = get_user_data(request.json["user_id"])
    if user_data:
        reply = f"Ваш статус: {user_data['status']}, Баланс: {user_data['balance']} руб."

Через общую БД (PostgreSQL)

Настройка подключения:

from flask_sqlalchemy import SQLAlchemy
import os
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
db = SQLAlchemy(app)

Пример запроса статуса заказа:

def get_order_status(order_id):
    result = db.session.execute(
        "SELECT status FROM orders WHERE id = :order_id",
        {"order_id": order_id}
    ).scalar()
    return result or "Не найден"
# В обработчике
if "статус заказа" in user_message:
    order_id = extract_order_id(user_message)  # Ваша функция парсинга
    status = get_order_status(order_id)
    return jsonify({"reply": f"Статус заказа #{order_id}: {status}"})

Важно:

  • создайте отдельного пользователя БД с правами только на чтение,
  • используйте параметризованные запросы для защиты от SQL-инъекций.

Вебинар-ассистент

Автоматизация ответов во время трансляции:

webinar_keywords = {
    r"где\s?запись": "Запись будет доступна через 2 часа после эфира",
    r"слайды": "Презентация: https://yoursite.com/webinar/slides.pdf",
    r"повтори": "Ответ продублирован в чате вебинара"
}
@app.route('/chat', methods=['POST'])
def chat_handler():
    if request.json.get("context") == "webinar":  # Фронтенд передает контекст
        for pattern, response in webinar_keywords.items():
            if re.search(pattern, user_message, re.IGNORECASE):
                return jsonify({"reply": response, "urgent": True})  # Срочное сообщение

Заключение

Интеграция Telegram-бота с веб-приложением на Flask — это не просто способ добавить чат на сайт, а полноценное расширение функциональности проекта. Такой бот может общаться с пользователями, выполнять действия внутри сайта, взаимодействовать с базой данных и API, автоматически подстраиваясь под бизнес-процессы. Мы рассмотрели ключевые этапы: от настройки продакшен-окружения на VPS до безопасного деплоя, подключения через Nginx и организации взаимодействия с фронтендом.

Благодаря гибкости Flask и прозрачности архитектуры, вы получаете решение, которое легко масштабировать, развивать и поддерживать. Настраивая всё самостоятельно, вы не только экономите, но и минимизируете зависимости от сторонних сервисов. А при должном уровне защиты — такой подход остаётся надёжным и безопасным даже при высокой нагрузке.

Читайте в блоге:

Loading spinner
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Нужен VPS сервер?

Арендуйте мощный VPS сервер для ваших проектов! Быстрая настройка, высокая производительность и надежная поддержка 24/7. Начните прямо сейчас!

Что будем искать? Например,VPS-сервер

Мы в социальных сетях