Мы уже рассказывали, как создать простого бота для сайта на Python/Flask, теперь пришло время интегрировать код бота с веб приложением. В статье — подготовка окружения, деплой бота на сервер, интеграция с сервисами сайта и советы по безопасности.
Введение
Внешние чат-боты часто ограничивают кастомизацию, навязывают платные тарифы и создают зависимость от чужого API, в то время как самописное решение на Flask даёт полный контроль над данными, глубокую интеграцию с внутренними системами вашего сайта и значительно экономит бюджет. Рассказываем, как развернуть и встроить на сайт Python-бота, используя Flask для бэкенда и HTML/JS для фронтенда, на хостинге с Ubuntu 24.04.
Архитектура решения: как всё работает вместе
Когда пользователь открывает ваш сайт, встроенный 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 и прозрачности архитектуры, вы получаете решение, которое легко масштабировать, развивать и поддерживать. Настраивая всё самостоятельно, вы не только экономите, но и минимизируете зависимости от сторонних сервисов. А при должном уровне защиты — такой подход остаётся надёжным и безопасным даже при высокой нагрузке.
Читайте в блоге:
- Безопасность Telegram-бота на VPS в 2025 году: профессиональная защита от атак и утечек данных
- Как сделать Telegram‑бота на Python для мониторинга сервера
- Настройка автозапуска Python-скриптов на сервере: cron, systemd, nohup