feat: Initial commit for SwiftGram - Smart MTProxy Manager

This commit is contained in:
kobaltgit
2026-04-05 22:08:46 +03:00
commit 9482cfe7f6
4 changed files with 1040 additions and 0 deletions

387
install.sh Normal file
View File

@@ -0,0 +1,387 @@
#!/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<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
}
# ── Проверки системы ─────────────────────────────────────────────────────────
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