#!/bin/bash # šŸš€ SwiftGram MTProxy — Smart Modular Manager # Š§ŠøŃŃ‚Š°Ń Š²ŠµŃ€ŃŠøŃ без рекламы. # Š¤ŃƒŠ½ŠŗŃ†ŠøŠø: Auto-BBR, IPv6, UDP-Fix, Domain Analysis, Hiddify Compatible. # ── ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠø Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€ŠøŃ (Š—ŠŠœŠ•ŠŠ˜ ŠŠ Š”Š’ŠžŠ˜ ŠŸŠžŠ”Š›Š• Š”ŠžŠ—Š”ŠŠŠ˜ŠÆ Š Š•ŠŸŠž) ──────────────── 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&2 [ "$current" -eq "$total" ] && echo "" >&2 } # ── ŠŸŃ€Š¾Š²ŠµŃ€ŠŗŠø системы ───────────────────────────────────────────────────────── 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 + Limits) ────────────────────────────────────────── optimize_system() { spinner_start "ŠžŠæŃ‚ŠøŠ¼ŠøŠ·Š°Ń†ŠøŃ сетевого стека (BBR)..." if ! sysctl net.ipv4.tcp_congestion_control | grep -q "bbr"; then { echo "net.core.default_qdisc=fq" echo "net.ipv4.tcp_congestion_control=bbr" echo "net.ipv4.ip_local_port_range=1024 65535" echo "net.core.somaxconn=65535" echo "net.ipv4.tcp_fastopen=3" } >> /etc/sysctl.conf sysctl -p >/dev/null 2>&1 fi # Увеличение лимитов открытых файлов if ! grep -q "soft nofile 1000000" /etc/security/limits.conf; then echo "* soft nofile 1000000" >> /etc/security/limits.conf echo "* hard nofile 1000000" >> /etc/security/limits.conf fi spinner_stop echo -e " ${GREEN}āœ“${NC} Дистема оптимизирована (BBR Š²ŠŗŠ»ŃŽŃ‡ŠµŠ½)" } # ── 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} Firewall: порты $port/TCP Šø $port/UDP открыты" } # ── Š˜Š½Ń‚ŠµŠ»Š»ŠµŠŗŃ‚ŃƒŠ°Š»ŃŒŠ½Ń‹Š¹ анализ Гомена ─────────────────────────────────────────── analyze_best_domain() { spinner_start "Анализ Š¾ŠæŃ‚ŠøŠ¼Š°Š»ŃŒŠ½Š¾Š³Š¾ Гомена Š“Š»Ń Fake TLS..." local test_domains=( "google.com" "wikipedia.org" "github.com" "habr.com" "microsoft.com" "stackoverflow.com" "lenta.ru" "rbc.ru" ) local best_domain="google.com" local min_time=999 for d in "${test_domains[@]}"; do # Пингуем 1 раз, жГем максимум 1 секунГу local t=$(ping -c 1 -W 1 "$d" 2>/dev/null | grep 'time=' | awk -F'time=' '{print $2}' | awk '{print $1}') if [ -z "$t" ]; then t=999; fi # Дравнение через bc (если ŠµŃŃ‚ŃŒ) или целочисленное if (( $(echo "$t < $min_time" | bc -l 2>/dev/null || [ ${t%.*} -lt ${min_time%.*} ]) )); then min_time=$t best_domain=$d fi done spinner_stop echo -e " ${GREEN}āœ“${NC} ŠžŠæŃ‚ŠøŠ¼Š°Š»ŃŒŠ½Ń‹Š¹ Гомен: ${WHITE}$best_domain${NC} (заГержка: ${min_time}ms)" echo "$best_domain" } # ── Умный поиск порта ──────────────────────────────────────────────────────── find_smart_port() { local port=443 # ŠŸŃ€Š¾Š²ŠµŃ€ŃŠµŠ¼ 443, если Š·Š°Š½ŃŃ‚ — ŠæŃ€Š¾Š²ŠµŃ€ŃŠµŠ¼ 8443, если Šø он Š·Š°Š½ŃŃ‚ — берем ранГом if ss -tlnp | grep -qE ":${port}\b"; then echo -e " ${YELLOW}ℹ ŠŸŠ¾Ń€Ń‚ 443 Š·Š°Š½ŃŃ‚ (Hiddify/Nginx). ŠŸŃ€Š¾Š±ŃƒŃŽ 8443...${NC}" port=8443 if ss -tlnp | grep -qE ":${port}\b"; then port=$(( (RANDOM % 10000) + 20000 )) echo -e " ${YELLOW}ℹ ŠŸŠ¾Ń€Ń‚ 8443 тоже Š·Š°Š½ŃŃ‚. Выбран ŃŠ»ŃƒŃ‡Š°Š¹Š½Ń‹Š¹: $port${NC}" fi fi echo "$port" } # ── Установка зависимостей ─────────────────────────────────────────────────── install_base_deps() { local total=4 cur=0 progress_bar $cur $total "ŠŸŃ€Š¾Š²ŠµŃ€ŠŗŠ°..." if ! command -v curl &>/dev/null; then install_pkg curl; fi cur=$((cur+1)); progress_bar $cur $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 cur=$((cur+1)); progress_bar $cur $total "docker" if ! command -v qrencode &>/dev/null; then install_pkg qrencode; fi cur=$((cur+1)); progress_bar $cur $total "qrencode" if ! docker info &>/dev/null 2>&1; then systemctl start docker; fi cur=$((cur+1)); progress_bar $cur $total "Готово" echo "" } # ── IP Утилиты ─────────────────────────────────────────────────────────────── get_ip4() { curl -s -4 --max-time 5 https://api.ipify.org || echo "0.0.0.0"; } get_ip6() { curl -s -6 --max-time 5 https://api6.ipify.org || echo ""; } # ── 1) Установка MTProxy ───────────────────────────────────────────────────── menu_install() { clear echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}ā•‘ Š£Š”Š¢ŠŠŠžŠ’ŠšŠ SWIFTGRAM MTPROXY ā•‘${NC}" echo -e "${CYAN}ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•${NC}" optimize_system local DOMAIN=$(analyze_best_domain) local PORT=$(find_smart_port) fix_firewall "$PORT" # ŠŸŃ€Š¾Ń†ŠµŃŃ Docker spinner_start "Š—Š°Š³Ń€ŃƒŠ·ŠŗŠ° Šø запуск прокси (IPv4 + IPv6 + UDP)..." 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 # Š—Š°ŠæŃƒŃŠŗ: слушаем 0.0.0.0 (все IPv4) Šø [::] (все IPv6) 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 -t 1.0.0.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}āœ“ ŠŸŃ€Š¾ŠŗŃŠø успешно Š·Š°ŠæŃƒŃ‰ŠµŠ½ на ŠæŠ¾Ń€Ń‚Ńƒ $PORT!${NC}" show_config else echo -e "\n${RED}āœ— ŠžŃˆŠøŠ±ŠŗŠ° запуска. ŠŸŃ€Š¾Š²ŠµŃ€ŃŒŃ‚Šµ: docker logs $CONTAINER_NAME${NC}" fi read -p "ŠŠ°Š¶Š¼ŠøŃ‚Šµ Enter..." } # ── ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ганные ────────────────────────────────────────────────────────── 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 IP6=$(get_ip6) echo -e "\n${CYAN}--- Š”ŠŠŠŠ«Š• ŠŸŠžŠ”ŠšŠ›Š®Š§Š•ŠŠ˜ŠÆ ---${NC}" echo -e "IPv4: ${WHITE}$IP4${NC}" [ -n "$IP6" ] && echo -e "IPv6: ${WHITE}$IP6${NC}" echo -e "ŠŸŠ¾Ń€Ń‚: ${WHITE}$PORT${NC}" echo -e "Secret: ${WHITE}$SECRET${NC}" local LINK="tg://proxy?server=$IP4&port=$PORT&secret=$SECRET" echo -e "\nДсылка: ${BLUE}$LINK${NC}" qrencode -t ANSIUTF8 "$LINK" } # ── 3) ŠŠ°ŃŃ‚Ń€Š¾Š¹ŠŗŠ° бота (ŠœŠ¾Š“ŃƒŠ»ŃŒŠ½Š°Ń) ──────────────────────────────────────────── menu_setup_bot() { clear echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}ā•‘ ŠŠŠ”Š¢Š ŠžŠ™ŠšŠ TELEGRAM Š‘ŠžŠ¢Š ā•‘${NC}" echo -e "${CYAN}ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•${NC}" # 1. Установка Python 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" # 2. Дкачивание моГулей (Requirements + Bot) spinner_start "Š—Š°Š³Ń€ŃƒŠ·ŠŗŠ° моГулей бота ŠøŠ· Ń€ŠµŠæŠ¾Š·ŠøŃ‚Š¾Ń€ŠøŃ..." curl -sL "$REPO_RAW_URL/requirements.txt" -o "requirements.txt" curl -sL "$REPO_RAW_URL/bot.py" -o "bot.py" spinner_stop # 3. Venv Šø зависимости if [ ! -d "venv" ]; then spinner_start "ДозГание Š²ŠøŃ€Ń‚ŃƒŠ°Š»ŃŒŠ½Š¾Š³Š¾ Š¾ŠŗŃ€ŃƒŠ¶ŠµŠ½ŠøŃ..." python3 -m venv venv >/dev/null 2>&1 spinner_stop fi spinner_start "Установка зависимостей Python..." ./venv/bin/pip install --upgrade pip -q ./venv/bin/pip install -r requirements.txt -q spinner_stop # 4. ŠšŠ¾Š½Ń„ŠøŠ³ .env echo -e "\n${YELLOW}ВвеГите BOT_TOKEN от @BotFather:${NC}" read -r TOKEN echo -e "${YELLOW}ВвеГите ваш Telegram ID (аГмин):${NC}" read -r ADMIN_ID { echo "BOT_TOKEN=$TOKEN" [ -n "$ADMIN_ID" ] && echo "ALLOWED_IDS=$ADMIN_ID" echo "CONTAINER_NAME=$CONTAINER_NAME" echo "CONFIG_PATH=$BOT_DIR/proxy.json" } > .env chmod 600 .env # 5. Systemd сервис cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF [Unit] Description=SwiftGram Bot Service After=network.target docker.service [Service] Type=simple WorkingDirectory=$BOT_DIR ExecStart=$BOT_DIR/venv/bin/python $BOT_DIR/bot.py Restart=always RestartSec=5 [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 echo -e "${RED}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${RED}ā•‘ Š£Š”ŠŠ›Š•ŠŠ˜Š• SWIFTGRAM ā•‘${NC}" echo -e "${RED}ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•${NC}" echo -e "Š‘ŃƒŠ“ŠµŃ‚ уГалено: контейнер, файлы бота, сервис Šø настройки.\n" read -p "Š’Ń‹ ŃƒŠ²ŠµŃ€ŠµŠ½Ń‹? (y/N): " yn [[ "$yn" != "y" ]] && return local words=("Š£Š”ŠŠ›Š˜Š¢Š¬" "SWIFTGRAM" "ŠžŠ§Š˜Š”Š¢ŠšŠ" "Š¤Š˜ŠŠŠ›") local confirm_word="${words[$((RANDOM % ${#words[@]}))]}" echo -e "ВвеГите слово Š“Š»Ń ŠæŠ¾Š“Ń‚Š²ŠµŃ€Š¶Š“ŠµŠ½ŠøŃ: ${WHITE}$confirm_word${NC}" read -p ">>> " input_word [[ "$input_word" != "$confirm_word" ]] && { echo "ŠžŃ‚Š¼ŠµŠ½Š°."; sleep 1; 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")" if [ "$SELF" != "/usr/local/bin/swiftgram" ]; then cp "$SELF" /usr/local/bin/swiftgram && chmod +x /usr/local/bin/swiftgram fi while true; do clear echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${MAGENTA}ā•‘ SWIFTGRAM MANAGER (No Ads) ā•‘${NC}" echo -e "${MAGENTA}ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•${NC}" if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then echo -e " ŠŸŃ€Š¾ŠŗŃŠø: ${GREEN}Š ŠŠ‘ŠžŠ¢ŠŠ•Š¢${NC}" else echo -e " ŠŸŃ€Š¾ŠŗŃŠø: ${RED}Š’Š«ŠšŠ›Š®Š§Š•Š${NC}" fi if systemctl is-active --quiet "$SERVICE_NAME"; then echo -e " Бот: ${GREEN}Š ŠŠ‘ŠžŠ¢ŠŠ•Š¢${NC}" else echo -e " Бот: ${YELLOW}ŠŠ• ŠŠŠ”Š¢Š ŠžŠ•Š${NC}" fi echo -e "\n ${GREEN}1)${NC} Š£ŃŃ‚Š°Š½Š¾Š²ŠøŃ‚ŃŒ / ŠžŠ±Š½Š¾Š²ŠøŃ‚ŃŒ прокси" echo -e " ${GREEN}2)${NC} ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Ганные (QR)" echo -e " ${CYAN}3)${NC} ŠŠ°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ Telegram-бота" echo -e " ${GREEN}4)${NC} ŠŸŠµŃ€ŠµŠ·Š°ŠæŃƒŃŃ‚ŠøŃ‚ŃŒ прокси" echo -e " ${RED}5)${NC} Š£Š“Š°Š»ŠøŃ‚ŃŒ всё" echo -e " ${WHITE}0)${NC} ВыхоГ" echo "" 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"; echo "Готово"; sleep 1 ;; 5) menu_remove ;; 0) exit 0 ;; esac done