#!/bin/bash # GoTelegram v2.2 — Управление telemt binary # Скачивание, обновление, запуск, остановка через systemd TELEMT_GITHUB="telemt/telemt" TELEMT_RELEASE_API="https://api.github.com/repos/${TELEMT_GITHUB}/releases/latest" TELEMT_USER="telemt" TELEMT_GROUP="telemt" # ── Получение последней версии ─────────────────────────────────────────────── get_latest_telemt_version() { local resp resp=$(curl -s --max-time 10 "$TELEMT_RELEASE_API" 2>/dev/null) if [ $? -ne 0 ] || [ -z "$resp" ]; then log_error "Не удалось получить информацию о релизах telemt" return 1 fi echo "$resp" | jq -r '.tag_name // empty' } get_telemt_download_url() { # Detect arch and map to telemt asset naming convention local arch arch_name arch=$(get_arch) case "$arch" in amd64) arch_name="x86_64" ;; arm64) arch_name="aarch64" ;; armv7) arch_name="armv7" ;; *) arch_name="$arch" ;; esac # IMPORTANT: We do NOT query the GitHub releases API here. # Reason: VPS providers (Hetzner/Hostkey/Aeza/DO/Selectel) share IPv4 with # many other tenants → unauthenticated GitHub API rate limit (60/hour) is # exhausted constantly → API returns 403 → jq sees no assets → install # fails with "не найден бинарник". # # The endpoint /releases/latest/download/ is a stable redirect served # from GitHub's CDN — it does NOT count against the API rate limit and # always points at the latest non-prerelease asset by exact filename. # Asset name format: telemt--linux-gnu.tar.gz echo "https://github.com/${TELEMT_GITHUB}/releases/latest/download/telemt-${arch_name}-linux-gnu.tar.gz" } # Fallback URL using musl libc (some minimal distros / older glibc) get_telemt_download_url_musl() { local arch arch_name arch=$(get_arch) case "$arch" in amd64) arch_name="x86_64" ;; arm64) arch_name="aarch64" ;; armv7) arch_name="armv7" ;; *) arch_name="$arch" ;; esac echo "https://github.com/${TELEMT_GITHUB}/releases/latest/download/telemt-${arch_name}-linux-musl.tar.gz" } # ── Установленная версия ───────────────────────────────────────────────────── get_installed_telemt_version() { if [ -x "$TELEMT_BIN" ]; then "$TELEMT_BIN" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 else echo "" fi } is_telemt_installed() { [ -x "$TELEMT_BIN" ] } # ── Скачивание и установка ─────────────────────────────────────────────────── download_telemt() { local url url=$(get_telemt_download_url) if [ -z "$url" ]; then log_error "Не найден бинарник telemt для архитектуры $(get_arch)" return 1 fi local tmp_file="/tmp/telemt_download_$$" local extract_dir="/tmp/telemt_extract_$$" log_info "Скачивание: $url" if ! curl -L -s --max-time 120 -o "$tmp_file" "$url"; then log_warning "Не удалось скачать gnu-сборку, пробую musl..." url=$(get_telemt_download_url_musl) log_info "Скачивание: $url" if ! curl -L -s --max-time 120 -o "$tmp_file" "$url"; then log_error "Ошибка скачивания telemt (gnu и musl)" rm -f "$tmp_file" return 1 fi fi # Проверяем что файл не пустой и не HTML local file_size file_size=$(stat -c%s "$tmp_file" 2>/dev/null || echo 0) if [ "$file_size" -lt 1000 ]; then # Try musl as fallback if gnu came back empty/error-html log_warning "Файл подозрительно мал ($file_size байт), пробую musl-сборку..." url=$(get_telemt_download_url_musl) log_info "Скачивание: $url" if ! curl -L -s --max-time 120 -o "$tmp_file" "$url"; then log_error "Ошибка скачивания telemt (musl fallback)" rm -f "$tmp_file" return 1 fi file_size=$(stat -c%s "$tmp_file" 2>/dev/null || echo 0) if [ "$file_size" -lt 1000 ]; then log_error "Скачанный файл слишком маленький ($file_size байт) — возможна ошибка сети" rm -f "$tmp_file" return 1 fi fi # Определяем тип файла и распаковываем local mime extracted="" mime=$(file -b --mime-type "$tmp_file" 2>/dev/null) rm -rf "$extract_dir" mkdir -p "$extract_dir" case "$mime" in application/gzip|application/x-gzip) tar xzf "$tmp_file" -C "$extract_dir" 2>/dev/null extracted=$(find "$extract_dir" -name "telemt" -type f 2>/dev/null | head -1) if [ -z "$extracted" ]; then # Может быть просто gzip без tar gunzip -c "$tmp_file" > "$extract_dir/telemt_bin" 2>/dev/null extracted="$extract_dir/telemt_bin" fi ;; application/x-tar) tar xf "$tmp_file" -C "$extract_dir" 2>/dev/null extracted=$(find "$extract_dir" -name "telemt" -type f 2>/dev/null | head -1) ;; application/zip) unzip -o "$tmp_file" -d "$extract_dir" 2>/dev/null extracted=$(find "$extract_dir" -name "telemt" -type f 2>/dev/null | head -1) ;; application/octet-stream|application/x-executable) extracted="$tmp_file" ;; *) # Пробуем определить по содержимому if file "$tmp_file" 2>/dev/null | grep -q "ELF"; then extracted="$tmp_file" else # Пробуем как tar.gz tar xzf "$tmp_file" -C "$extract_dir" 2>/dev/null extracted=$(find "$extract_dir" -name "telemt" -type f 2>/dev/null | head -1) fi ;; esac if [ -z "$extracted" ] || [ ! -f "$extracted" ]; then log_error "Не удалось извлечь бинарник telemt (mime: $mime)" rm -f "$tmp_file" rm -rf "$extract_dir" return 1 fi # Устанавливаем cp "$extracted" "$TELEMT_BIN" chmod 755 "$TELEMT_BIN" rm -f "$tmp_file" rm -rf "$extract_dir" # Проверяем if "$TELEMT_BIN" --version &>/dev/null; then log_success "telemt $(get_installed_telemt_version) установлен в $TELEMT_BIN" return 0 else log_error "Бинарник telemt не запускается ($(file -b "$TELEMT_BIN" 2>/dev/null))" return 1 fi } # ── Системный пользователь ─────────────────────────────────────────────────── create_telemt_user() { if ! id "$TELEMT_USER" &>/dev/null; then useradd -r -s /usr/sbin/nologin -d /etc/telemt "$TELEMT_USER" 2>/dev/null log_dim "Создан системный пользователь: $TELEMT_USER" fi } # ── Systemd сервис ─────────────────────────────────────────────────────────── install_telemt_service() { local config_path="${1:-$TELEMT_CONFIG}" cat > "/etc/systemd/system/${TELEMT_SERVICE}.service" << EOF [Unit] Description=GoTelegram MTProxy (telemt engine) Documentation=https://github.com/telemt/telemt After=network-online.target Wants=network-online.target [Service] Type=simple User=root ExecStart=$TELEMT_BIN run $config_path Restart=always RestartSec=5 LimitNOFILE=65535 # Безопасность NoNewPrivileges=true ProtectSystem=full ProtectHome=true PrivateTmp=true [Install] WantedBy=multi-user.target EOF systemctl daemon-reload log_success "Systemd сервис $TELEMT_SERVICE создан" } # ── Управление сервисом ────────────────────────────────────────────────────── # start_telemt ensures telemt is running with the CURRENT on-disk config. # If the service is already active we must restart (not plain start) — otherwise # the running process keeps its old in-memory config and the freshly generated # /etc/telemt/config.toml is silently ignored. This was the root cause of the # "lite-mode key doesn't work after reinstall" bug: telemt had loaded the # previous Pro config (tls_domain=anten-ka.com) and was rejecting SNI=google.com # clients with unknown_sni_action=Drop even though the on-disk config said # tls_domain=google.com. start_telemt() { if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then systemctl restart "$TELEMT_SERVICE" 2>/dev/null else systemctl start "$TELEMT_SERVICE" 2>/dev/null fi sleep 2 if systemctl is-active --quiet "$TELEMT_SERVICE"; then log_success "telemt запущен" return 0 else log_error "telemt не запустился" journalctl -u "$TELEMT_SERVICE" --no-pager -n 10 2>/dev/null return 1 fi } stop_telemt() { if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then systemctl stop "$TELEMT_SERVICE" log_success "telemt остановлен" else log_dim "telemt уже остановлен" fi } restart_telemt() { systemctl restart "$TELEMT_SERVICE" 2>/dev/null sleep 2 if systemctl is-active --quiet "$TELEMT_SERVICE"; then log_success "telemt перезапущен" return 0 else log_error "telemt не перезапустился" return 1 fi } enable_telemt() { systemctl enable "$TELEMT_SERVICE" 2>/dev/null } telemt_status() { if ! is_telemt_installed; then echo "not_installed" return fi if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then echo "running" elif systemctl is-enabled --quiet "$TELEMT_SERVICE" 2>/dev/null; then echo "stopped" else echo "disabled" fi } telemt_logs() { local lines="${1:-40}" journalctl -u "$TELEMT_SERVICE" --no-pager -n "$lines" 2>/dev/null } telemt_uptime() { local started started=$(systemctl show "$TELEMT_SERVICE" --property=ActiveEnterTimestamp --value 2>/dev/null) if [ -n "$started" ] && [ "$started" != "" ]; then echo "$started" else echo "N/A" fi } # ── Обновление ─────────────────────────────────────────────────────────────── check_telemt_update() { local current latest current=$(get_installed_telemt_version) latest=$(get_latest_telemt_version) if [ -z "$current" ] || [ -z "$latest" ]; then return 1 fi if [ "$current" != "$latest" ]; then echo "$latest" return 0 # есть обновление fi return 1 # актуально } update_telemt() { local latest latest=$(check_telemt_update) if [ $? -ne 0 ]; then log_info "telemt уже последней версии ($(get_installed_telemt_version))" return 0 fi log_info "Доступно обновление: $(get_installed_telemt_version) → $latest" if ! confirm "Обновить telemt?"; then return 0 fi stop_telemt if download_telemt; then start_telemt log_success "telemt обновлён до $latest" else start_telemt # запускаем старую версию обратно log_error "Обновление не удалось" return 1 fi } # ── Полная установка telemt ────────────────────────────────────────────────── install_telemt_full() { log_step "Установка telemt" # Создаём директории mkdir -p /etc/telemt # Скачиваем бинарник run_with_spinner "Скачивание telemt" download_telemt || return 1 # Устанавливаем systemd сервис install_telemt_service # Включаем автозапуск enable_telemt log_success "telemt готов к работе" return 0 } # ── Удаление telemt ────────────────────────────────────────────────────────── remove_telemt() { stop_telemt systemctl disable "$TELEMT_SERVICE" 2>/dev/null rm -f "/etc/systemd/system/${TELEMT_SERVICE}.service" systemctl daemon-reload rm -f "$TELEMT_BIN" rm -rf /etc/telemt log_success "telemt полностью удалён" }