v2.1: 3X-UI submenu with JSON guide and port, toggle clients with ok confirm and container restart

Made-with: Cursor
This commit is contained in:
anten-ka
2026-03-20 16:42:15 +03:00
parent 82b1a38592
commit 4ad1ac497e

244
warp.sh
View File

@@ -2,12 +2,12 @@
set -o pipefail set -o pipefail
# ══════════════════════════════════════════════════════════════ # ══════════════════════════════════════════════════════════════
# WARP Manager v2.0 — Unified 3X-UI + AmneziaWG # WARP Manager v2.1 — Unified 3X-UI + AmneziaWG
# Cloudflare WARP · Telegram Bot · Auto-detect mode # Cloudflare WARP · Telegram Bot · Auto-detect mode
# Channel: https://www.youtube.com/@antenkaru # Channel: https://www.youtube.com/@antenkaru
# ══════════════════════════════════════════════════════════════ # ══════════════════════════════════════════════════════════════
WARP_VERSION="2.0" WARP_VERSION="2.1"
WARP_DIR="/etc/warp-manager" WARP_DIR="/etc/warp-manager"
WARP_CONF="$WARP_DIR/config" WARP_CONF="$WARP_DIR/config"
WARP_LOG="/var/log/warp-manager.log" WARP_LOG="/var/log/warp-manager.log"
@@ -283,7 +283,7 @@ install_warp_3xui() {
else else
echo -e "${YELLOW} ⚠ Подключение не подтверждено.${NC}" echo -e "${YELLOW} ⚠ Подключение не подтверждено.${NC}"
fi fi
echo -e "\n${WHITE}Настройки SOCKS5 и JSON: пункт меню ${YELLOW}6${NC}" echo -e "\n${WHITE}Настройка 3X-UI: п.${YELLOW}6${WHITE} (JSON, инструкция, порт)${NC}"
read -p "Enter..." read -p "Enter..."
} }
@@ -341,27 +341,105 @@ change_port_3xui() {
log_action "3XUI PORT: ${np}"; read -p "Enter..." log_action "3XUI PORT: ${np}"; read -p "Enter..."
} }
show_xui_json() { show_3xui_menu() {
clear; echo -e "\n${CYAN}━━━ Конфигурация для 3X-UI ━━━${NC}\n" while true; do
echo -e "${GREEN}── Outbound ──${NC}\n" clear
echo -e "\n${CYAN}━━━ Настройки SOCKS5 для 3X-UI ━━━${NC}\n"
echo -e " ${WHITE}SOCKS5-прокси:${NC} ${GREEN}127.0.0.1:${SOCKS_PORT}${NC}"
if is_warp_running_3xui; then
echo -e " ${WHITE}WARP IP:${NC} ${GREEN}$(get_warp_ip_3xui)${NC}"
fi
echo -e "\n 1) 📋 Показать JSON Outbound и Routing"
echo -e " 2) 📖 Пошаговая инструкция для 3X-UI"
echo -e " 3) 🔧 Изменить порт SOCKS5 (сейчас: ${SOCKS_PORT})"
echo -e " 0) ⬅️ Назад"
echo ""
read -p " Выбор: " ch
case $ch in
1) show_3xui_json ;;
2) show_3xui_guide ;;
3) change_port_3xui ;;
0) return ;;
esac
done
}
show_3xui_json() {
clear; echo -e "\n${CYAN}━━━ JSON для 3X-UI ━━━${NC}\n"
echo -e "${WHITE}Добавьте в ${YELLOW}Xray Settings → Outbounds${WHITE} (JSON):${NC}\n"
echo -e "${GREEN}── 1. Outbound (добавить в массив outbounds) ──${NC}\n"
cat <<EOF cat <<EOF
{ {
"tag": "warp", "tag": "warp",
"protocol": "socks", "protocol": "socks",
"settings": { "settings": {
"servers": [{"address": "127.0.0.1", "port": ${SOCKS_PORT}}] "servers": [
{
"address": "127.0.0.1",
"port": ${SOCKS_PORT}
}
]
} }
} }
EOF EOF
echo -e "\n${GREEN}── Routing Rule ──${NC}\n"
echo -e "\n${GREEN}── 2. Routing Rule (маршруты через WARP) ──${NC}\n"
echo -e "${WHITE}Только определённые сайты через WARP:${NC}\n"
cat <<EOF cat <<EOF
{ {
"outboundTag": "warp", "outboundTag": "warp",
"domain": ["geosite:openai","geosite:netflix","geosite:disney","geosite:spotify","domain:claude.ai"] "domain": [
"geosite:openai",
"geosite:netflix",
"geosite:disney",
"geosite:spotify",
"domain:chat.openai.com",
"domain:claude.ai"
]
} }
EOF EOF
echo -e "\n${WHITE}SOCKS5: ${GREEN}127.0.0.1:${SOCKS_PORT}${NC}"
is_warp_running_3xui && echo -e "${WHITE}WARP IP: ${GREEN}$(get_warp_ip_3xui)${NC}" echo -e "\n${WHITE}Весь трафик через WARP:${NC}\n"
cat <<EOF
{
"outboundTag": "warp",
"network": "tcp,udp"
}
EOF
echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e " ${WHITE}SOCKS5:${NC} ${GREEN}127.0.0.1:${SOCKS_PORT}${NC}"
if is_warp_running_3xui; then
echo -e " ${WHITE}WARP IP:${NC} ${GREEN}$(get_warp_ip_3xui)${NC}"
fi
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""; read -p "Enter..."
}
show_3xui_guide() {
clear; echo -e "\n${CYAN}━━━ Пошаговая настройка 3X-UI ━━━${NC}\n"
echo -e "${YELLOW}Шаг 1.${NC} Откройте панель 3X-UI в браузере"
echo -e "${YELLOW}Шаг 2.${NC} Перейдите в ${WHITE}Настройки Xray${NC} (Xray Settings)"
echo -e "${YELLOW}Шаг 3.${NC} В разделе ${WHITE}Outbounds${NC} нажмите ${GREEN}Добавить${NC}"
echo -e "${YELLOW}Шаг 4.${NC} Вставьте JSON outbound (пункт 1 в меню)"
echo -e ""
echo -e "${WHITE} Outbound JSON (компактно):${NC}"
echo -e " ${GREEN}{\"tag\":\"warp\",\"protocol\":\"socks\",\"settings\":{\"servers\":[{\"address\":\"127.0.0.1\",\"port\":${SOCKS_PORT}}]}}${NC}"
echo -e ""
echo -e "${YELLOW}Шаг 5.${NC} В разделе ${WHITE}Routing${NC} добавьте правило:"
echo -e " ${WHITE}Outbound Tag:${NC} ${GREEN}warp${NC}"
echo -e " ${WHITE}Domain:${NC} ${GREEN}geosite:openai, geosite:netflix, domain:claude.ai${NC}"
echo -e ""
echo -e "${YELLOW}Шаг 6.${NC} Нажмите ${WHITE}Сохранить${NC} и ${WHITE}Перезапустить Xray${NC}"
echo -e " Или в SSH: ${GREEN}x-ui restart${NC}"
echo -e ""
echo -e "${YELLOW}Шаг 7.${NC} Проверьте:"
echo -e " Подключитесь к VPN → откройте ${CYAN}https://whoer.net${NC}"
echo -e " Сайты из списка покажут ${GREEN}IP Cloudflare${NC}"
echo -e " Остальные — ${WHITE}IP вашего сервера${NC}"
echo -e ""
echo -e "${CYAN}Проверка через SSH:${NC}"
echo -e " ${GREEN}curl -s --proxy socks5h://127.0.0.1:${SOCKS_PORT} ifconfig.me${NC}"
echo ""; read -p "Enter..." echo ""; read -p "Enter..."
} }
@@ -835,70 +913,85 @@ awg_get_client_ips() {
} }
awg_toggle_clients_ssh() { awg_toggle_clients_ssh() {
awg_get_client_ips; awg_parse_clients_table; awg_load_clients
if [ ${#AWG_CLIENT_IPS[@]} -eq 0 ]; then
echo -e "\n ${RED}Нет клиентов в конфиге VPN.${NC}"
read -p "Enter..."; return
fi
local -a pending_ips=()
for ip in "${AWG_SELECTED_IPS[@]}"; do pending_ips+=("$ip"); done
while true; do while true; do
awg_get_client_ips; awg_parse_clients_table; awg_load_clients local pending_set=" ${pending_ips[*]+"${pending_ips[*]}"} "
local warp_set=" ${AWG_SELECTED_IPS[*]+"${AWG_SELECTED_IPS[*]}"} " clear; echo -e "\n${CYAN}━━━ Управление клиентами WARP ━━━${NC}\n"
echo -e " ${DIM}Нажмите номер чтобы вкл/выкл WARP для клиента${NC}\n"
clear; echo -e "\n${CYAN}━━━ Клиенты WARP ━━━${NC}\n"
if [ ${#AWG_CLIENT_IPS[@]} -eq 0 ]; then
echo -e " ${RED}Нет клиентов в конфиге VPN.${NC}"
read -p "Enter..."; return
fi
local i=1 warp_count=0 local i=1 warp_count=0
for ip in "${AWG_CLIENT_IPS[@]}"; do for ip in "${AWG_CLIENT_IPS[@]}"; do
local label; label=$(awg_format_label "$ip") local label; label=$(awg_format_label "$ip")
if [[ "$warp_set" == *" $ip "* ]]; then if [[ "$pending_set" == *" $ip "* ]]; then
echo -e " ${GREEN}$i) ✅ $label${NC}" echo -e " ${GREEN} $i) ✅ $label${NC}"
((warp_count++)) ((warp_count++))
else else
echo -e " $i)$label" echo -e " ${WHITE} $i)${NC} $label"
fi fi
((i++)) ((i++))
done done
echo "" echo ""
echo -e " ${WHITE}В WARP: ${CYAN}${warp_count}${NC} из ${#AWG_CLIENT_IPS[@]}" echo -e " ${WHITE}Через WARP: ${CYAN}${warp_count}${NC} из ${#AWG_CLIENT_IPS[@]}"
echo -e "${CYAN}──────────────────────────────────────────────────────${NC}"
echo -e " ${GREEN}all${NC}) Включить всех ${YELLOW}none${NC}) Выключить всех"
echo -e " ${GREEN}ok${NC}) Применить ${DIM}0${NC}) Отмена (без изменений)"
echo "" echo ""
echo -e " ${DIM}Введите номер для переключения (через запятую)${NC}" read -p " > " answer
echo -e " ${DIM}all) все в WARP | none) убрать всех | 0) назад${NC}"
echo ""
read -p " Выбор: " answer
[ -z "$answer" ] || [ "$answer" = "0" ] && return case "$answer" in
0|"")
local changed=0 return ;;
if [ "$answer" = "all" ]; then all)
AWG_SELECTED_IPS=("${AWG_CLIENT_IPS[@]}") pending_ips=("${AWG_CLIENT_IPS[@]}") ;;
changed=1 none)
elif [ "$answer" = "none" ]; then pending_ips=() ;;
AWG_SELECTED_IPS=() ok)
changed=1 AWG_SELECTED_IPS=("${pending_ips[@]+"${pending_ips[@]}"}")
else echo -e "\n${YELLOW} Применяю правила...${NC}"
IFS=',' read -ra parts <<< "$answer" awg_save_clients; awg_apply_rules; awg_patch_start_sh
for p in "${parts[@]}"; do echo -e "${GREEN} ✓ Правила сохранены${NC}"
p=$(echo "$p" | xargs) echo -e "\n${YELLOW} Перезапуск контейнера ${CONTAINER}...${NC}"
if [[ "$p" =~ ^[0-9]+$ ]] && (( p >= 1 && p <= ${#AWG_CLIENT_IPS[@]} )); then docker restart "$CONTAINER" >/dev/null 2>&1
local ip="${AWG_CLIENT_IPS[$((p-1))]}" local a=0
if [[ "$warp_set" == *" $ip "* ]]; then while [ "$a" -lt 15 ]; do
local -a tmp=() docker exec "$CONTAINER" sh -c "true" 2>/dev/null && break
for eip in "${AWG_SELECTED_IPS[@]}"; do sleep 1; ((a++))
[ "$eip" != "$ip" ] && tmp+=("$eip") done
done if docker exec "$CONTAINER" sh -c "true" 2>/dev/null; then
AWG_SELECTED_IPS=("${tmp[@]+"${tmp[@]}"}") echo -e "${GREEN} ✓ Контейнер перезапущен${NC}"
else else
AWG_SELECTED_IPS+=("$ip") echo -e "${RED} ⚠ Контейнер не отвечает${NC}"
fi
changed=1
fi fi
done log_action "AWG CLIENTS APPLIED: ${#AWG_SELECTED_IPS[@]} in WARP, container restarted"
fi read -p " Enter..."; return ;;
*)
if [ "$changed" -eq 1 ]; then IFS=',' read -ra parts <<< "$answer"
awg_save_clients; awg_apply_rules; awg_patch_start_sh for p in "${parts[@]}"; do
log_action "AWG TOGGLE: ${#AWG_SELECTED_IPS[@]} clients in WARP" p=$(echo "$p" | xargs)
fi if [[ "$p" =~ ^[0-9]+$ ]] && (( p >= 1 && p <= ${#AWG_CLIENT_IPS[@]} )); then
local ip="${AWG_CLIENT_IPS[$((p-1))]}"
if [[ "$pending_set" == *" $ip "* ]]; then
local -a tmp=()
for eip in "${pending_ips[@]}"; do
[ "$eip" != "$ip" ] && tmp+=("$eip")
done
pending_ips=("${tmp[@]+"${tmp[@]}"}")
else
pending_ips+=("$ip")
fi
fi
done ;;
esac
done done
} }
@@ -1080,8 +1173,7 @@ kbd_main_awg() {
[{"text":"📊 Статус","callback_data":"st"},{"text":"🌐 IP","callback_data":"ip"}], [{"text":"📊 Статус","callback_data":"st"},{"text":"🌐 IP","callback_data":"ip"}],
[{"text":"▶️ Запустить","callback_data":"on"},{"text":"⏹ Остановить","callback_data":"off"}], [{"text":"▶️ Запустить","callback_data":"on"},{"text":"⏹ Остановить","callback_data":"off"}],
[{"text":"🔑 Перевыпуск","callback_data":"rk"}], [{"text":"🔑 Перевыпуск","callback_data":"rk"}],
[{"text":"👥 Клиенты WARP","callback_data":"cl"}], [{"text":"👥 Клиенты WARP","callback_data":"cl"},{"text":"🔄 Контейнер","callback_data":"rc"}],
[{"text":"🔄 Контейнер","callback_data":"rc"}],
[{"text":"💻 Система","callback_data":"sys"}], [{"text":"💻 Система","callback_data":"sys"}],
[{"text":"🏢 Хостинг","callback_data":"promo"}] [{"text":"🏢 Хостинг","callback_data":"promo"}]
] ]
@@ -1274,7 +1366,10 @@ bot_handle_callback() {
fi fi
fi fi
awg_save_clients; awg_apply_rules; awg_patch_start_sh awg_save_clients; awg_apply_rules; awg_patch_start_sh
log_action "BOT AWG TOGGLE: ${#AWG_SELECTED_IPS[@]}" tg_edit "$chat_id" "$msg_id" "⏳ Применяю и перезапускаю контейнер..." ""
docker restart "$CONTAINER" >/dev/null 2>&1
local _a=0; while [ "$_a" -lt 15 ]; do docker exec "$CONTAINER" sh -c "true" 2>/dev/null && break; sleep 1; ((_a++)); done
log_action "BOT AWG TOGGLE: ${#AWG_SELECTED_IPS[@]}, container restarted"
bot_handle_callback "$chat_id" "$msg_id" "" "cl" ;; bot_handle_callback "$chat_id" "$msg_id" "" "cl" ;;
rc) rc)
@@ -1530,23 +1625,21 @@ show_menu() {
if [ "$MODE" = "3xui" ]; then if [ "$MODE" = "3xui" ]; then
echo -e "\n${CYAN}── 3X-UI ──────────────────────────────────────────────${NC}" echo -e "\n${CYAN}── 3X-UI ──────────────────────────────────────────────${NC}"
echo -e " 6) 📋 ${CYAN}Настройки SOCKS5 / JSON для 3X-UI${NC}" echo -e " 6) 📋 ${CYAN}Настройки SOCKS5 / JSON / Инструкция${NC}"
echo -e " 7) 🔧 ${WHITE}Изменить порт SOCKS5${NC}"
fi fi
if [ "$MODE" = "amnezia" ]; then if [ "$MODE" = "amnezia" ]; then
echo -e "\n${CYAN}── AmneziaWG ──────────────────────────────────────────${NC}" echo -e "\n${CYAN}── AmneziaWG ──────────────────────────────────────────${NC}"
echo -e " 6) 👥 ${GREEN}Управление клиентами WARP${NC}" echo -e " 6) 👥 ${GREEN}Управление клиентами WARP${NC}"
echo -e " 7) 🔄 ${CYAN}Перезапуск контейнера${NC}"
fi fi
echo -e "\n${CYAN}── Telegram-бот ───────────────────────────────────────${NC}" echo -e "\n${CYAN}── Telegram-бот ───────────────────────────────────────${NC}"
echo -e " 8) 🤖 ${CYAN}Настройка и управление ботом${NC}" echo -e " 7) 🤖 ${CYAN}Настройка и управление ботом${NC}"
echo -e "\n${CYAN}── Прочее ─────────────────────────────────────────────${NC}" echo -e "\n${CYAN}── Прочее ─────────────────────────────────────────────${NC}"
echo -e " 9) ${YELLOW}PROMO${NC}" echo -e " 8) ${YELLOW}PROMO${NC}"
echo -e " 10) ${MAGENTA}📚 Инструкция${NC}" echo -e " 9) ${MAGENTA}📚 Инструкция${NC}"
echo -e " 11) ${RED}⚠ Полное удаление${NC}" echo -e " 10) ${RED}⚠ Полное удаление${NC}"
echo -e " 0) Выход" echo -e " 0) Выход"
echo -e "${CYAN}──────────────────────────────────────────────────────${NC}" echo -e "${CYAN}──────────────────────────────────────────────────────${NC}"
read -p " Выбор: " ch read -p " Выбор: " ch
@@ -1557,12 +1650,11 @@ show_menu() {
3) if [ "$MODE" = "3xui" ]; then stop_warp_3xui; else stop_warp_awg; fi ;; 3) if [ "$MODE" = "3xui" ]; then stop_warp_3xui; else stop_warp_awg; fi ;;
4) if [ "$MODE" = "3xui" ]; then show_status_3xui; else show_status_awg; fi ;; 4) if [ "$MODE" = "3xui" ]; then show_status_3xui; else show_status_awg; fi ;;
5) if [ "$MODE" = "3xui" ]; then rekey_warp_3xui; else rekey_warp_awg; fi ;; 5) if [ "$MODE" = "3xui" ]; then rekey_warp_3xui; else rekey_warp_awg; fi ;;
6) if [ "$MODE" = "3xui" ]; then show_xui_json; else awg_toggle_clients_ssh; fi ;; 6) if [ "$MODE" = "3xui" ]; then show_3xui_menu; else awg_toggle_clients_ssh; fi ;;
7) if [ "$MODE" = "3xui" ]; then change_port_3xui; else awg_restart_container; fi ;; 7) bot_menu ;;
8) bot_menu ;; 8) show_promo ;;
9) show_promo ;; 9) show_info ;;
10) show_info ;; 10) full_uninstall ;;
11) full_uninstall ;;
0) exit 0 ;; 0) exit 0 ;;
esac esac
done done