Files
swiftgram/install.sh
kobaltgit ec972b17e4 fix: Ultimate UDP call fix with host networking
- Switched container to --network host to eliminate NAT-related UDP call issues.
- Fixed availability by explicitly binding to 0.0.0.0 instead of hybrid :: address.
- Retained smart port selection logic and ad-free environment.
- Verified as the most stable configuration for MTProxy calls.
2026-04-05 23:49:12 +03:00

315 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 v1.0.3 — Финальный фикс звонков (UDP)
# Режим: Network Host + IPv4 Explicit Binding (100% Calls Compatibility)
# ── Настройки репозитория ────────────────────────────────────────────────────
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} Firewall настроен (TCP/UDP $port)"
}
# ── Установка зависимостей ───────────────────────────────────────────────────
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"; }
get_ip6() { curl -s -6 --max-time 5 https://api6.ipify.org || echo ""; }
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 IP6=$(get_ip6)
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}"
[ -n "$IP6" ] && echo -e " IPv6: ${WHITE}$IP6${NC}"
echo -e " Порт: ${WHITE}$PORT${NC} (Direct UDP Calls Ready)"
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 "Запуск контейнера (UDP Calls Optimized)..."
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
# РЕШЕНИЕ: --network host + привязка к IPv4 (0.0.0.0).
# Это убирает NAT докера, который ломает звонки, но оставляет доступность.
docker run -d --name "$CONTAINER_NAME" --restart always \
--network host \
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}✓ 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 (v1.0.3) ║${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