Деплой бота на Python на Beget

Деплой – это развёртывание программного обеспечения, то есть это все действия, которые делают программную систему готовой к использованию.
Деплой телеграм-бота – это размещение его на сервере или на хостинге.

Итак, стартовые условия:

  • хостинг на Beget
  • к хостингу привязан домен
  • для домена выпущен бесплатный SSL-сертификат Let’s Encrypt
Установим бота написанного на питоне на хостинг Бегет

Начинаем установку Flask.

Установка Flask на Beget

Включаем SSH в настройках хостинга (если он выключен).

Нам понадобится доступ по SSH

Подключаемся к хостингу через SSH. Это можно сделать прямо из панели управления хостингом: у Бегет встроен терминал прямо тут – мега-удобная штука.

Терминал в панели Beget
Все работы в консоли в Beget можно сделать прямо в панели управления хостингом благодаря встроенному терминалу.


Я делаю это через программу Putty.

В поле “hostname (or IP address)” вводим:

<логин-к-хостингу>@domain.ru

То есть в моем конкретно случае:

<логин-к-хостингу>@hosting-telegram-bota.ru

Нажимаем Open, вводим пароль от хостинга и заходим на хостинг через SSH:

При установке бота на Python на хостинг без консоли не обойтись..

Затем нам нужно перейти в Docker, выполняем команду:

ssh localhost -p222

Еще раз потребуется ввести пароль от хостинга, и если всё ОК – видим надпись (docker) в скобочках.

Переходи в Docker в консоли
Если все ОК - то слева в скобках будет надпись "docker"

Теперь переходим в папку сайта, в моем случае команда выглядит так:

cd hosting-telegram-bota.ru

Вы всегда можете подсмотреть, где сейчас находитесь в помощью команды:

ls -l

Итак, зашли внутрь папки hosting-telegram-bota.ru

Внутри корневой директории


Теперь создадим папку .venv командой

mkdir .venv

Обновим pip командой

python3 -m pip install --upgrade pip 

Активируем виртуальное окружение. Сначала команда:

pip install pipenv

Затем

pipenv shell

Затем переходим в папку .venv

cd .venv

Выполняем

source bin/activate

Если посмотреть через менеджер файлов – то на хостинге у нас такая картина:

Создали папку с виртуальным окружением

и внутри папки .venv тоже кое-что появилось:

Продолжаем работу в консоли через Putty.

Нужно узнать путь к Python, который мы позже пропишем в настройках Flask. Выполните команду:

which python3 

и запишите куда-то путь, который вам покажет.

Путь к Python на веб хостинге

Например, что-то такое:

/home/h/<логин_к_хостингу>/hosting-telegram-bota.ru/.venv/bin/python3

Установим Flask.

python3 -m pip install flask 

Установим библиотеку Requests:

pip install requests

Также на этом этапе возможно вам потребуется установить библиотеки, необходимые для работы вашего бота. Тем более, что бот может быть написан с использованием разных вспомогательных фреймворков – Aiogram, Telebot и т.д.


Выйдем из папки .venv на уровень выше

cd ..

И начнем создавать структуру папок:

.
└── hosting-telegram-bota.ru
    ├── HelloFlask
    │   └── __init__.py
    ├── .htaccess
    ├── passenger_wsgi.py
    └── tmp
    └── .venv
    └── Pipfile
    └── public_html

Создаем две директории HelloFlask и tmp.

mkdir HelloFlask tmp

Теперь, если посмотреть через File Manager Beget, у нас такая структура папок внутри папки сайта “../hosting-telegram-bota.ru”

Структура папок Flask на хостинге HelloFlask

Также создаем 2 файла:

touch .htaccess
touch passenger_wsgi.py

Параллельно, если не уверенно себя чувствует с консолью, можно проверять изменения через файловый менеджер хостинга, не забываем кнопку “Обновить”, чтобы увидеть изменения.

За структурой папок и файлов можно следить через удобный файловый менеджер хостинга Бегет

Здесь же (в менеджере файлов Бегет) я открою файлы на редактирование.

Редактируем htaccess файл, чтобы запускалось приложение Flask

Сначала .htaccess

Прописываем путь к интерпретатору Python на хостинге

В файле .htaccess пишем следующие строки, где во второй – путь к нашему Python, который мы узнали ранее через команду which python3

PassengerEnabled On
PassengerPython /home/h/<логин_к_хостингу>/hosting-telegram-bota.ru/.venv/bin/python3

Теперь редактируем файл passenger_wsgi

# -*- coding: utf-8 -*-                                 
import sys, os

# указываем директорию с проектом 
sys.path.append('/home/<ваша_буква>/<логин_к_хостингу>/hosting-telegram-bota.ru/HelloFlask') 

# указываем директорию с библиотеками, куда поставили Flask
sys.path.append('/home/<ваша_буква>/<логин_к_хостингу>/.local/lib/python3.6/site-packages') 

from HelloFlask import app as application
# Когда Flask стартует, он ищет application. 
# Если не указать 'as application', сайт не заработает

from werkzeug.debug import DebuggedApplication
# Опционально: подключение модуля отладки 

application.wsgi_app = DebuggedApplication(application.wsgi_app, False)
# Опционально: включение модуля отадки

application.debug = False
# Опционально: True/False устанавливается по необходимости в отладке 
Редактирование passenger_wsgi чтобы Flask работал на хостинге Бегет.ру

Также я меняю для обоих файлов права на 644.

Меняем права доступа к файлам
Через панель хостинга изменяем атрибуты на чтение и выполнение файлов
Устанавливаем chmod 644

Переходим в папку HelloFlask

cd HelloFlask 

Создаём там файл __init__.py

touch __init__.py 

Открываем его на редактирование и пишем:

from flask import Flask
app = Flask(__name__)

@app.route('/python-bot/')
def hello_world(): 
    return 'Hello Flask!'

if __name__ == '__main__':
    app.run()

Обратите внимание, я задал route /python-bot/, который будет использован потом при добавлении вебхука для телеграм-бота.

Я задал route для приложения Flask, который потом использую для активации вебхука для телеграмм бота на хостинге

Сохраняем и также изменяем атрибуты доступа на 644.

Остались последние приготовления перед проверкой – запустилось ли наше Flask-приложение.

Возвращаемся в корневую директорию

cd ..

Выполняем последние команды:

ln -s public_html public

И запуск (ре-старт) Flask:

touch tmp/restart.txt

Эта команда (touch tmp/restart.txt) понадобится нам каждый раз, когда мы будем вносить какие-то изменения, чтобы перезапустить Flask.

Не забывайте выполнять ее, иначе изменения применяться не будут.

Также, не забывайте про права на файлы (chmod 644) и возможные другие проблемы. Важна каждая деталь, например, кодировка файлов.

Windows вместо Unix приведет к ошибке
Нам на хостинге нужен Unix
Правильная кодировка UTF-8

Теперь проверим – работает ли Flask. Откроем в браузере наш сайт на той странице, адрес которой указали в __init__.py.

Если всё OK, увидим “Hello Flask!”

Всё отлично, Flask запущен на хостинге Beget

Запускаем телеграм бота на хостинге

Ок, Flask работает. Теперь заменим код в файле __init__.py на код нашего бота.

Я сделал второго телеграмм бота, чтобы на хостинге у нас работал бот на Python с похожим функционалом, как и тот, что вначале был сделан на PHP.

Вот такой код я помещу в __init__.py

from flask import Flask, render_template
from flask import request
from flask import Response
import requests

TOKEN = "<токен бота>"
 
app = Flask(__name__, template_folder='../public_html')
 
def tel_parse_message(message):
    print("message-->",message)
    try:
        chat_id = message['message']['chat']['id']
        txt = message['message']['text']
        
        print("chat_id-->", chat_id)
        print("txt-->", txt)
 
        return chat_id,txt
    except:
        print("NO text found-->>")
 
def tel_send_message(chat_id, text):
    url = f'https://api.telegram.org/bot{TOKEN}/sendMessage'
    payload = {
                'chat_id': chat_id,
                'text': text
                }
   
    r = requests.post(url,json=payload)
 
    return r
 
def tel_send_image(chat_id):
    url = f'https://api.telegram.org/bot{TOKEN}/sendPhoto'
    payload = {
        'chat_id': chat_id,
        'photo': "https://hosting-telegram-bota.ru/pic/pss-python.jpg",
        'caption': "Жми /more"
    }
 
    r = requests.post(url, json=payload)
    return r
    
def tel_send_inlineurl(chat_id):
    url = f'https://api.telegram.org/bot{TOKEN}/sendMessage'
 
    payload = {
        'chat_id': chat_id,
        'text': "Добро пожаловать в бота!\nСделано на Python.\nВашему боту нужен хостинг с поддержкой:",
        'reply_markup': {
            "inline_keyboard": [
                [
                    {"text": "Python", "url": "https://hosting-telegram-bota.ru/python"},
                    {"text": "Node JS", "url": "https://hosting-telegram-bota.ru/"}
                ],
                [
                    {"text": "PHP", "url": "https://hosting-telegram-bota.ru/"},
                    {"text": "PHP - сила!", "url": "https://hosting-telegram-bota.ru/php-bot/PHP_power.jpg"}
                ]
            ]
        }
    }
 
    r = requests.post(url, json=payload)
    return r
 
@ app.route('/python-bot/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        msg = request.get_json()
        
        
        
        try:
            chat_id, txt = tel_parse_message(msg)
            if txt == "hi":
                tel_send_message(chat_id,"Hello, world!")
            elif txt == "/start":
                tel_send_image(chat_id)
            elif txt == "/more":
                tel_send_inlineurl(chat_id)
                
 
            else:
                tel_send_message(chat_id, 'from webhook')
        except:
            print("from index-->")
 
        return Response('ok', status=200)
    else:        
        return '<h1>Это страница-webhook для бота на Python, размещенного на хостинге Beget.</h1>'
        
        
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    return render_template('home.html')
    
    

 
if __name__ == '__main__':
    app.run(threaded=True)

После сохранения нового кода в init.py – не забываем перезапустить Фласк командой (зайдя на хостинг через SSH):

touch tmp/restart.txt

И также активировать webhook для бота, открыв в браузере:

https://api.telegram.org/bot<токен бота>/setWebhook?url=https://hosting-telegram-bota.ru/python-bot/
Webhook успешно установлен

Проверяем, открыв страницу бота в браузере, и видим ту надпись, которую мы задали для GET-запроса:

Для GET-запросов бот будет показывать простое сообщение

Проверяем как работает сам бот @hosting_telegram_bot

Проверяем - всё работает! Мы запустили бота на Python на обычном шаред хостинге!

Сервер для телеграмм бота Python

Вот так бот на Python может работать на обычном шаред-хостинге. Бесплатного тестового периода в 30 дней вполне хватит, чтобы поиграться-протестировать гипотезу, запустить MVP.
Конечно, боты бывают разной сложности и замысла. Возможно, все-таки понадобится аренда сервера для бота, которые у Beget тоже есть с хорошими конфигурациями.
Список с ценами за VPS/VDS – по ссылке.
А здесь короткое видео, как разместить бота на сервере от Бегет:

Недорогие серверы на Beget.

Перезапуск Flask через терминал Beget

Из панели управления хостингом доступен терминал, что позволяет удобно управлять проектом или перезапускать сервер Flask после внесения правок.
Терминал у Бегет находится слева в виде боковой вкладки:

Терминал Beget

Удобно, что скопировать команды в терминал можно с помощью обычного CTRL+C => CTRL+V. Также (если вы не знакомы с Linux) – стрелками “вверх-вниз” на клавиатуре можно листать историю команд (чтобы не набирать их заново).
При сворачивании терминал сохраняет историю команд, но если что-то зависло или не реагирует – можно закрыть-открыть новую вкладку:

Как работать с терминалом хостинга Бегет

Вот пример, как я перезапускаю Flask после каких-либо правок в теле страницы – например, в данном случае я добавил новую кнопку:

Перезапуск сервера Flask после внесения изменений

Если я оказался в неправильной директории и команда touch tmp/restart.txt не сработала – всегда можно посмотреть где мы с помощью команда ls -l

Ре-старт сервера Flask на хостинге

После перехода в папку с сайтом делаем ре-старт Фласка – и теперь все ок. На главной странице добавлена новая кнопка на статью про бота отслеживания подписок на канал:

Изменения в коде страницы видны только после перезапуска сервера Flask

Полезные ссылки

Бот для сбора статистики – откуда приходят подписчики в канал и для снижения цены привлечения подписчика.