version 1.2: Telegram-бот, мониторинг сервера на дашборде, README

- bot.py: Telegram-бот (/users, /create, /delete, /warp, /stats, /dashboard)
- install-bot.sh: установщик бота (systemd, конфиг /etc/mita/bot.json)
- app.py: API /api/bot/{status,install,uninstall,config}, /api/stats (CPU/RAM/диск)
- templates: раздел «Telegram бот» в UI, мониторинг CPU/RAM/диск на дашборде (2s auto-refresh)
- mita-ctl.sh: пункт 11 «Telegram-бот», удаление бота в полном uninstall
- install.sh: опциональная установка бота с инструкцией
- README.md: описание проекта и дорожная карта
This commit is contained in:
2026-06-26 23:37:05 +03:00
parent d65f80cf9e
commit 33bdcdce68
9 changed files with 1432 additions and 49 deletions
+194 -19
View File
@@ -76,6 +76,7 @@ main_menu() {
echo -e " ${BOLD}8.${NC} Рекомендации по безопасности VPS"
echo -e " ${RED}${BOLD}9.${NC} ${RED}Полное удаление mita, панели и WARP${NC}"
echo -e " ${BOLD}10.${NC} Показать текущую конфигурацию"
echo -e " ${BOLD}11.${NC} Управление Telegram-ботом"
echo -e " ${BOLD}0.${NC} Выход"
echo ""
read -r -p " Выберите пункт: " choice
@@ -90,6 +91,7 @@ main_menu() {
8) menu_security ;;
9) menu_uninstall ;;
10) menu_show_config ;;
11) menu_bot ;;
0) exit 0 ;;
*) warn "Неверный выбор" ;;
esac
@@ -332,16 +334,30 @@ print(b.get('portRange',b.get('port','2100-2110')))
_fw_open() {
local port="$1" proto="${2:-tcp}"
command -v ufw &>/dev/null && ufw status | grep -q "Status: active" \
&& ufw allow "$port/$proto" 2>/dev/null || true
iptables -I INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null || true
if [[ "$port" == *"-"* ]]; then
local _s="${port%-*}" _e="${port#*-}"
command -v ufw &>/dev/null && ufw status | grep -q "Status: active" \
&& ufw allow "${_s}:${_e}/${proto}" 2>/dev/null || true
iptables -I INPUT -p "$proto" --dport "${_s}:${_e}" -j ACCEPT 2>/dev/null || true
else
command -v ufw &>/dev/null && ufw status | grep -q "Status: active" \
&& ufw allow "${port}/${proto}" 2>/dev/null || true
iptables -I INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null || true
fi
}
_fw_close() {
local port="$1" proto="${2:-tcp}"
command -v ufw &>/dev/null && ufw status | grep -q "Status: active" \
&& ufw delete allow "$port/$proto" 2>/dev/null || true
iptables -D INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null || true
if [[ "$port" == *"-"* ]]; then
local _s="${port%-*}" _e="${port#*-}"
command -v ufw &>/dev/null && ufw status | grep -q "Status: active" \
&& ufw delete allow "${_s}:${_e}/${proto}" 2>/dev/null || true
iptables -D INPUT -p "$proto" --dport "${_s}:${_e}" -j ACCEPT 2>/dev/null || true
else
command -v ufw &>/dev/null && ufw status | grep -q "Status: active" \
&& ufw delete allow "${port}/${proto}" 2>/dev/null || true
iptables -D INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null || true
fi
}
# ════════════════════════════════════════════════════════════════════════════
@@ -1030,7 +1046,7 @@ with open('$PANEL_CONFIG','w') as f: json.dump(d,f,indent=2)
mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d
cat > /etc/fail2ban/filter.d/mita-panel.conf << EOF
[Definition]
failregex = ^.*"POST /[^"]+/login[^"]*" 4(01|29).*$
failregex = ^<HOST> .+ "POST /[^"]+/login[^"]*" 4(?:01|29).*$
ignoreregex =
EOF
cat > /etc/fail2ban/jail.d/mita-panel.conf << EOF
@@ -1042,10 +1058,12 @@ logpath = /var/log/mita-panel-access.log
maxretry = $max_retry
bantime = $ban_time
findtime = $ban_time
action = iptables-multiport[name=mita-panel, port="http,https,8080,8443", protocol=tcp]
EOF
systemctl restart fail2ban 2>/dev/null || true
ok "fail2ban настроен: $max_retry попыток / ${ban_time}с"
if systemctl restart fail2ban 2>/dev/null && systemctl is-active --quiet fail2ban; then
ok "fail2ban настроен и запущен: $max_retry попыток / ${ban_time}с"
else
warn "fail2ban настроен, но не запустился. Проверьте: journalctl -u fail2ban -n 20"
fi
else
warn "fail2ban не установлен — лимиты сохранены только в panel.json"
fi
@@ -1055,6 +1073,141 @@ EOF
ok "Настройки применены. Попыток: $max_retry, бан: ${ban_time}с"
}
# ════════════════════════════════════════════════════════════════════════════
# 11. TELEGRAM БОТ
# ════════════════════════════════════════════════════════════════════════════
menu_bot() {
section "Управление Telegram-ботом"
BOT_SERVICE="mita-bot"
BOT_DIR="/opt/mita-bot"
BOT_CONFIG="/etc/mita/bot.json"
local installed=false running=false
if [[ -f "/etc/systemd/system/${BOT_SERVICE}.service" ]]; then
installed=true
systemctl is-active --quiet "$BOT_SERVICE" && running=true
fi
echo ""
if $installed; then
echo -e " Статус: ${GREEN}● Установлен${NC}"
if $running; then
echo -e " Состояние: ${GREEN}● Активен${NC}"
else
echo -e " Состояние: ${RED}● Остановлен${NC}"
fi
if [[ -f "$BOT_CONFIG" ]]; then
local token
token=$(python3 -c "import json; d=json.load(open('$BOT_CONFIG')); print(d.get('token','')[:8]+'…')" 2>/dev/null || echo "—")
echo -e " Токен: ${YELLOW}${token}${NC}"
local admins
admins=$(python3 -c "import json; d=json.load(open('$BOT_CONFIG')); print(', '.join(d.get('admin_ids',[])))" 2>/dev/null || echo "—")
echo -e " Админы ID: ${YELLOW}${admins}${NC}"
fi
else
echo -e " Статус: ${YELLOW}● Не установлен${NC}"
fi
echo ""
echo -e " ${BOLD}1.${NC} Установить / обновить бота"
echo -e " ${BOLD}2.${NC} Перезапустить бота"
echo -e " ${BOLD}3.${NC} Добавить админа (Telegram ID)"
echo -e " ${BOLD}4.${NC} Логи бота (journalctl)"
if $installed; then
echo -e " ${RED}${BOLD}5.${NC} ${RED}Удалить бота${NC}"
fi
echo -e " ${BOLD}0.${NC} Назад"
echo ""
read -r -p " Выбор: " choice
case "$choice" in
1) _bot_install ;;
2) _bot_restart ;;
3) _bot_add_admin ;;
4) journalctl -u "$BOT_SERVICE" -f --no-pager -n 50 ;;
5)
if $installed; then
read -r -p " Точно удалить бота? [y/N]: " del
if [[ "${del,,}" == "y" ]]; then
_bot_uninstall
fi
fi
;;
esac
}
_bot_install() {
section "Установка Telegram-бота"
local installer=""
for candidate in /opt/mita-panel/install-bot.sh "$SCRIPT_DIR/install-bot.sh"; do
[[ -f "$candidate" ]] && { installer="$candidate"; break; }
done
if [[ -z "$installer" ]]; then
error "install-bot.sh не найден. Поместите его в /opt/mita-panel/"
pause
return
fi
read -r -p "Токен бота (от @BotFather): " token
[[ -z "$token" ]] && { error "Токен обязателен"; return; }
read -r -p "Ваш Telegram ID (число, @userinfobot): " admin_id
[[ -z "$admin_id" || ! "$admin_id" =~ ^[0-9]+$ ]] && { error "ID должен быть числом"; return; }
BOT_TOKEN_NONINTERACTIVE="$token" BOT_ADMIN_NONINTERACTIVE="$admin_id" bash "$installer"
pause
}
_bot_restart() {
section "Перезапуск бота"
BOT_SERVICE="mita-bot"
systemctl restart "$BOT_SERVICE" 2>/dev/null || true
sleep 1
if systemctl is-active --quiet "$BOT_SERVICE"; then
ok "Бот перезапущен"
else
warn "Бот не запустился. Проверьте: journalctl -u $BOT_SERVICE -f"
fi
pause
}
_bot_add_admin() {
section "Добавление админа"
BOT_CONFIG="/etc/mita/bot.json"
[[ ! -f "$BOT_CONFIG" ]] && { error "Бот не установлен"; return; }
read -r -p "Telegram ID нового админа (число): " new_id
[[ -z "$new_id" || ! "$new_id" =~ ^[0-9]+$ ]] && { error "ID должен быть числом"; return; }
python3 -c "
import json
with open('$BOT_CONFIG') as f: d=json.load(f)
ids=d.get('admin_ids',[])
if '$new_id' not in ids: ids.append('$new_id')
d['admin_ids']=ids
with open('$BOT_CONFIG','w') as f: json.dump(d,f,indent=2)
"
systemctl restart mita-bot 2>/dev/null || true
ok "Админ $new_id добавлен"
pause
}
_bot_uninstall() {
section "Удаление Telegram-бота"
BOT_SERVICE="mita-bot"
systemctl stop "$BOT_SERVICE" 2>/dev/null || true
systemctl disable "$BOT_SERVICE" 2>/dev/null || true
rm -f "/etc/systemd/system/${BOT_SERVICE}.service"
systemctl daemon-reload 2>/dev/null || true
rm -rf /opt/mita-bot
rm -f /etc/mita/bot.json
ok "Бот удалён"
pause
}
# ════════════════════════════════════════════════════════════════════════════
# 9. ПОЛНОЕ УДАЛЕНИЕ
# ════════════════════════════════════════════════════════════════════════════
@@ -1070,6 +1223,7 @@ menu_uninstall() {
echo -e " ${YELLOW}${NC} mita сервер (бинарник, systemd unit, конфиги)"
echo -e " ${YELLOW}${NC} Веб-панель (/opt/mita-panel, systemd unit)"
echo -e " ${YELLOW}${NC} Cloudflare WARP (Docker-контейнер)"
echo -e " ${YELLOW}${NC} Telegram-бот (/opt/mita-bot, systemd unit)"
echo -e " ${YELLOW}${NC} Все пользователи и пароли (/etc/mita/)"
echo -e " ${YELLOW}${NC} SSL-сертификаты, выпущенные для панели"
echo -e " ${YELLOW}${NC} Правила fail2ban для панели"
@@ -1200,12 +1354,30 @@ except: print('2100-2110')
rm -f /usr/local/bin/mita-update-lists
ok "Cron-задачи удалены"
# ── 7a. Удалить Telegram-бота ────────────────────────────────────
if [[ -f "/etc/systemd/system/mita-bot.service" ]]; then
info "Удаление Telegram-бота..."
systemctl stop mita-bot 2>/dev/null || true
systemctl disable mita-bot 2>/dev/null || true
rm -f /etc/systemd/system/mita-bot.service
systemctl daemon-reload 2>/dev/null || true
rm -rf /opt/mita-bot
rm -f /etc/mita/bot.json
ok "Telegram-бот удалён"
fi
# ── 8. Закрыть порты в firewall ────────────────────────────────
info "Закрытие портов mita ($_MITA_RANGE) и панели ($_PANEL_PORT) в firewall..."
info "SSH порт $_SSH_PORT остаётся открытым."
info "SSH порт $_SSH_PORT будет явно сохранён открытым."
_UFW_ACTIVE=false
command -v ufw &>/dev/null && ufw status 2>/dev/null | grep -q "Status: active" && _UFW_ACTIVE=true
# ---- UFW ----
if command -v ufw &>/dev/null && ufw status 2>/dev/null | grep -q "Status: active"; then
if $_UFW_ACTIVE; then
# Сначала явно гарантируем SSH, ПОТОМ удаляем остальные правила
ufw allow "$_SSH_PORT/tcp" comment "SSH" 2>/dev/null || true
# Удаляем правило mita (диапазон или одиночный порт)
if [[ "$_MITA_RANGE" == *"-"* ]]; then
_SP="${_MITA_RANGE%-*}"; _EP="${_MITA_RANGE#*-}"
@@ -1218,14 +1390,14 @@ except: print('2100-2110')
# Удаляем правило панели
ufw delete allow "$_PANEL_PORT/tcp" 2>/dev/null || true
# Дополнительно: чистим правила по комментарию (совместимость с разными версиями)
ufw status numbered 2>/dev/null | { grep -iE "mita|panel" || true; } | awk -F'[][]' '{print $2}' | sort -rn | while read -r num; do
ufw status numbered 2>/dev/null | { grep -iE "mita|panel" || true; } | awk -F'[][]' '{gsub(/[[:space:]]/, "", $2); print $2}' | sort -rn | while read -r num; do
[[ -n "$num" ]] && yes | ufw delete "$num" 2>/dev/null || true
done
ok "UFW: правила удалены"
ok "UFW: правила удалены, SSH ($_SSH_PORT) сохранён"
fi
# ---- iptables ----
if command -v iptables &>/dev/null; then
# ---- iptables (только когда UFW не управляет firewall) ----
if ! $_UFW_ACTIVE && command -v iptables &>/dev/null; then
if [[ "$_MITA_RANGE" == *"-"* ]]; then
_SP="${_MITA_RANGE%-*}"; _EP="${_MITA_RANGE#*-}"
iptables -D INPUT -p tcp --dport "${_SP}:${_EP}" -j ACCEPT 2>/dev/null || true
@@ -1235,12 +1407,15 @@ except: print('2100-2110')
iptables -D INPUT -p udp --dport "$_MITA_RANGE" -j ACCEPT 2>/dev/null || true
fi
iptables -D INPUT -p tcp --dport "$_PANEL_PORT" -j ACCEPT 2>/dev/null || true
# Сохраняем правила если есть iptables-save
# Явно обеспечиваем SSH-правило первым в цепочке
iptables -D INPUT -p tcp --dport "$_SSH_PORT" -j ACCEPT 2>/dev/null || true
iptables -I INPUT 1 -p tcp --dport "$_SSH_PORT" -j ACCEPT 2>/dev/null || true
# Сохраняем правила
command -v iptables-save &>/dev/null && iptables-save > /etc/iptables/rules.v4 2>/dev/null || true
ok "iptables: правила удалены"
ok "iptables: правила удалены, SSH ($_SSH_PORT) сохранён"
fi
ok "Firewall: порты mita и панели закрыты. SSH ($_SSH_PORT) не тронут."
ok "Firewall: порты mita и панели закрыты. SSH ($_SSH_PORT) открыт."
systemctl daemon-reload 2>/dev/null || true