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:
+194
-19
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user