Поэтому я решил реализовать простое, но любопытное решение. А именно — написать 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» — идентификатор процесса)Процесс автоматически запустится в фоном режиме. Перейдем в диалог с ботом и проверим, что всё работает, как надо:
С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
Снова проверим, что всё работает корректно:
По нажатию кнопки под сообщением бот должен повторять команду, от которой было прислано данное сообщение.
Вместо заключения
Безусловно, такой метод не претендует стать заменой классическим способам подключения, однако, он позволяет достаточно быстро узнать о состоянии сервера и отправить ему команды, не требующие сложного вывода.
Комментарии (20)
Ktulhy
15.03.2019 14:17Крайне желательно сделать проверку id пользователя, иначе — это огромная дыра в безопасности
MonkAlex
15.03.2019 14:23+3Зато хоть что-то будет в безопасности! (С)
На деле — очень странная идея, изобретать такой вот дикий костыль при куче готовых и вполне испытанных решений по доступу ~_~ZloyKishechnik
15.03.2019 20:12-2а какие еще есть доступы?
знаю webmin, vnc ну и стандартный ссш.
а еще? когда оторвало ссш или просто нет возможности к нему приконнектиться? можете для общего развития рассказать о тех, которые известны вам?
pavelpromin
15.03.2019 14:32Хмм. Это в давние времена, когда ssh-клиентов не было на Symbian (Nokia E5-00), а был лишь асечный клиент jimm,- делал такой на php через аську.
Но сегодня нет примерно не одной ситуации когда можно поставить телеграм, но нельзя ssh-клент. Причем для ssh (ну когда вдруг остался без своего телефона) можно использовать закрытый ключ с паролем и хранить его в любом месте интернета (почта, гуглдрайв, на сайте, ...)Blaine_Mono
15.03.2019 14:54Вообще есть ситуация когда openssh сервер бесполезен. Например домашний компьютер за NAT
gecube
15.03.2019 23:20Почему? Можно вывернуться и сделать обратный ssh туннель :-) вариантов масса — от dyndns до плясок с промежуточным узлом с внешним ip
jrthwk
15.03.2019 15:51Для ссш-клиента надо белый IP, с чем как бы совсем не так хорошо как хотелось бы…
зы А вообще для такого полуинтерактивного удаленного рулежа я бы вообще email использовал…pavelpromin
15.03.2019 15:58Если есть доступ к редактированию dns (dyndns-ы или api регистратора), то не нужен.
Просто, несмотря на кажущиеся плюсы, у предложенного(через телеграм) подхода есть также куча минусов. Например, что с интерактивным вводом?! или как послать ^C для прерывания команды?jrthwk
15.03.2019 16:33>Если есть доступ к редактированию dns (dyndns-ы или api регистратора), то не нужен.
Тащемта провайдеры стараются запихать всех за нат, чем тут редактирование днс поможет? Или я чего-то пропустил в мире сетей?
skymal4ik
15.03.2019 14:38Решение интересное, и может быть полезным для быстрого мониторинга/проверки.
Но я бы всё равно ограничил набор доступных команд через sudo и самим скриптом. И емейл бы посылал при подключении через бота. Ато вдруг утечёт доступ, а вы и не узнаете.
msa
15.03.2019 15:10Аналогичное решение, но без программирования, shell-команды задаются через командную строку — shell2telegram
tmnhy
15.03.2019 20:51Безусловно, такой метод не претендует стать заменой классическим способам подключения, однако, он позволяет ...
Однако он аналогичен такому методу развлечения, как «зажать яйца между дверью и коробкой, самому давить со всей силы на дверь и самому же кричать, как же больно».
tuxi
16.03.2019 10:36Если нам нужно иметь доступ к ограниченному списку операций, то задача сильно упрощается, телеграмм тут становится лишним звеном, достаточно простого браузера и доступ по урл содержащий хэш md5, который меняется (например) каждые сутки. Онлайн сервисов генерации MD5 в интернете много. Если MD5 указан верно, получаем доступ к нами написанной панельке с перечислением доступных команд и тп, данный hash привязывается к айпи, с другого айпи на него уже не зайти, даже если браузер сольет ссылку поисковой машине. Чем не решение?
immaculate
16.03.2019 10:46Для Android есть приложение JuiceSSH (есть еще несколько ssh клиентов, просто к этому уже привык). Генерируем или добавляем ключ, копируем его на все сервера сразу же. В JuiceSSH создаем записи для всех серверов (чтобы потом не вспоминать и не искать лихорадочно, какие же у них ip-адреса, и какое имя пользователя/ключ надо использовать).
Еще для Android есть приложение termux.
Для iOS есть свои аналоги, если не ошибаюсь.
Это во-первых, намного удобнее, чем костыль с телеграмом (как через телеграм конфиг редактировать? через
sed
?), во-вторых, надежнее и безопаснее.
Ну и код, даже несмотря на минимальный размер, имеет массу недостатков, начиная с банального несоблюдения PEP-8 и массы совершенно ненужных комментариев а-ля:
command = message.text #текст сообщения
Серьезно найдется человек, которому этот комментарий поможет разобраться в коде???
В общем, очередной велосипед с квадратными колесами (TM).
denaspireone
del