mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 14:36:05 +00:00
GoTelegram MTProxy + bot (gotelegram_pro)
Made-with: Cursor
This commit is contained in:
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Секреты и конфиг с токенами
|
||||||
|
.env
|
||||||
|
*.env.local
|
||||||
|
config.local.env
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
|
||||||
|
# Временные и системные
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
99
IMPROVEMENTS.md
Normal file
99
IMPROVEMENTS.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# Предложения по улучшению GoTelegram MTProxy
|
||||||
|
|
||||||
|
## Анализ текущего скрипта
|
||||||
|
|
||||||
|
Скрипт уже хорошо структурирован: проверка root, установка зависимостей, меню, работа с Docker (nineseconds/mtg). Ниже — конкретные улучшения.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Безопасность и надёжность
|
||||||
|
|
||||||
|
### 1.1 Валидация порта
|
||||||
|
- **Сейчас:** при выборе "свой порт" можно ввести нечисло или порт вне диапазона.
|
||||||
|
- **Предложение:** проверять число в диапазоне 1–65535 и повторять запрос при ошибке.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
while true; do
|
||||||
|
read -p "Введите порт (1-65535): " PORT
|
||||||
|
[[ "$PORT" =~ ^[0-9]+$ ]] && (( PORT >= 1 && PORT <= 65535 )) && break
|
||||||
|
echo "Неверный порт."
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 Проверка занятости порта
|
||||||
|
- Перед запуском контейнера проверять, что порт свободен (например, `ss -tlnp | grep -q ":$PORT "`), и выводить понятное сообщение, если порт занят.
|
||||||
|
|
||||||
|
### 1.3 Остановка только своего контейнера
|
||||||
|
- В пункте 4 (удаление) использовать `docker stop mtproto-proxy 2>/dev/null; docker rm mtproto-proxy 2>/dev/null` и проверять код возврата, чтобы не путать с отсутствием контейнера.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Функциональность
|
||||||
|
|
||||||
|
### 2.1 Свой домен для Fake TLS
|
||||||
|
- В списке доменов добавить пункт "Свой домен" с вводом произвольной строки и базовой проверкой (например, наличие точки, длина).
|
||||||
|
|
||||||
|
### 2.2 Рестарт прокси
|
||||||
|
- Отдельный пункт меню "Перезапустить прокси" без пересоздания контейнера: `docker restart mtproto-proxy`.
|
||||||
|
|
||||||
|
### 2.3 Логи
|
||||||
|
- Пункт "Показать логи" (последние N строк): `docker logs --tail 50 mtproto-proxy`.
|
||||||
|
|
||||||
|
### 2.4 Обновление образа mtg
|
||||||
|
- Пункт "Обновить образ mtg": `docker pull nineseconds/mtg:2`, затем предложить пересоздать прокси с теми же параметрами (сохранить secret/порт из текущего контейнера).
|
||||||
|
|
||||||
|
### 2.5 Сохранение конфигурации
|
||||||
|
- Сохранять выбранные домен и порт в файл (например, `/etc/gotelegram.conf` или `~/.gotelegram`), чтобы при обновлении/переустановке не вводить заново.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Удобство и совместимость
|
||||||
|
|
||||||
|
### 3.1 Поддержка RHEL/CentOS
|
||||||
|
- В `install_deps` для установки `qrencode` использовать `command -v apt-get` / `command -v yum` или `dnf`, а не только `apt-get` и `yum`, чтобы корректно работало на RHEL 8+.
|
||||||
|
|
||||||
|
### 3.2 Неинтерактивный режим
|
||||||
|
- Поддержка аргументов для автоматической установки, например:
|
||||||
|
`./setup_gotelegram.sh --domain wikipedia.org --port 443 --no-promo`
|
||||||
|
- Полезно для скриптов развёртывания и для бота.
|
||||||
|
|
||||||
|
### 3.3 Отключение промо
|
||||||
|
- Переменная окружения или флаг, например `SKIP_PROMO=1` или `--no-promo`, чтобы при первом запуске не показывать промо (для автоматизации и бота).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Вывод и интерфейс
|
||||||
|
|
||||||
|
### 4.1 Текстовый вывод ссылки для копирования
|
||||||
|
- В `show_config` выводить ссылку в одну строку без переносов, чтобы удобно копировать из терминала и отправлять в бота/чат.
|
||||||
|
|
||||||
|
### 4.2 Сообщение при отсутствии прокси
|
||||||
|
- В пункте 2 при отсутствии контейнера не только "Прокси не найден!", но и подсказка: "Выберите пункт 1 для установки."
|
||||||
|
|
||||||
|
### 4.3 Версия скрипта
|
||||||
|
- В начале или в меню выводить версию (например, из переменной `VERSION="1.0"`), чтобы при обновлениях было проще отлаживать.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Мелкие правки
|
||||||
|
|
||||||
|
### 5.1 Заголовок промо
|
||||||
|
- В рамке промо текст "ХОСТИНГ СО СКИДКОЙ..." разной длины — выровнять по ширине рамки или центрировать, чтобы рамка не "прыгала".
|
||||||
|
|
||||||
|
### 5.2 Имя контейнера
|
||||||
|
- Сейчас жёстко `mtproto-proxy`. Имеет смысл вынести в переменную в начале скрипта (например, `CONTAINER_NAME="mtproto-proxy"`), чтобы при необходимости можно было менять в одном месте.
|
||||||
|
|
||||||
|
### 5.3 Таймауты curl
|
||||||
|
- В `get_ip` уже есть `--max-time 5`. Можно добавить резервный источник (например, `ifconfig.me` или `ipecho.net/plain`) на случай недоступности основных.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Приоритеты внедрения
|
||||||
|
|
||||||
|
| Приоритет | Улучшение |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Высокий | Валидация порта, проверка занятости порта, неинтерактивный режим / отключение промо |
|
||||||
|
| Средний | Свой домен, рестарт, логи, сохранение конфигурации |
|
||||||
|
| Низкий | Версия скрипта, выравнивание промо, дополнительные источники IP |
|
||||||
|
|
||||||
|
Эти изменения улучшат устойчивость скрипта в автоматизации и при использовании через Telegram-бота.
|
||||||
144
INSTALL_PRIVATE.md
Normal file
144
INSTALL_PRIVATE.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# Установка из закрытого GitHub-репозитория (по ключу)
|
||||||
|
|
||||||
|
Инструкция для размещения проекта в **приватном** репозитории и установки на сервер **по SSH-ключу** или **по токену (PAT)**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Размещение в закрытом репозитории
|
||||||
|
|
||||||
|
### 1.1 Создать приватный репозиторий
|
||||||
|
|
||||||
|
1. GitHub → **New repository**.
|
||||||
|
2. Имя, например: `gotelegram_pro`.
|
||||||
|
3. Выберите **Private**.
|
||||||
|
4. Не добавляйте README, .gitignore и лицензию, если пушите существующий проект.
|
||||||
|
|
||||||
|
### 1.2 Загрузить код (с локальной машины)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd "Скрипт mtproxy"
|
||||||
|
git init
|
||||||
|
git remote add origin git@github.com:ВАШ_ЛОГИН/gotelegram_pro.git
|
||||||
|
git add .
|
||||||
|
git commit -m "GoTelegram MTProxy + bot"
|
||||||
|
git branch -M main
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
Если репо уже есть и вы только добавляете remote:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote add origin git@github.com:ВАШ_ЛОГИН/gotelegram_pro.git
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 Настроить доступ «по ключу»
|
||||||
|
|
||||||
|
Доступ к приватному репо с сервера возможен двумя способами.
|
||||||
|
|
||||||
|
| Способ | Когда использовать |
|
||||||
|
|--------|--------------------|
|
||||||
|
| **SSH-ключ** | На сервере уже настроен `ssh-agent` и ключ добавлен в GitHub (Deploy key или ваш SSH key). |
|
||||||
|
| **Personal Access Token (PAT)** | Удобно для одноразовой установки или CI; токен передаётся в переменной окружения. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Установка по SSH-ключу
|
||||||
|
|
||||||
|
### 2.1 Добавить SSH-ключ в GitHub
|
||||||
|
|
||||||
|
**На сервере** (или с машины, с которой будете клонировать):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Сгенерировать ключ (если ещё нет)
|
||||||
|
ssh-keygen -t ed25519 -C "server-gotelegram" -f ~/.ssh/gotelegram_deploy -N ""
|
||||||
|
cat ~/.ssh/gotelegram_deploy.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Личный репо:** GitHub → **Settings → SSH and GPG keys → New SSH key** → вставить содержимое `.pub`.
|
||||||
|
- **Организация:** добавить ключ как **Deploy key** в настройках репозитория (Read-only достаточно).
|
||||||
|
|
||||||
|
Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -T git@github.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 Клонировать и установить
|
||||||
|
|
||||||
|
**Вариант А:** скопируйте `bootstrap_install.sh` на сервер (через scp или вставьте содержимое в файл), затем:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x bootstrap_install.sh
|
||||||
|
GIT_REPO_SSH="git@github.com:ВАШ_ЛОГИН/gotelegram_pro.git" sudo bash bootstrap_install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Вариант Б:** клонировать репо вручную и запустить установку:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:ВАШ_ЛОГИН/gotelegram_pro.git /tmp/gotelegram_pro
|
||||||
|
sudo /tmp/gotelegram_pro/install_gotelegram_bot.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Установка по токену (PAT)
|
||||||
|
|
||||||
|
### 3.1 Создать Personal Access Token
|
||||||
|
|
||||||
|
1. GitHub → **Settings → Developer settings → Personal access tokens**.
|
||||||
|
2. **Tokens (classic)** → **Generate new token**.
|
||||||
|
3. Права: минимум **repo** (полный доступ к приватным репо).
|
||||||
|
4. Скопировать токен (один раз показывается).
|
||||||
|
|
||||||
|
### 3.2 Установка одной командой (bootstrap)
|
||||||
|
|
||||||
|
Скопируйте **bootstrap_install.sh** на сервер (scp или создайте файл и вставьте содержимое из репо). Затем:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Подставьте свой токен и репо
|
||||||
|
export GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
export GIT_REPO_HTTPS="https://github.com/ВАШ_ЛОГИН/gotelegram_pro.git"
|
||||||
|
sudo -E bash bootstrap_install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`-E` сохраняет переменные окружения (в т.ч. `GITHUB_TOKEN`) при sudo.
|
||||||
|
|
||||||
|
Вариант без экспорта (токен в истории не сохраняйте в продакшене):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GITHUB_TOKEN=ghp_xxx GIT_REPO_HTTPS=https://github.com/USER/gotelegram_pro.git sudo -E bash bootstrap_install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Установка через install_gotelegram_bot.sh
|
||||||
|
|
||||||
|
Если скрипт **install_gotelegram_bot.sh** уже лежит на сервере (скопирован из репо), но папки **gotelegram-bot** рядом нет, скрипт сам попытается клонировать репо по токену:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
|
||||||
|
export GOTETELEGRAM_BOT_REPO="https://github.com/ВАШ_ЛОГИН/gotelegram_pro"
|
||||||
|
sudo -E ./install_gotelegram_bot.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Токен в процессе установки **не сохраняется** на диск, только используется для `git clone`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Безопасность
|
||||||
|
|
||||||
|
- **SSH:** используйте отдельный ключ (Deploy key) с доступом только к этому репо и при необходимости только на чтение.
|
||||||
|
- **PAT:** не коммитьте токен в репо и не оставляйте в истории shell. Для повторных установок лучше SSH или новый токен.
|
||||||
|
- После установки можно удалить клонированную папку: `rm -rf /tmp/gotelegram_pro*`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Краткая шпаргалка
|
||||||
|
|
||||||
|
| Задача | Команда |
|
||||||
|
|--------|--------|
|
||||||
|
| Установка по SSH (репо уже клонирован) | `sudo ./install_gotelegram_bot.sh` |
|
||||||
|
| Установка по SSH (bootstrap) | `GIT_REPO_SSH=git@github.com:USER/REPO.git sudo bash bootstrap_install.sh` |
|
||||||
|
| Установка по токену (bootstrap) | `GITHUB_TOKEN=ghp_xxx GIT_REPO_HTTPS=https://github.com/USER/REPO.git sudo -E bash bootstrap_install.sh` |
|
||||||
|
| Установка по токену (только install-скрипт) | `GITHUB_TOKEN=ghp_xxx sudo -E ./install_gotelegram_bot.sh` |
|
||||||
|
|
||||||
|
Вместо `USER/REPO` подставьте свой логин и имя репозитория.
|
||||||
34
PUSH_README.txt
Normal file
34
PUSH_README.txt
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
═══════════════════════════════════════════════════════════════
|
||||||
|
Как выложить проект в GitHub (ключ давать никому не нужно)
|
||||||
|
═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
1. Создайте репозиторий на GitHub
|
||||||
|
• Откройте: https://github.com/new
|
||||||
|
• Repository name: gotelegram_pro
|
||||||
|
• Выберите Private (или Public)
|
||||||
|
• НЕ добавляйте README, .gitignore, License — нажмите Create repository
|
||||||
|
|
||||||
|
2. Настройте доступ к GitHub с этого компьютера (один раз)
|
||||||
|
|
||||||
|
Вариант А — по SSH (удобно навсегда):
|
||||||
|
• Установите Git: https://git-scm.com/download/win
|
||||||
|
• Создайте ключ: в терминале (Git Bash или PowerShell):
|
||||||
|
ssh-keygen -t ed25519 -C "your@email" -f "%USERPROFILE%\.ssh\id_ed25519" -N ""
|
||||||
|
• Скопируйте публичный ключ в буфер:
|
||||||
|
type %USERPROFILE%\.ssh\id_ed25519.pub
|
||||||
|
• GitHub → Settings → SSH and GPG keys → New SSH key → вставьте ключ
|
||||||
|
• Проверка: ssh -T git@github.com
|
||||||
|
|
||||||
|
Вариант Б — по токену (разовый или если не хотите SSH):
|
||||||
|
• GitHub → Settings → Developer settings → Personal access tokens
|
||||||
|
• Generate new token (classic), право: repo
|
||||||
|
• Скопируйте токен (ghp_...)
|
||||||
|
• При первом push Git спросит логин и пароль — в пароль вставьте этот токен
|
||||||
|
• Или: git remote set-url origin https://ВАШ_ТОКЕН@github.com/anten-ka/gotelegram_pro.git
|
||||||
|
|
||||||
|
3. Запустите выкладку
|
||||||
|
• Дважды щёлкните: push_to_github.bat
|
||||||
|
• Подтвердите отправку (y)
|
||||||
|
• Если всё настроено — код уйдёт в репо без ввода ключа в чат
|
||||||
|
|
||||||
|
Ключ или токен нужны только на вашем компьютере в настройках Git — никому (и ни в какой чат) их передавать не нужно.
|
||||||
65
bootstrap_install.sh
Normal file
65
bootstrap_install.sh
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Bootstrap: клонирует приватный репозиторий (по SSH или по токену) и запускает установку.
|
||||||
|
# Использование:
|
||||||
|
# По SSH-ключу: GIT_REPO_SSH=git@github.com:USER/REPO.git bash bootstrap_install.sh
|
||||||
|
# По токену: GITHUB_TOKEN=ghp_xxx GIT_REPO_HTTPS=https://github.com/USER/REPO.git bash bootstrap_install.sh
|
||||||
|
# Или задайте репо по умолчанию ниже и запустите: sudo bash bootstrap_install.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Репозиторий по умолчанию (подставьте свой)
|
||||||
|
REPO_SSH="${GIT_REPO_SSH:-git@github.com:anten-ka/gotelegram_pro.git}"
|
||||||
|
REPO_HTTPS="${GIT_REPO_HTTPS:-https://github.com/anten-ka/gotelegram_pro.git}"
|
||||||
|
BRANCH="${GIT_BRANCH:-main}"
|
||||||
|
CLONE_DIR="/tmp/gotelegram_pro_install_$$"
|
||||||
|
|
||||||
|
cleanup() { rm -rf "$CLONE_DIR"; }
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
echo -e "${GREEN}[*] Установка GoTelegram Bot из приватного репозитория${NC}"
|
||||||
|
|
||||||
|
if ! command -v git &>/dev/null; then
|
||||||
|
echo -e "${YELLOW}[*] Установка git...${NC}"
|
||||||
|
if command -v apt-get &>/dev/null; then
|
||||||
|
apt-get update && apt-get install -y git
|
||||||
|
elif command -v dnf &>/dev/null; then
|
||||||
|
dnf install -y git
|
||||||
|
elif command -v yum &>/dev/null; then
|
||||||
|
yum install -y git
|
||||||
|
else
|
||||||
|
echo -e "${RED}Установите git вручную.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$GITHUB_TOKEN" ]; then
|
||||||
|
echo -e "${GREEN}[*] Клонирование по токену (HTTPS)...${NC}"
|
||||||
|
# Подставляем токен в URL для доступа к приватному репо
|
||||||
|
if [[ "$REPO_HTTPS" == https://github.com/* ]]; then
|
||||||
|
CLONE_URL="https://${GITHUB_TOKEN}@github.com/${REPO_HTTPS#https://github.com/}"
|
||||||
|
else
|
||||||
|
CLONE_URL="$REPO_HTTPS"
|
||||||
|
fi
|
||||||
|
git clone --depth 1 --branch "$BRANCH" "$CLONE_URL" "$CLONE_DIR"
|
||||||
|
elif [ -n "$GIT_REPO_SSH" ]; then
|
||||||
|
echo -e "${GREEN}[*] Клонирование по SSH...${NC}"
|
||||||
|
git clone --depth 1 --branch "$BRANCH" "$GIT_REPO_SSH" "$CLONE_DIR"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}[*] Клонирование по SSH (ключ по умолчанию)...${NC}"
|
||||||
|
git clone --depth 1 --branch "$BRANCH" "$REPO_SSH" "$CLONE_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$CLONE_DIR/install_gotelegram_bot.sh" ]; then
|
||||||
|
echo -e "${RED}В репозитории не найден install_gotelegram_bot.sh${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$CLONE_DIR/install_gotelegram_bot.sh"
|
||||||
|
# Передаём токен в установочный скрипт, если использовали HTTPS (для совместимости)
|
||||||
|
export GITHUB_TOKEN
|
||||||
|
echo -e "${GREEN}[*] Запуск установки...${NC}"
|
||||||
|
exec sudo "$CLONE_DIR/install_gotelegram_bot.sh"
|
||||||
70
gotelegram-bot/README.md
Normal file
70
gotelegram-bot/README.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# GoTelegram MTProxy Bot
|
||||||
|
|
||||||
|
Telegram-бот для управления MTProxy на сервере — те же функции, что и у CLI `gotelegram`, но через бота.
|
||||||
|
|
||||||
|
## Команды
|
||||||
|
|
||||||
|
| Команда | Описание |
|
||||||
|
|--------|----------|
|
||||||
|
| `/start`, `/help` | Справка |
|
||||||
|
| `/install` | Установить или обновить прокси (выбор домена и порта) |
|
||||||
|
| `/status` | Статус и данные подключения (IP, порт, secret, ссылка) |
|
||||||
|
| `/link` | Только ссылка `tg://proxy` |
|
||||||
|
| `/restart` | Перезапустить контейнер |
|
||||||
|
| `/logs` | Последние логи контейнера |
|
||||||
|
| `/remove` | Удалить прокси |
|
||||||
|
| `/promo` | Промо хостинга |
|
||||||
|
|
||||||
|
## Установка на сервер
|
||||||
|
|
||||||
|
### Публичный репозиторий (одной командой)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sL https://raw.githubusercontent.com/anten-ka/gotelegram_pro/main/install_gotelegram_bot.sh -o /tmp/install_gotelegram_bot.sh && sudo bash /tmp/install_gotelegram_bot.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
При установке скрипт запросит **BOT_TOKEN** (получить у [@BotFather](https://t.me/BotFather)).
|
||||||
|
|
||||||
|
### Закрытый репозиторий (установка по ключу)
|
||||||
|
|
||||||
|
Для **приватного** репо используется клонирование по **SSH-ключу** или по **токену (PAT)**. Подробно: **[INSTALL_PRIVATE.md](../INSTALL_PRIVATE.md)** в корне репозитория.
|
||||||
|
|
||||||
|
Кратко:
|
||||||
|
- **По SSH:** скопируйте `bootstrap_install.sh` на сервер, затем
|
||||||
|
`GIT_REPO_SSH=git@github.com:USER/REPO.git sudo bash bootstrap_install.sh`
|
||||||
|
- **По токену:**
|
||||||
|
`GITHUB_TOKEN=ghp_xxx GIT_REPO_HTTPS=https://github.com/USER/REPO.git sudo -E bash bootstrap_install.sh`
|
||||||
|
- Или клонируйте репо вручную и запустите:
|
||||||
|
`sudo ./install_gotelegram_bot.sh`
|
||||||
|
|
||||||
|
### Локально (файлы уже рядом со скриптом)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./install_gotelegram_bot.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
Файл: `/opt/gotelegram-bot/.env`
|
||||||
|
|
||||||
|
- **BOT_TOKEN** — токен от @BotFather (обязательно).
|
||||||
|
- **ALLOWED_IDS** — опционально. Список ID пользователей через запятую; если не задан, бот доступен всем.
|
||||||
|
|
||||||
|
После изменения `.env` перезапуск сервиса:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart gotelegram-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## Требования на сервере
|
||||||
|
|
||||||
|
- Linux (systemd), Docker, Python 3.
|
||||||
|
- Перед использованием бота на сервере должен быть установлен Docker (бот сам поднимает контейнер `nineseconds/mtg:2` по команде `/install`).
|
||||||
|
|
||||||
|
## Управление сервисом
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status gotelegram-bot
|
||||||
|
sudo systemctl restart gotelegram-bot
|
||||||
|
journalctl -u gotelegram-bot -f
|
||||||
|
```
|
||||||
402
gotelegram-bot/bot.py
Normal file
402
gotelegram-bot/bot.py
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
GoTelegram MTProxy — Telegram-бот для управления MTProxy на сервере.
|
||||||
|
Функции: установка, статус, ссылка, удаление, рестарт, логи (по аналогии с CLI gotelegram).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import html
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Загрузка .env из текущей папки или /etc/gotelegram-bot
|
||||||
|
_env_path = Path(__file__).resolve().parent / ".env"
|
||||||
|
if not _env_path.exists():
|
||||||
|
_env_path = Path("/etc/gotelegram-bot/.env")
|
||||||
|
if _env_path.exists():
|
||||||
|
with open(_env_path, encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if line and not line.startswith("#") and "=" in line:
|
||||||
|
k, v = line.split("=", 1)
|
||||||
|
os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'"))
|
||||||
|
|
||||||
|
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||||
|
from telegram.ext import (
|
||||||
|
Application,
|
||||||
|
CommandHandler,
|
||||||
|
CallbackQueryHandler,
|
||||||
|
ContextTypes,
|
||||||
|
MessageHandler,
|
||||||
|
filters,
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Конфиг ---
|
||||||
|
BOT_TOKEN = os.environ.get("BOT_TOKEN")
|
||||||
|
_allowed = os.environ.get("ALLOWED_IDS", "").strip()
|
||||||
|
if _allowed:
|
||||||
|
try:
|
||||||
|
ALLOWED_IDS = set(int(x.strip()) for x in _allowed.split(",") if x.strip())
|
||||||
|
except ValueError:
|
||||||
|
ALLOWED_IDS = None
|
||||||
|
else:
|
||||||
|
ALLOWED_IDS = None # все пользователи
|
||||||
|
|
||||||
|
CONTAINER_NAME = "mtproto-proxy"
|
||||||
|
DOMAINS = [
|
||||||
|
"google.com", "wikipedia.org", "habr.com", "github.com",
|
||||||
|
"coursera.org", "udemy.com", "medium.com", "stackoverflow.com",
|
||||||
|
"bbc.com", "cnn.com", "reuters.com", "nytimes.com",
|
||||||
|
"lenta.ru", "rbc.ru", "ria.ru", "kommersant.ru",
|
||||||
|
"stepik.org", "duolingo.com", "khanacademy.org", "ted.com",
|
||||||
|
]
|
||||||
|
PROMO_LINK = "https://vk.cc/ct29NQ"
|
||||||
|
TIP_LINK = "https://pay.cloudtips.ru/p/7410814f"
|
||||||
|
|
||||||
|
|
||||||
|
def check_access(user_id: int) -> bool:
|
||||||
|
if ALLOWED_IDS is None:
|
||||||
|
return True
|
||||||
|
return user_id in ALLOWED_IDS
|
||||||
|
|
||||||
|
|
||||||
|
def _decode(data: bytes) -> str:
|
||||||
|
return (data or b"").decode("utf-8", errors="replace").strip()
|
||||||
|
|
||||||
|
|
||||||
|
async def run_cmd(*args: str, timeout: int = 60) -> tuple[int, str, str]:
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
*args,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
proc.kill()
|
||||||
|
await proc.wait()
|
||||||
|
return -1, "", "Timeout"
|
||||||
|
return proc.returncode or 0, _decode(stdout), _decode(stderr)
|
||||||
|
|
||||||
|
|
||||||
|
async def docker_inspect(fmt: str) -> str:
|
||||||
|
code, out, err = await run_cmd(
|
||||||
|
"docker", "inspect", CONTAINER_NAME, "--format", fmt, timeout=10
|
||||||
|
)
|
||||||
|
if code != 0:
|
||||||
|
return ""
|
||||||
|
return out.strip()
|
||||||
|
|
||||||
|
|
||||||
|
async def get_ip() -> str:
|
||||||
|
for url in ["https://api.ipify.org", "https://icanhazip.com"]:
|
||||||
|
code, out, _ = await run_cmd("curl", "-s", "-4", "--max-time", "5", url, timeout=8)
|
||||||
|
if code == 0 and out:
|
||||||
|
m = re.search(r"([0-9]{1,3}\.){3}[0-9]{1,3}", out)
|
||||||
|
if m:
|
||||||
|
return m.group(0)
|
||||||
|
return "0.0.0.0"
|
||||||
|
|
||||||
|
|
||||||
|
async def proxy_is_running() -> bool:
|
||||||
|
code, out, _ = await run_cmd("docker", "ps", "--format", "{{.Names}}", timeout=10)
|
||||||
|
if code != 0:
|
||||||
|
return False
|
||||||
|
return CONTAINER_NAME in (out or "")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Обработчики ---
|
||||||
|
|
||||||
|
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
text = (
|
||||||
|
"🚀 *GoTelegram MTProxy Bot*\n\n"
|
||||||
|
"Управление MTProxy на этом сервере.\n\n"
|
||||||
|
"Команды:\n"
|
||||||
|
"/install — установить или обновить прокси (выбор домена и порта)\n"
|
||||||
|
"/status — статус контейнера и данные подключения\n"
|
||||||
|
"/link — только ссылка tg://proxy\n"
|
||||||
|
"/restart — перезапустить прокси\n"
|
||||||
|
"/logs — последние логи\n"
|
||||||
|
"/remove — удалить прокси\n"
|
||||||
|
"/promo — промо хостинга\n"
|
||||||
|
"/help — эта справка"
|
||||||
|
)
|
||||||
|
await update.message.reply_text(text, parse_mode="Markdown")
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
if not await proxy_is_running():
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ Прокси не запущен.\nИспользуйте /install для установки."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
secret = await docker_inspect("{{range .Config.Cmd}}{{.}} {{end}}")
|
||||||
|
secret = secret.split()[-1] if secret else ""
|
||||||
|
port = await docker_inspect("{{range $p, $conf := .HostConfig.PortBindings}}{{(index $conf 0).HostPort}}{{end}}")
|
||||||
|
port = port or "443"
|
||||||
|
ip = await get_ip()
|
||||||
|
link = f"tg://proxy?server={ip}&port={port}&secret={secret}"
|
||||||
|
# HTML безопаснее для произвольного secret (экранируем)
|
||||||
|
text = (
|
||||||
|
"✅ <b>Прокси запущен</b>\n\n"
|
||||||
|
f"IP: <code>{html.escape(ip)}</code>\n"
|
||||||
|
f"Port: <code>{html.escape(port)}</code>\n"
|
||||||
|
f"Secret: <code>{html.escape(secret)}</code>\n\n"
|
||||||
|
f"Ссылка (скопируйте):\n<code>{html.escape(link)}</code>"
|
||||||
|
)
|
||||||
|
await update.message.reply_text(text, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_link(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
if not await proxy_is_running():
|
||||||
|
await update.message.reply_text("❌ Прокси не запущен. /install")
|
||||||
|
return
|
||||||
|
secret = await docker_inspect("{{range .Config.Cmd}}{{.}} {{end}}")
|
||||||
|
secret = secret.split()[-1] if secret else ""
|
||||||
|
port = await docker_inspect("{{range $p, $conf := .HostConfig.PortBindings}}{{(index $conf 0).HostPort}}{{end}}")
|
||||||
|
port = port or "443"
|
||||||
|
ip = await get_ip()
|
||||||
|
link = f"tg://proxy?server={ip}&port={port}&secret={secret}"
|
||||||
|
await update.message.reply_text(link)
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_remove(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
await update.message.reply_text("Удаляю прокси...")
|
||||||
|
await run_cmd("docker", "stop", CONTAINER_NAME, timeout=15)
|
||||||
|
await run_cmd("docker", "rm", CONTAINER_NAME, timeout=10)
|
||||||
|
if await proxy_is_running():
|
||||||
|
await update.message.reply_text("⚠️ Не удалось удалить. Проверьте docker вручную.")
|
||||||
|
else:
|
||||||
|
await update.message.reply_text("✅ Прокси удалён.")
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_restart(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
if not await proxy_is_running():
|
||||||
|
await update.message.reply_text("❌ Прокси не запущен. /install")
|
||||||
|
return
|
||||||
|
await update.message.reply_text("Перезапускаю...")
|
||||||
|
code, _, err = await run_cmd("docker", "restart", CONTAINER_NAME, timeout=30)
|
||||||
|
if code == 0:
|
||||||
|
await update.message.reply_text("✅ Прокси перезапущен.")
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(f"❌ Ошибка: {err or 'unknown'}")
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_logs(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
if not await proxy_is_running():
|
||||||
|
await update.message.reply_text("❌ Прокси не запущен. /install")
|
||||||
|
return
|
||||||
|
code, out, err = await run_cmd("docker", "logs", "--tail", "40", CONTAINER_NAME, timeout=15)
|
||||||
|
text = (out or "") + (("\n" + err) if err else "")
|
||||||
|
if not text:
|
||||||
|
text = "Нет вывода."
|
||||||
|
if len(text) > 4000:
|
||||||
|
text = text[-4000:]
|
||||||
|
await update.message.reply_text(f"<pre>{html.escape(text)}</pre>", parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_promo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
text = (
|
||||||
|
"💰 *Хостинг со скидкой до -60%*\n"
|
||||||
|
f"Ссылка: {PROMO_LINK}\n\n"
|
||||||
|
"Промокоды: OFF60, antenka20, antenka6, antenka12\n\n"
|
||||||
|
f"Донат: {TIP_LINK}"
|
||||||
|
)
|
||||||
|
await update.message.reply_text(text, parse_mode="Markdown")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Установка: выбор домена и порта через инлайн-кнопки и диалог ---
|
||||||
|
|
||||||
|
async def install_choice_domain(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.effective_user or not update.message:
|
||||||
|
return
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await update.message.reply_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
buttons = []
|
||||||
|
row = []
|
||||||
|
for i, d in enumerate(DOMAINS):
|
||||||
|
row.append(InlineKeyboardButton(d, callback_data=f"dom_{i}"))
|
||||||
|
if len(row) == 2:
|
||||||
|
buttons.append(row)
|
||||||
|
row = []
|
||||||
|
if row:
|
||||||
|
buttons.append(row)
|
||||||
|
await update.message.reply_text(
|
||||||
|
"Выберите домен для маскировки (Fake TLS):",
|
||||||
|
reply_markup=InlineKeyboardMarkup(buttons),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def install_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
query = update.callback_query
|
||||||
|
if not query or not update.effective_user:
|
||||||
|
return
|
||||||
|
await query.answer()
|
||||||
|
if not check_access(update.effective_user.id):
|
||||||
|
await query.edit_message_text("⛔ Доступ запрещён.")
|
||||||
|
return
|
||||||
|
data = query.data or ""
|
||||||
|
if data.startswith("dom_"):
|
||||||
|
try:
|
||||||
|
idx = int(data[4:])
|
||||||
|
except ValueError:
|
||||||
|
await query.edit_message_text("❌ Неверные данные. Начните с /install.")
|
||||||
|
return
|
||||||
|
if not (0 <= idx < len(DOMAINS)):
|
||||||
|
await query.edit_message_text("❌ Неверный выбор. Начните с /install.")
|
||||||
|
return
|
||||||
|
domain = DOMAINS[idx]
|
||||||
|
context.user_data["gotelegram_domain"] = domain
|
||||||
|
kb = InlineKeyboardMarkup([
|
||||||
|
[InlineKeyboardButton("443 (рекомендуется)", callback_data="port_443"),
|
||||||
|
InlineKeyboardButton("8443", callback_data="port_8443")],
|
||||||
|
])
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"Домен: {domain}\n\nВыберите порт или введите свой (1-65535):",
|
||||||
|
reply_markup=kb,
|
||||||
|
)
|
||||||
|
context.user_data["gotelegram_wait_port"] = True
|
||||||
|
return
|
||||||
|
if data == "port_443":
|
||||||
|
context.user_data["gotelegram_port"] = "443"
|
||||||
|
context.user_data["gotelegram_wait_port"] = False
|
||||||
|
await do_install(update, context)
|
||||||
|
return
|
||||||
|
if data == "port_8443":
|
||||||
|
context.user_data["gotelegram_port"] = "8443"
|
||||||
|
context.user_data["gotelegram_wait_port"] = False
|
||||||
|
await do_install(update, context)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
async def do_install(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
domain = context.user_data.get("gotelegram_domain") or "google.com"
|
||||||
|
port = context.user_data.get("gotelegram_port") or "443"
|
||||||
|
if update.callback_query:
|
||||||
|
msg = update.callback_query.message
|
||||||
|
await msg.edit_text("⏳ Генерация secret и запуск контейнера...", reply_markup=None)
|
||||||
|
else:
|
||||||
|
msg = update.message
|
||||||
|
chat = msg.chat
|
||||||
|
if not update.callback_query:
|
||||||
|
await chat.send_message("⏳ Генерация secret и запуск контейнера...")
|
||||||
|
|
||||||
|
# generate secret
|
||||||
|
code, secret_out, err = await run_cmd(
|
||||||
|
"docker", "run", "--rm", "nineseconds/mtg:2", "generate-secret", "--hex", domain,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
if code != 0:
|
||||||
|
await chat.send_message(f"❌ Ошибка генерации secret: {err or secret_out}")
|
||||||
|
return
|
||||||
|
secret = (secret_out or "").strip().split()[-1] or secret_out.strip()
|
||||||
|
if not secret:
|
||||||
|
await chat.send_message("❌ Не удалось получить secret.")
|
||||||
|
return
|
||||||
|
|
||||||
|
await run_cmd("docker", "stop", CONTAINER_NAME, timeout=15)
|
||||||
|
await run_cmd("docker", "rm", CONTAINER_NAME, timeout=10)
|
||||||
|
code, _, err = await run_cmd(
|
||||||
|
"docker", "run", "-d", "--name", CONTAINER_NAME, "--restart", "always",
|
||||||
|
"-p", f"{port}:{port}",
|
||||||
|
"nineseconds/mtg:2", "simple-run", "-n", "1.1.1.1", "-i", "prefer-ipv4", f"0.0.0.0:{port}", secret,
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
if code != 0:
|
||||||
|
await chat.send_message(f"❌ Ошибка запуска контейнера: {err}")
|
||||||
|
return
|
||||||
|
ip = await get_ip()
|
||||||
|
link = f"tg://proxy?server={ip}&port={port}&secret={secret}"
|
||||||
|
text = (
|
||||||
|
"✅ Прокси установлен.\n"
|
||||||
|
f"Домен: {html.escape(domain)}, порт: {html.escape(port)}\n\n"
|
||||||
|
f"Ссылка:\n<code>{html.escape(link)}</code>"
|
||||||
|
)
|
||||||
|
await chat.send_message(text, parse_mode="HTML")
|
||||||
|
context.user_data.pop("gotelegram_domain", None)
|
||||||
|
context.user_data.pop("gotelegram_port", None)
|
||||||
|
context.user_data.pop("gotelegram_wait_port", None)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_port_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
if not update.message:
|
||||||
|
return
|
||||||
|
if not context.user_data.get("gotelegram_wait_port"):
|
||||||
|
return
|
||||||
|
text = (update.message.text or "").strip()
|
||||||
|
if not re.match(r"^[0-9]+$", text):
|
||||||
|
return
|
||||||
|
port_num = int(text)
|
||||||
|
if not (1 <= port_num <= 65535):
|
||||||
|
await update.message.reply_text("Введите число от 1 до 65535.")
|
||||||
|
return
|
||||||
|
context.user_data["gotelegram_port"] = str(port_num)
|
||||||
|
context.user_data["gotelegram_wait_port"] = False
|
||||||
|
await do_install(update, context)
|
||||||
|
|
||||||
|
|
||||||
|
async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
await start(update, context)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
if not BOT_TOKEN:
|
||||||
|
raise SystemExit("Установите BOT_TOKEN в .env или в переменных окружения.")
|
||||||
|
app = (
|
||||||
|
Application.builder()
|
||||||
|
.token(BOT_TOKEN)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
app.add_handler(CommandHandler("start", start))
|
||||||
|
app.add_handler(CommandHandler("help", help_cmd))
|
||||||
|
app.add_handler(CommandHandler("install", install_choice_domain))
|
||||||
|
app.add_handler(CommandHandler("status", cmd_status))
|
||||||
|
app.add_handler(CommandHandler("link", cmd_link))
|
||||||
|
app.add_handler(CommandHandler("remove", cmd_remove))
|
||||||
|
app.add_handler(CommandHandler("restart", cmd_restart))
|
||||||
|
app.add_handler(CommandHandler("logs", cmd_logs))
|
||||||
|
app.add_handler(CommandHandler("promo", cmd_promo))
|
||||||
|
app.add_handler(CallbackQueryHandler(install_callback))
|
||||||
|
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_port_message))
|
||||||
|
app.run_polling(allowed_updates=Update.ALL_TYPES)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
4
gotelegram-bot/config.example.env
Normal file
4
gotelegram-bot/config.example.env
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Скопируйте в .env и заполните
|
||||||
|
BOT_TOKEN=your_bot_token_from_@BotFather
|
||||||
|
# Опционально: список ID пользователей с доступом (через запятую). Пусто = все.
|
||||||
|
# ALLOWED_IDS=123456789,987654321
|
||||||
1
gotelegram-bot/requirements.txt
Normal file
1
gotelegram-bot/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python-telegram-bot>=21.0
|
||||||
139
install_gotelegram_bot.sh
Normal file
139
install_gotelegram_bot.sh
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Установка GoTelegram MTProxy Bot (по образцу gokaskad).
|
||||||
|
# Запуск: curl -sL URL/install_gotelegram_bot.sh -o /tmp/install_gotelegram_bot.sh && sudo bash /tmp/install_gotelegram_bot.sh
|
||||||
|
# Или с токеном GitHub (приватный репо): curl -sL -H "Authorization: token YOUR_GITHUB_TOKEN" URL -o /tmp/install_gotelegram_bot.sh && sudo bash /tmp/install_gotelegram_bot.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo -e "${RED}Запустите скрипт с sudo.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BOT_DIR="/opt/gotelegram-bot"
|
||||||
|
SERVICE_NAME="gotelegram-bot"
|
||||||
|
REPO_URL="${GOTETELEGRAM_BOT_REPO:-https://github.com/anten-ka/gotelegram_pro}"
|
||||||
|
# Для приватного репо задайте GITHUB_TOKEN перед запуском или в одной команде:
|
||||||
|
# GITHUB_TOKEN=ghp_xxx curl -sL -H "Authorization: token $GITHUB_TOKEN" ...
|
||||||
|
|
||||||
|
echo -e "${GREEN}[*] Установка GoTelegram Bot...${NC}"
|
||||||
|
|
||||||
|
# Зависимости
|
||||||
|
if ! command -v python3 &>/dev/null; then
|
||||||
|
if command -v apt-get &>/dev/null; then
|
||||||
|
apt-get update && apt-get install -y python3 python3-pip python3-venv
|
||||||
|
elif command -v dnf &>/dev/null; then
|
||||||
|
dnf install -y python3 python3-pip python3-virtualenv 2>/dev/null || dnf install -y python3 python3-pip
|
||||||
|
elif command -v yum &>/dev/null; then
|
||||||
|
yum install -y python3 python3-pip
|
||||||
|
else
|
||||||
|
echo -e "${RED}Установите python3 вручную.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if ! command -v docker &>/dev/null; then
|
||||||
|
echo -e "${YELLOW}[!] Docker не найден. Установите Docker для работы /install.${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Каталог бота
|
||||||
|
mkdir -p "$BOT_DIR"
|
||||||
|
cd "$BOT_DIR"
|
||||||
|
|
||||||
|
# Откуда брать файлы: локальная папка (клонированный репо) или скачивание
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
if [ -f "$SCRIPT_DIR/gotelegram-bot/bot.py" ]; then
|
||||||
|
echo -e "${GREEN}[*] Копирование файлов из $SCRIPT_DIR/gotelegram-bot${NC}"
|
||||||
|
cp -r "$SCRIPT_DIR/gotelegram-bot"/* "$BOT_DIR/"
|
||||||
|
else
|
||||||
|
# Приватный репо: клонируем по токену (raw URL с токеном для приватного не работает)
|
||||||
|
if [ -n "$GITHUB_TOKEN" ] && command -v git &>/dev/null; then
|
||||||
|
echo -e "${GREEN}[*] Клонирование приватного репозитория (HTTPS + токен)...${NC}"
|
||||||
|
CLONE_DIR="/tmp/gotelegram_pro_fetch_$$"
|
||||||
|
trap "rm -rf '$CLONE_DIR'" EXIT
|
||||||
|
REPO_PATH="${REPO_URL#https://}"
|
||||||
|
REPO_PATH="${REPO_PATH#http://}"
|
||||||
|
git clone --depth 1 --branch "${GIT_BRANCH:-main}" "https://${GITHUB_TOKEN}@${REPO_PATH}" "$CLONE_DIR" 2>/dev/null || {
|
||||||
|
echo -e "${RED}Клонирование не удалось. Проверьте GITHUB_TOKEN и доступ к репо.${NC}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if [ -f "$CLONE_DIR/gotelegram-bot/bot.py" ]; then
|
||||||
|
cp -r "$CLONE_DIR/gotelegram-bot"/* "$BOT_DIR/"
|
||||||
|
fi
|
||||||
|
rm -rf "$CLONE_DIR"
|
||||||
|
trap - EXIT
|
||||||
|
fi
|
||||||
|
# Если файлов всё ещё нет — пробуем raw (только для публичного репо)
|
||||||
|
if [ ! -f "$BOT_DIR/bot.py" ]; then
|
||||||
|
echo -e "${YELLOW}[*] Скачивание файлов из репозитория (публичный доступ)...${NC}"
|
||||||
|
for f in bot.py requirements.txt config.example.env; do
|
||||||
|
if [ -n "$GITHUB_TOKEN" ]; then
|
||||||
|
curl -sL -f -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
|
"$REPO_URL/raw/main/gotelegram-bot/$f" -o "$BOT_DIR/$f" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
[ ! -f "$BOT_DIR/$f" ] && curl -sL -f "$REPO_URL/raw/main/gotelegram-bot/$f" -o "$BOT_DIR/$f" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ ! -f "$BOT_DIR/bot.py" ]; then
|
||||||
|
echo -e "${RED}Не удалось получить файлы бота.${NC}"
|
||||||
|
echo -e " Для приватного репо: задайте GITHUB_TOKEN и убедитесь, что установлен git."
|
||||||
|
echo -e " Или клонируйте репо вручную и запустите: sudo ./install_gotelegram_bot.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# venv и зависимости
|
||||||
|
if [ ! -d "$BOT_DIR/venv" ]; then
|
||||||
|
python3 -m venv "$BOT_DIR/venv"
|
||||||
|
fi
|
||||||
|
"$BOT_DIR/venv/bin/pip" install -r "$BOT_DIR/requirements.txt" -q
|
||||||
|
|
||||||
|
# Конфиг
|
||||||
|
if [ ! -f "$BOT_DIR/.env" ]; then
|
||||||
|
echo -e "${YELLOW}Введите BOT_TOKEN от @BotFather:${NC}"
|
||||||
|
TOKEN=""
|
||||||
|
while [ -z "$TOKEN" ]; do
|
||||||
|
read -r TOKEN
|
||||||
|
TOKEN=$(echo "$TOKEN" | tr -d '[:space:]')
|
||||||
|
[ -z "$TOKEN" ] && echo -e "${RED}Токен не может быть пустым. Повторите:${NC}"
|
||||||
|
done
|
||||||
|
{
|
||||||
|
echo "BOT_TOKEN=$TOKEN"
|
||||||
|
[ -f "$BOT_DIR/config.example.env" ] && grep -v "^BOT_TOKEN=" "$BOT_DIR/config.example.env" | grep -v "^#"
|
||||||
|
} > "$BOT_DIR/.env"
|
||||||
|
chmod 600 "$BOT_DIR/.env"
|
||||||
|
echo -e "${GREEN}[*] .env создан.${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}[*] .env уже есть.${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# systemd
|
||||||
|
cat > "/etc/systemd/system/${SERVICE_NAME}.service" << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=GoTelegram MTProxy Bot
|
||||||
|
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
|
||||||
|
Environment=PATH=$BOT_DIR/venv/bin:/usr/bin
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable "$SERVICE_NAME"
|
||||||
|
systemctl restart "$SERVICE_NAME" 2>/dev/null || systemctl start "$SERVICE_NAME"
|
||||||
|
echo -e "${GREEN}[*] Сервис $SERVICE_NAME установлен и запущен.${NC}"
|
||||||
|
echo -e "Проверка: systemctl status $SERVICE_NAME"
|
||||||
|
echo -e "Логи: journalctl -u $SERVICE_NAME -f"
|
||||||
|
echo -e "Настройки: $BOT_DIR/.env (BOT_TOKEN, ALLOWED_IDS)"
|
||||||
|
exit 0
|
||||||
54
push_to_github.bat
Normal file
54
push_to_github.bat
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
setlocal
|
||||||
|
cd /d "%~dp0"
|
||||||
|
|
||||||
|
set REMOTE=git@github.com:anten-ka/gotelegram_pro.git
|
||||||
|
set BRANCH=main
|
||||||
|
|
||||||
|
echo [*] Репозиторий: https://github.com/anten-ka/gotelegram_pro
|
||||||
|
echo [*] Папка: %CD%
|
||||||
|
echo.
|
||||||
|
|
||||||
|
where git >nul 2>nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Ошибка: git не найден. Установите Git for Windows.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist ".git" (
|
||||||
|
echo [*] Инициализация репозитория...
|
||||||
|
git init
|
||||||
|
)
|
||||||
|
|
||||||
|
git remote remove origin 2>nul
|
||||||
|
git remote add origin %REMOTE%
|
||||||
|
git branch -M %BRANCH%
|
||||||
|
git add .
|
||||||
|
git status
|
||||||
|
|
||||||
|
set /p CONFIRM="Закоммитить и отправить на GitHub? (y/n): "
|
||||||
|
if /i not "%CONFIRM%"=="y" (
|
||||||
|
echo Отменено.
|
||||||
|
pause
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
|
||||||
|
git commit -m "GoTelegram MTProxy + bot (gotelegram_pro)" 2>nul || git commit --allow-empty -m "Update"
|
||||||
|
echo [*] Отправка на origin/%BRANCH%...
|
||||||
|
git push -u origin %BRANCH%
|
||||||
|
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo Не удалось отправить. Проверьте:
|
||||||
|
echo 1. Репо создан на GitHub: https://github.com/anten-ka/gotelegram_pro
|
||||||
|
echo 2. Доступ по SSH: ssh -T git@github.com
|
||||||
|
echo 3. Или настройте токен: git remote set-url origin https://ВАШ_ТОКЕН@github.com/anten-ka/gotelegram_pro.git
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Готово: https://github.com/anten-ka/gotelegram_pro
|
||||||
|
pause
|
||||||
Reference in New Issue
Block a user