Доступ к linux серверу с помощью Telegram-бота на Python

Довольно часто происходят ситуации, когда доступ к серверу нужен здесь и сейчас. Однако, не всегда подключение по SSH является наиболее удобным способом, потому что под рукой может не оказаться SSH клиента, адреса сервера или связки «пользователь/пароль». Конечно, есть Webmin, который упрощает администрирование, но он также не даёт моментальный доступ.

Поэтому я решил реализовать простое, но любопытное решение. А именно — написать Telegram-бота, который, запускаясь на самом сервере, будет выполнять присылаемые ему команды и возвращать результат. Изучив несколько статей на эту тему, я понял, что подобных реализаций ещё никто не описывал.

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

Регистрация бота

Регистрируем нового бота у @BotFather. Отправляем ему /newbot и далее по тексту. Нам понадобятся токен нового бота и ваш id (получить его можно, например, у @userinfobot).

Подготовка питона

Для запуска бота будем использовать библиотеку telebot (pip install pytelegrambotapi). С помощью библиотеки subprocess будем выполнять команды на сервере.

Запуск бота

На сервере создаем файл bot.py:
nano bot.py

И вставляем в него код:

from subprocess import check_output
import telebot
import time

bot = telebot.TeleBot("XXXXXXXXX:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")#токен бота
user_id = 0 #id вашего аккаунта
@bot.message_handler(content_types=["text"])
def main(message):
   if (user_id == message.chat.id): #проверяем, что пишет именно владелец
      comand = message.text  #текст сообщения
      try: #если команда невыполняемая - check_output выдаст exception
         bot.send_message(message.chat.id, check_output(comand, shell = True))
      except:
         bot.send_message(message.chat.id, "Invalid input") #если команда некорректна
if __name__ == '__main__':
    while True:
        try:#добавляем try для бесперебойной работы
            bot.polling(none_stop=True)#запуск бота
        except:
            time.sleep(10)#в случае падения

Заменяем в нём токен бота на тот, который выдал @BotFather, и user_id — на значение id вашего аккаунта. Проверка id юзера нужна для того, чтобы бот предоставлял доступ к вашему серверу только вам. Функция check_output() выполняет переданную команду и возвращает результат.

Осталось только запустить бота. Для запуска процессов на сервере я предпочитаю использовать screen (sudo apt-get install screen):

screen -dmS ServerBot python3 bot.py

(где «ServerBot» — идентификатор процесса)

Процесс автоматически запустится в фоном режиме. Перейдем в диалог с ботом и проверим, что всё работает, как надо:

Доступ к linux серверу с помощью Telegram-бота на Python

Сongratulations! Бот выполняет присылаемые ему команды. Теперь, чтобы получить доступ к серверу, вам достаточно открыть диалог с ботом.

Повторение команд

Зачастую, для мониторинга состояния сервера приходится выполнять одни и те же команды. Поэтому реализация повтора команд без их повторного отправления будет очень к месту.

Реализовывать будем при помощи inline кнопок под сообщениями:

from subprocess import check_output
import telebot
from telebot import types #Добавляем импорт кнопок
import time

bot = telebot.TeleBot("XXXXXXXXX:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")#Токен бота
user_id = 0 #id вашего аккаунта
@bot.message_handler(content_types=["text"])
def main(message):
   if (user_id == message.chat.id): #проверяем, что пишет именно владелец
      comand = message.text  #текст сообщения
      markup = types.InlineKeyboardMarkup() #создаем клавиатуру
      button = types.InlineKeyboardButton(text="Повторить", callback_data=comand) #создаем кнопку
      markup.add(button) #добавляем кнопку в клавиатуру
      try: #если команда невыполняемая - check_output выдаст exception
         bot.send_message(user_id, check_output(comand, shell = True,  reply_markup = markup)) #вызываем команду и отправляем сообщение с результатом
      except:
         bot.send_message(user_id, "Invalid input") #если команда некорректна

@bot.callback_query_handler(func=lambda call: True)
def callback(call):
  comand = call.data #считываем команду из поля кнопки data
  try:#если команда не выполняемая - check_output выдаст exception
     markup = types.InlineKeyboardMarkup() #создаем клавиатуру
     button = types.InlineKeyboardButton(text="Повторить", callback_data=comand) #создаем кнопку и в data передаём команду
     markup.add(button) #добавляем кнопку в клавиатуру
     bot.send_message(user_id, check_output(comand, shell = True), reply_markup = markup) #вызываем команду и отправляем сообщение с результатом
  except:
     bot.send_message(user_id, "Invalid input") #если команда некорректна

if __name__ == '__main__':
    while True:
        try:#добавляем try для бесперебойной работы
            bot.polling(none_stop=True)#запуск бота
        except:
            time.sleep(10)#в случае падения

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

killall python3
screen -dmS ServerBot python3 bot.py

Снова проверим, что всё работает корректно:

Доступ к linux серверу с помощью Telegram-бота на Python

По нажатию кнопки под сообщением бот должен повторять команду, от которой было прислано данное сообщение.

Вместо заключения

Безусловно, такой метод не претендует стать заменой классическим способам подключения, однако, он позволяет достаточно быстро узнать о состоянии сервера и отправить ему команды, не требующие сложного вывода.

Источник: habr.com