Files
swiftgram/install.sh

387 lines
17 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 — 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