Files
swiftgram/install.sh
2026-04-05 23:34:33 +03:00

312 lines
15 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 🚀 SwiftGram MTProxy — Полнофункциональный менеджер
# Исправлено: Возврат к стандартной сетевой модели Docker для 100% доступности.
# ── Настройки репозитория ────────────────────────────────────────────────────
REPO_RAW_URL="https://git.bargcraft.top/kobalt/swiftgram/raw/branch/main"
# ── Цвета ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
MAGENTA='\033[0;35m'
BLUE='\033[0;34m'
WHITE='\033[1;37m'
NC='\033[0m'
# ── Конфиг ───────────────────────────────────────────────────────────────────
CONTAINER_NAME="swiftgram-proxy"
BOT_DIR="/opt/swiftgram"
SERVICE_NAME="swiftgram-bot"
# ── Спиннер и прогресс-бар ────────────────────────────────────────────────────
spin_pid=""
spinner_start() {
local msg="${1:-Подождите...}"
(
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local i=0
while true; do
printf "\r ${CYAN}${frames[$i]}${NC} ${msg}" >&2
i=$(( (i+1) % ${#frames[@]} ))
sleep 0.12
done
) &
spin_pid=$!
}
spinner_stop() {
[ -n "$spin_pid" ] && kill "$spin_pid" 2>/dev/null && wait "$spin_pid" 2>/dev/null
spin_pid=""
printf "\r\033[K" >&2
}
progress_bar() {
local current="$1" total="$2" label="${3:-}"
local pct=$(( current * 100 / total ))
local filled=$(( pct / 2 ))
local empty=$(( 50 - filled ))
local bar=""
for ((i=0; i<filled; i++)); do bar+="█"; done
for ((i=0; i<empty; i++)); do bar+="░"; done
printf "\r ${GREEN}[${bar}]${NC} ${pct}%% ${label}" >&2
[ "$current" -eq "$total" ] && echo "" >&2
}
run_with_progress() {
local label="$1"; shift
spinner_start "$label"
"$@" >/dev/null 2>&1
local rc=$?
spinner_stop
if [ $rc -eq 0 ]; then
echo -e " ${GREEN}${NC} $label"
else
echo -e " ${RED}${NC} $label ${RED}(ошибка)${NC}"
fi
return $rc
}
# ── Проверки системы ─────────────────────────────────────────────────────────
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Запустите с sudo / root.${NC}"
exit 1
fi
install_pkg() {
if command -v apt-get &>/dev/null; then
apt-get update -qq && apt-get install -y -qq "$@"
elif command -v dnf &>/dev/null; then
dnf install -y "$@" 2>/dev/null
elif command -v yum &>/dev/null; then
yum install -y "$@"
fi
}
# ── Оптимизация Сети (BBR) ───────────────────────────────────────────────────
optimize_system() {
if ! sysctl net.ipv4.tcp_congestion_control | grep -q "bbr"; then
spinner_start "Оптимизация сетевого стека (BBR)..."
{
echo "net.core.default_qdisc=fq"
echo "net.ipv4.tcp_congestion_control=bbr"
} >> /etc/sysctl.conf
sysctl -p >/dev/null 2>&1
spinner_stop
echo -e " ${GREEN}${NC} BBR включен"
fi
}
# ── Firewall (Фикс звонков) ──────────────────────────────────────────────────
fix_firewall() {
local port="$1"
if command -v ufw &>/dev/null && ufw status | grep -q "active"; then
ufw allow "$port"/tcp >/dev/null 2>&1
ufw allow "$port"/udp >/dev/null 2>&1
elif command -v firewall-cmd &>/dev/null && systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-port="$port"/tcp >/dev/null 2>&1
firewall-cmd --permanent --add-port="$port"/udp >/dev/null 2>&1
firewall-cmd --reload >/dev/null 2>&1
fi
echo -e " ${GREEN}${NC} Порты $port (TCP/UDP) открыты"
}
# ── Установка зависимостей ───────────────────────────────────────────────────
install_base_deps() {
local steps=0 total=4
progress_bar $steps $total "Проверка зависимостей..."
if ! command -v curl &>/dev/null; then run_with_progress "Установка curl" install_pkg curl; fi
steps=$((steps+1)); progress_bar $steps $total "curl"
if ! command -v docker &>/dev/null; then
spinner_start "Установка Docker..."
curl -fsSL https://get.docker.com | sh >/dev/null 2>&1
systemctl enable --now docker >/dev/null 2>&1
spinner_stop
fi
steps=$((steps+1)); progress_bar $steps $total "docker"
if ! command -v qrencode &>/dev/null; then run_with_progress "Установка qrencode" install_pkg qrencode; fi
steps=$((steps+1)); progress_bar $steps $total "qrencode"
if ! docker info &>/dev/null 2>&1; then systemctl start docker 2>/dev/null; sleep 2; fi
steps=$((steps+1)); progress_bar $steps $total "Готово"
echo ""
}
# ── Утилиты IP и Портов ──────────────────────────────────────────────────────
get_ip4() { curl -s -4 --max-time 5 https://api.ipify.org || echo "0.0.0.0"; }
check_port() {
local port="$1"
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"; then
local hp=$(docker inspect "$CONTAINER_NAME" --format='{{range $p,$c := .HostConfig.PortBindings}}{{(index $c 0).HostPort}} {{end}}' 2>/dev/null)
for p in $hp; do [ "$p" = "$port" ] && return 1; done
fi
local line=$(ss -tlnp 2>/dev/null | grep -E ":${port}\b" | head -1)
[ -n "$line" ] && { echo "$line"; return 0; }
return 1
}
find_smart_port() {
local port=443
if ss -tlnp | grep -qE ":${port}\b"; then
echo -e " ${YELLOW} Порт 443 занят (Hiddify/Nginx). Пробую 8443...${NC}" >&2
port=8443
if ss -tlnp | grep -qE ":${port}\b"; then
port=$(( (RANDOM % 10000) + 20000 ))
echo -e " ${YELLOW} Порт 8443 тоже занят. Выбран случайный: $port${NC}" >&2
fi
fi
echo "$port"
}
# ── Показать данные подключения ──────────────────────────────────────────────
show_config() {
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo -e "${RED}Прокси не запущен!${NC}"; return
fi
local DATA=$(cat "$BOT_DIR/proxy.json" 2>/dev/null)
local PORT=$(echo "$DATA" | grep -oP '(?<="port": ")[^"]*')
local SECRET=$(echo "$DATA" | grep -oP '(?<="secret": ")[^"]*')
local IP4=$(get_ip4)
local LINK="tg://proxy?server=$IP4&port=$PORT&secret=$SECRET"
echo -e "\n${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ ДАННЫЕ ПОДКЛЮЧЕНИЯ ║${NC}"
echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e " IP: ${WHITE}$IP4${NC}"
echo -e " Порт: ${WHITE}$PORT${NC} (TCP + UDP)"
echo -e " Secret: ${WHITE}$SECRET${NC}"
echo -e "\n Ссылка: ${BLUE}$LINK${NC}"
echo ""
qrencode -t ANSIUTF8 "$LINK"
}
# ── 1) Установка MTProxy ─────────────────────────────────────────────────────
menu_install() {
clear
echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}УСТАНОВКА SWIFTGRAM MTPROXY ║${NC}"
echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
local domains=("google.com" "wikipedia.org" "github.com" "habr.com" "microsoft.com" "stackoverflow.com" "lenta.ru" "rbc.ru")
echo -e "\nВыберите домен для маскировки (Fake TLS):"
for i in "${!domains[@]}"; do
printf " ${YELLOW}%2d)${NC} %-20s" "$((i+1))" "${domains[$i]}"
[[ $(( (i+1) % 2 )) -eq 0 ]] && echo ""
done
echo -e "\n ${CYAN}9)${NC} Ввести свой домен"
read -p "Выбор: " d_idx
if [ "$d_idx" = "9" ]; then read -p "Введите домен: " DOMAIN; else DOMAIN=${domains[$((d_idx-1))]}; fi
DOMAIN=${DOMAIN:-google.com}
local PORT=$(find_smart_port)
echo -e " ${GREEN}${NC} Итоговый порт: ${WHITE}$PORT${NC}"
optimize_system
fix_firewall "$PORT"
spinner_start "Запуск контейнера..."
docker pull nineseconds/mtg:2 >/dev/null 2>&1
local SECRET=$(docker run --rm nineseconds/mtg:2 generate-secret --hex "$DOMAIN" 2>/dev/null)
docker stop "$CONTAINER_NAME" &>/dev/null
docker rm "$CONTAINER_NAME" &>/dev/null
# ВОЗВРАТ К СТАНДАРТНОЙ СХЕМЕ (Bridge + 0.0.0.0), которая работала в оригинале
docker run -d --name "$CONTAINER_NAME" --restart always \
-p "$PORT":"$PORT"/tcp \
-p "$PORT":"$PORT"/udp \
nineseconds/mtg:2 simple-run \
-n 1.1.1.1 -i prefer-ipv4 \
0.0.0.0:"$PORT" "$SECRET" > /dev/null 2>&1
sleep 2
spinner_stop
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
mkdir -p "$BOT_DIR"
echo "{\"domain\": \"$DOMAIN\", \"port\": \"$PORT\", \"secret\": \"$SECRET\"}" > "$BOT_DIR/proxy.json"
echo -e "\n${GREEN}✓ SwiftGram успешно запущен!${NC}"
show_config
else
echo -e "\n${RED}✗ Ошибка запуска. Проверьте: docker logs $CONTAINER_NAME${NC}"
fi
read -p "Нажмите Enter..."
}
# ── 3) Настройка бота ────────────────────────────────────────────────────────
menu_setup_bot() {
clear
echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ НАСТРОЙКА TELEGRAM БОТА ║${NC}"
echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}"
if ! command -v python3 &>/dev/null; then run_with_progress "Установка Python3" install_pkg python3 python3-pip python3-venv; fi
mkdir -p "$BOT_DIR"
cd "$BOT_DIR"
spinner_start "Загрузка модулей..."
curl -sL "$REPO_RAW_URL/requirements.txt" -o "requirements.txt"
curl -sL "$REPO_RAW_URL/bot.py" -o "bot.py"
spinner_stop
[ ! -d "venv" ] && python3 -m venv venv >/dev/null 2>&1
./venv/bin/pip install --upgrade pip -q
./venv/bin/pip install -r requirements.txt -q
echo -e "\n${YELLOW}Введите BOT_TOKEN:${NC}"
read -r TOKEN
echo -e "${YELLOW}Ваш Telegram ID:${NC}"
read -r ADMIN_ID
{ echo "BOT_TOKEN=$TOKEN"; echo "ALLOWED_IDS=$ADMIN_ID"; echo "CONTAINER_NAME=$CONTAINER_NAME"; echo "CONFIG_PATH=$BOT_DIR/proxy.json"; } > .env
chmod 600 .env
cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF
[Unit]
Description=SwiftGram Bot
After=network.target docker.service
[Service]
Type=simple
WorkingDirectory=$BOT_DIR
ExecStart=$BOT_DIR/venv/bin/python $BOT_DIR/bot.py
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
echo -e "\n${GREEN}✓ Бот запущен!${NC}"
read -p "Нажмите Enter..."
}
# ── 7) Удаление ──────────────────────────────────────────────────────────────
menu_remove() {
clear
read -p "Удалить SwiftGram полностью? (y/N): " yn
[[ "$yn" != "y" ]] && return
spinner_start "Удаление..."
docker stop "$CONTAINER_NAME" &>/dev/null; docker rm "$CONTAINER_NAME" &>/dev/null
systemctl stop "$SERVICE_NAME" 2>/dev/null; systemctl disable "$SERVICE_NAME" 2>/dev/null
rm -f "/etc/systemd/system/${SERVICE_NAME}.service"; rm -rf "$BOT_DIR"; rm -f /usr/local/bin/swiftgram
spinner_stop
echo -e "${GREEN}✓ Удалено.${NC}"; read -p "Enter..."
}
# ── Главный цикл ─────────────────────────────────────────────────────────────
install_base_deps
SELF="$(realpath "$0")"
[ "$SELF" != "/usr/local/bin/swiftgram" ] && { cp "$SELF" /usr/local/bin/swiftgram; chmod +x /usr/local/bin/swiftgram; }
while true; do
clear
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${MAGENTA}║ SWIFTGRAM MANAGER (Professional) ║${NC}"
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════════════╝${NC}"
docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" && echo -e " Прокси: ${GREEN}РАБОТАЕТ${NC}" || echo -e " Прокси: ${RED}ВЫКЛЮЧЕН${NC}"
systemctl is-active --quiet "$SERVICE_NAME" && echo -e " Бот: ${GREEN}РАБОТАЕТ${NC}" || echo -e " Бот: ${YELLOW}НЕ НАСТРОЕН${NC}"
echo -e "\n ${GREEN}1)${NC} Установить / Обновить прокси\n ${GREEN}2)${NC} Показать данные (QR)\n ${CYAN}3)${NC} Настроить Telegram-бота\n ${GREEN}4)${NC} Перезапустить прокси\n ${RED}5)${NC} Удалить SwiftGram\n ${WHITE}0)${NC} Выход"
read -p "Пункт: " m_idx
case $m_idx in
1) menu_install ;; 2) clear; show_config; read -p "Нажмите Enter..." ;; 3) menu_setup_bot ;;
4) docker restart "$CONTAINER_NAME"; sleep 1 ;; 5) menu_remove ;; 0) exit 0 ;;
esac
done