64 KiB
goTelegram Pro — техническая документация для ИИ-агентов
Версия: 2.5.0
Репозиторий: anten-ka/gotelegram_pro
Активная ветка: beta для публичной проверки; alpha — личная экспериментальная ветка владельца; main — продакшен.
Целевая ОС: Ubuntu 20.04+, Debian 11+
Этот документ описывает устройство проекта с максимальным количеством нюансов — все ловушки, на которые мы уже наступали, все причины «почему именно так», формат всех внешних интерфейсов, и checklist действий для типовых задач. Цель: чтобы новый агент мог продолжить работу без повторения ошибок и без регрессий.
1. Общая картина
goTelegram Pro — это менеджер MTProxy для Telegram, собранный вокруг Rust-ядра telemt (порт mtproto-proxy с поддержкой fake-TLS, v3.3.x). Проект даёт три вещи:
- CLI-меню на bash (
install.sh+lib/*.sh) — установка, настройка, обновление, бекап, перезапуск, смена режима, управление сайтом-маскировкой, выбор шаблона. Единая точка входаgotelegram(symlink →/opt/gotelegram/install.sh). - Сайт-маскировку — поднимает рядом nginx с настоящим сайтом на настоящем домене (Let's Encrypt) из каталога 1801 HTML-шаблонов (html5up / startbootstrap / ThemeWagon / dawidolko). В stealth-режиме telemt слушает 443, маскировочный трафик проксирует на локальный nginx (127.0.0.1:8443) через
dns_overrides. - Telegram-бота (
gotelegram-bot/bot.py, python-telegram-bot v21+) — управление прокси со смартфона: статус/ссылка/QR/перезапуск/бекап/смена режима/смена домена/смена шаблона/переключение языка per-user (RU/EN).
Архитектура stealth-режима:
Клиент Telegram ──┐
├─► anten-ka.com:443 (telemt, 0.0.0.0:443)
Обычный браузер ───┘ │
│ dns_overrides:
▼ "anten-ka.com:8443:127.0.0.1"
127.0.0.1:8443 (nginx)
│
▼
/var/www/gotelegram-site/ (HTML шаблон)
Lite-режим (без домена):
Клиент Telegram ─► IP:443 (telemt) ─► Telegram DC
Fake-TLS эмулируется (tls_emulation=true), mask-трафик падает никуда
tls_domain = google.com (или любой из QUICK_DOMAINS)
2. Репозиторий и ветки
anten-ka/gotelegram_pro
├── main ← продакшен, максимально стабильная версия
├── beta ← публичная бета для пользователей, готовых к риску и поиску багов
└── alpha ← личная alpha ветка владельца для самых ранних изменений
Правило коммитов: новые изменения сначала проверяются в alpha, затем после ручной проверки идут в beta. В main попадает только проверенный beta-код после отдельного решения о релизе. Перед любым переносом между ветками создавай rollback tag/release для текущего состояния ветки.
Инструменты для коммитов:
- Основной путь — обычный
git commit+git pushв нужную ветку после локальной проверки. - Если окружение не может пушить напрямую, используй GitHub REST API с PAT из переменной окружения
GOTELEGRAM_PAT. - Workflow через GitHub API:
POST git/blobsдля каждого файла →POST git/trees(сbase_treeот текущего HEAD) →POST git/commits(parents=[текущий HEAD]) →PATCH git/refs/heads/alphaи/илиPATCH git/refs/heads/beta(sha=новый commit) → при необходимостиPOST /releases. - Важно про
base_tree: при частичном обновлении (1-2 файла) ОБЯЗАТЕЛЬНО передаватьbase_tree— иначе дерево получится только из переданных файлов, и все остальные файлы пропадут из коммита.base_treeможно опускать только при коммите с полным набором файлов.
3. Карта файлов
install.sh главная точка входа, CLI-меню из 14 пунктов
install_gotelegram_bot.sh legacy-установщик бота (функционал продублирован в install.sh)
bootstrap.sh установщик приватного репо через raw.githubusercontent.com с PAT
templates_catalog.json каталог 1801 шаблонов, 18 категорий, 4 источника (~460KB)
DOCS_HUMAN.md документация для пользователя (этот каталог)
DOCS_AI.md этот файл
lib/common.sh цвета, log_*, confirm, select_option, _valid_ip, config_get,
save_gotelegram_config, get_server_ip, run_with_spinner,
version, GOTELEGRAM_VERSION, пути
lib/telemt.sh download_telemt, install_telemt_full, start/stop/restart_telemt,
update_telemt, remove_telemt, telemt_status, telemt_logs,
install_telemt_service (systemd юнит)
lib/telemt_config.sh generate_telemt_toml (TOML v3), generate_proxy_link,
get_config_value, validate_telemt_config, QUICK_DOMAINS[],
select_quick_domain, select_port, show_proxy_info[_pro]
lib/templates_catalog.sh download_template, select_category, select_template,
show_template_preview, поддержка 5 источников
lib/website.sh nginx + certbot + деплой шаблона
lib/backup.sh create_backup, restore_backup, list_backups
lib/i18n.sh t(), tf(), switch_language(), загрузка lang/ru.sh и lang/en.sh
lib/lang/ru.sh 328 i18n ключей на русском
lib/lang/en.sh 328 i18n ключей на английском
lib/stats.sh телеметрия (опциональная)
gotelegram-bot/bot.py Telegram-бот (python-telegram-bot v21+)
gotelegram-bot/config.example.env
gotelegram-bot/requirements.txt
gotelegram-bot/README.md
gotelegram-bot/locales/*.json 99 ключей i18n для бота с per-user persistence
Где что лежит на VPS после установки:
| Что | Путь |
|---|---|
| Репо-скрипты | /opt/gotelegram/ |
| Symlink запуска | /usr/local/bin/gotelegram → /opt/gotelegram/install.sh |
| Конфиг goTelegram Pro (JSON) | /opt/gotelegram/config.json |
| Конфиг telemt | /etc/telemt/config.toml |
| Бинарник telemt | /usr/local/bin/telemt |
| Systemd юнит telemt | /etc/systemd/system/telemt.service |
| Bot | /opt/gotelegram-bot/ |
| Systemd юнит бота | /etc/systemd/system/gotelegram-bot.service |
| Сайт | /var/www/gotelegram-site/ |
| nginx конфиг | /etc/nginx/sites-available/gotelegram |
| nginx enabled | /etc/nginx/sites-enabled/gotelegram |
| Бекапы | /opt/gotelegram/backups/ |
| Лог goTelegram Pro | /var/log/gotelegram.log |
| Логи telemt | journalctl -u telemt |
| Логи бота | journalctl -u gotelegram-bot |
4. Формат telemt v3 TOML (КРИТИЧЕСКИ ВАЖНО)
telemt v3.3.39 использует собственный TOML-формат, несовместимый с mtg и mtproto-proxy. Попытка скормить ему старый формат ([security], [[users]], [listen] bind_to) приводит к тому, что telemt молча игнорирует секции и запускается с дефолтами → клиенты отваливаются с ошибкой SNI.
Минимальный рабочий конфиг для Lite-режима
[server]
port = 443
listen_addr_ipv4 = "0.0.0.0"
[censorship]
tls_domain = "google.com"
mask = true
mask_port = 443
tls_emulation = true # true → telemt сам эмулирует TLS handshake от имени tls_domain
[access.users]
main = "HEX_SECRET_32" # 16 байт = 32 hex символа, БЕЗ префикса ee
Минимальный рабочий конфиг для Pro-режима (stealth)
[server]
port = 443
listen_addr_ipv4 = "0.0.0.0"
[censorship]
tls_domain = "anten-ka.com"
mask = true
mask_port = 8443
tls_emulation = false # false → mask-трафик идёт на mask_port, nginx имеет свой Let's Encrypt cert
[access.users]
main = "HEX_SECRET_32"
[network]
dns_overrides = ["anten-ka.com:8443:127.0.0.1"]
# формат host:port:ip — именно три поля через двоеточие
Поля по секциям (полный набор, который telemt принимает в дефолтном gen-config)
[general]— modes, telemetry, links (опционально, можно не трогать).[general.modes]— включение/отключение режимов прокси.[general.telemetry]— отправка статистики (по умолчанию выключено).[general.links]— формат публикуемых ссылок.[server]—port,listen_addr_ipv4,listen_addr_ipv6.[server.api]— HTTP-админка (не используем).[server.conntrack_control]— ограничения на conntrack.[timeouts]— таймауты handshake, idle и т.д.[network]—stun_servers,dns_overrides.[censorship]—tls_domain,mask,mask_port,tls_emulation,unknown_sni_action(значения:Drop,Proxy).[censorship.tls_fetch]— параметры получения реального cert от tls_domain (используется только еслиtls_emulation=falseИ нет dns_overrides).[access]— rate limits, доступ.[access.users]— таблицаname = "secret"(секрет — 32 hex).[access.user_max_unique_ips]— опциональная таблицаname = число, ограничивает одновременные уникальные IP на ключ; в goTelegram Pro значение0в UI удаляет строку и означает безлимит.
Почему unknown_sni_action = Drop нас кусал
В Pro-режиме при старом конфиге с tls_domain = anten-ka.com telemt дропает всех клиентов, которые приходят с другим SNI. Если потом перегенерировать конфиг в Lite (tls_domain = google.com), но НЕ перезапустить telemt полноценно (systemctl start no-op на живом сервисе), то у telemt в памяти остаётся старое anten-ka.com, и клиенты с SNI=google.com дропаются. Симптом пользователя: «ключ Lite не работает, telemt живой». Фикс — в start_telemt(), см. раздел 10, баг #23.
Fake-TLS секрет (ee-формат)
Что присылается клиенту в ссылке tg://proxy?...:
секрет_в_ссылке = "ee" + <hex_secret_32chars> + <hex(tls_domain)>
Пример для secret=2de6920b1e17ccd440933ba0600f578f6 (длинное — 32 hex) и domain=google.com:
- hex(google.com) =
676f6f676c652e636f6d - итог:
ee2de6920b1e17ccd440933ba0600f578f676f6f676c652e636f6d
В конфиге telemt ([access.users] main = ...) секрет хранится без префикса ee и без hex-домена. telemt сам склеивает при handshake. Функция generate_proxy_link() в lib/telemt_config.sh делает эту конкатенацию при формировании ссылки.
Systemd юнит
Генерируется функцией install_telemt_service() в lib/telemt.sh:
[Unit]
Description=goTelegram Pro MTProxy (telemt engine)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/telemt run /etc/telemt/config.toml
Restart=always
RestartSec=5
LimitNOFILE=65535
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
ProtectSystem=full(НЕstrict!) — telemt пишет cache-файлы, приstrictон падает.User=root— telemt нужен для bind на 443. Можно заменить наtelemt+AmbientCapabilities=CAP_NET_BIND_SERVICE, но это усложнение ради эстетики.
5. Жизненный цикл установки (Lite)
Функция install_lite_mode в install.sh. Порядок:
select_quick_domain(lib/telemt_config.sh) — интерактивный выборtls_domainиз списка QUICK_DOMAINS[] (20 доменов: google.com, microsoft.com, cloudflare.com, apple.com, amazon.com, github.com …). Функция ОБЯЗАТЕЛЬНО выводит UI через>&2, потому что она вызывается через$()— см. раздел 10, баг #14.select_port— порт (443 по умолчанию, проверяется занятость черезcheck_port).- Генерация секрета:
openssl rand -hex 16→ 32 hex символа. install_telemt_full→download_telemt(скачивает бинарник из telemt/telemt GitHub Releases с фильтромtelemt-x86_64-linux-gnu.tar.gz) →install_telemt_service→enable_telemt.generate_telemt_toml "$secret" "$port" "lite" "$domain" "$port"→ пишет/etc/telemt/config.toml.save_gotelegram_config→ пишет/opt/gotelegram/config.jsonс полямиmode=lite,domain="",mask_host=$domain,secret,port.start_telemt→ restart если уже active (см. баг #23), иначеstart. Проверяетsystemctl is-activeчерез 2 сек.show_proxy_info— выводит IP/port/secret/tls_domain иtg://proxy?...ссылку, QR через qrencode если есть.
6. Жизненный цикл установки (Pro / stealth)
Функция install_pro_mode в install.sh. Добавляет к Lite-флоу:
- Запрос домена (
read_user_input domain),validate_domain— проверка формата. dig +short $domain→ проверка DNS = IP VPS. Если не совпало — предупреждение, но продолжаем (пользователь может знать лучше).apt install nginx certbot python3-certbot-nginx(если ещё нет).interactive_template_selection→select_category→select_template→show_template_preview→ возвращаетtpl_id. Все UI через>&2— иначе ID замусоривается.download_template "$tpl_id"→ клонирует репо шаблона в temp, проверяетindex.html, копирует в/var/www/gotelegram-site/. Для StartBootstrap проверяетdist/index.html— см. баг #21.- Запись временного nginx-конфига на порту 80 (для challenge), reload nginx.
certbot --nginx -d $domain→ получает Let's Encrypt сертификат.- Переписывание nginx-конфига: listen
127.0.0.1:8443 ssl, root/var/www/gotelegram-site, используем cert от certbot. - Генерация
telemt/config.tomlв режимеproсtls_emulation=false,mask_port=8443,dns_overrides = ["$domain:8443:127.0.0.1"]. save_gotelegram_config mode=pro domain=$domain ....start_telemt(restart-safe) →show_proxy_info_proвыводит ссылку через доменное имя.
7. Правила subshell-capture (железно)
Это самое частое место ошибок в проекте. Любая функция, которая вызывается через $(...) для получения значения, должна писать ВСЕ логи и UI в stderr (>&2). Единственный разрешённый вывод в stdout — это финальный echo "$result" с возвращаемым значением.
Что обязательно >&2:
- Все
log_info/success/warning/error/step/dimвlib/common.sh(это уже сделано). confirm,select_optionвlib/common.sh(сделано).select_quick_domain,select_portвlib/telemt_config.sh(сделано).select_category,select_template,show_template_previewвlib/templates_catalog.sh(сделано, баг #18 был о том, что 4 строки в show_template_preview выводили без >&2).- Любой
echo/printfвнутриdownload_templateпри ошибочном пути — см. баг #22 (ls -laбез>&2замусоривал вывод). - Любая новая интерактивная функция, которую добавляешь.
Чек-лист когда пишешь новую функцию:
- Она вызывается через
$()? → все echo/printf/log_* через>&2, кроме финального. - Возвращает строку через echo → именно одна финальная строка, без лишних переводов строки.
- Ошибочный путь (early return) → НЕ писать в stdout, только в stderr,
return 1.
8. SCRIPT_DIR и symlink
install.sh запускается через symlink /usr/local/bin/gotelegram → /opt/gotelegram/install.sh. Если наивно использовать dirname "${BASH_SOURCE[0]}", получим /usr/local/bin, а там нет каталога lib/. Правильный паттерн:
SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
readlink -f резолвит symlink до реального файла → SCRIPT_DIR=/opt/gotelegram, и source "$SCRIPT_DIR/lib/common.sh" работает. Это зафиксировано в баге #19.
9. Каталог шаблонов
Файл templates_catalog.json, ~460KB, ~18000 строк. Формат:
{
"version": "2.4.1",
"sources": ["html5up", "startbootstrap", "themewagon", "dawidolko"],
"categories": ["landing", "portfolio", "agency", "saas", "restaurant", ...],
"templates": [
{
"id": "h5up_massively",
"name": "Massively",
"source": "html5up",
"repo": "https://github.com/html5up-inc/massively.git",
"category": "personal",
"preview": "https://html5up.net/massively"
},
...
]
}
Источники и как они скачиваются (download_template в lib/templates_catalog.sh):
| Источник | Префикс id | Метод | Где index.html |
|---|---|---|---|
| html5up | h5up_* |
git clone --depth 1 $repo |
в корне |
| startbootstrap | sb_* |
git clone --depth 1 → ищем dist/index.html → копируем dist/* |
в dist/ |
| themewagon | tw_* |
git clone --depth 1 $repo (каждый шаблон в отдельном репо) |
в корне |
| dawidolko | dw_* / colorlib_* |
sparse checkout одного большого репо | в подпапке |
Fallback: если по известным правилам index.html не найден, download_template делает find -name "index.html" по всему клону и берёт первый. Это спасает для нестандартных структур.
ColorlibHQ отброшен — оказались WordPress-темы (PHP), index.html пустой. Не пытаться включать обратно.
10. История багов (не наступать на те же грабли)
Все решены в текущем HEAD (beta/alpha). Перечисление для того, чтобы новый агент не «чинил» то, что уже починено, и понимал контекст.
telemt.sh grep— URL форматtelemt-x86_64-linux-gnu.tar.gz, arch передlinux. Нуженgrep -iE "$arch_pattern"+ цепочка фильтров (grep -i linux,grep -v sha256,grep gnu,head -1).bot.py safe_edit_message— обёртка дляquery.edit_message_text, ловитBadRequest: message is not modified.bot.py QR cleanup—os.remove(qr_file)вfinallyблоке.common.sh _valid_ip— проверка октетов 0-255, раньше пропускал 999.common.sh os-release injection— блокирует;, backticks,$(,${при парсинге/etc/os-release.common.sh config_get— return codes:0=ok,2=файл отсутствует,3=невалидный JSON.common.sh run_with_spinner— stderr в temp-файл, показ первых 3 строк при ошибке.install.sh— проверка пустого домена передvalidate_domain(валидатор падал на пустой строке).install.sh mode_choice— санитизация${mode_choice:-}чтобыset -uне ронял скрипт.backup.sh— инициализацияfinal_file/tar_file/backup_fileперед ветвлением (иначе unset var).bot.py XSS—html.escape(preview_url, quote=True)с двойными кавычками.common.sh— версия была устаревшая, обновлена (сейчас 2.4.1).install.sh— добавлен пункт 12 меню (Telegram-бот) с подменю установка/статус/логи/настройки/удаление.- КРИТИЧЕСКИЙ subshell capture — интерактивные функции (
select_quick_domain,select_port,select_category,select_template,show_template_preview) выводили UI в stdout. Вызов через$()→ меню уходило в переменную. Фикс: весь UI через>&2. - КРИТИЧЕСКИЙ download_telemt extract —
find -newerне находил извлечённый файл (таймстамп архива старше). Фикс: извлечение в отдельную директорию$extract_dir+ проверка размера файла + fallback черезfileдля определения ELF. common.sh log_*— всеlog_info/success/warning/error/step/dimвыводят в stderr (>&2).common.sh confirm/select_option— UI через>&2.- КРИТИЧЕСКИЙ show_template_preview stdout leak — 4 строки (блок «Спасибо авторам» + разделители) выводили без
>&2. Цепочкаinteractive_template_selection → select_template → show_template_preview→ мусор подмешивался кtpl_id→download_templateполучал мусорный ID → «шаблон не содержит index.html». Фикс:>&2ко всем 4 echo. - symlink SCRIPT_DIR —
readlink -f "${BASH_SOURCE[0]}"для резолва symlink/usr/local/bin/gotelegram. - bootstrap.sh — скачивание приватного репо через
raw.githubusercontent.com/.../bootstrap.sh?token=..., создание symlink, запуск install.sh. - КРИТИЧЕСКИЙ StartBootstrap dist/ — sb_* шаблоны хранят production в
dist/. Фикс: клонируем в$sb_tmp, проверяемdist/index.html, копируемdist/*в$clone_dir, + universal fallback черезfind. - templates_catalog.sh ls stdout leak —
ls -laв блоке ошибкиdownload_templateшёл в stdout. Фикс:>&2. - КРИТИЧЕСКИЙ start_telemt stale config (v2.4.1) —
systemctl startэто no-op для уже активного сервиса. После переустановки Lite поверх Pro конфиг на диске менялся, но telemt держал в памяти старыйtls_domain=anten-ka.comи дропал клиентов с SNI=google.com. Фикс:start_telemtтеперь делаетrestartесли сервис уже активен. См.lib/telemt.sh:189-213. - КРИТИЧЕСКИЙ safe_edit_message TypeError (v2.4.2) — в iter2 аудите субагент нашёл:
cb_pro_confirmв success-пути вызывалsafe_edit_message(query, text, ..., disable_web_page_preview=True), но сигнатура обёртки этот kwarg не принимала. Runtime TypeError прямо в хэппи-пути смены шаблона из бота. Фикс: добавленdisable_web_page_preview: Optional[bool] = None+ условный форвард через**kwargs. - template_id field name mismatch (v2.4.2) —
save_gotelegram_configвсегда писал ключtemplate_id, ноbot.pyчиталconfig.get('template')и писалconfig['template']вhandle_text_message. Результат: статус шаблона в боте никогда не отображался, а поле в JSON появлялось фантомно и не использовалось. Фикс: везде толькоtemplate_id. Исторические чтения совместимы черезconfig.get("template_id") or config.get("template")для legacy конфигов. - jq 1.5 compat в bot_update_config_field (v2.4.2) — использовалось
jq '... | .updated_at = (now | todate)', но фильтрnow|todateтолько с jq 1.6. На Debian 10 jq 1.5 падал с syntax error, config не обновлялся. Фикс: генерим timestamp черезdate -Isecondsв shell и передаём черезjq --arg t. - Отсутствующая валидация tpl_id/domain (v2.4.2) —
tpl_idизcallback_dataиdomainиз текстового ввода передавались напрямую в subprocess как--template=$x. Defense-in-depth: в bot.py добавлены_TPL_ID_RE = ^[A-Za-z0-9_-]{1,64}$и_DOMAIN_RE, в install.sh —validate_domainпередgenerate_telemt_toml. Малформный ввод отвергается early. - КРИТИЧЕСКИЙ race в bot_action_dispatch (v2.4.3) — iter3-тест с 3 параллельными
change-lite-domainдал{"status":"error","code":"no_secret"}на одном из вызовов. Причина:bot_update_config_fieldделаетjq ... > tmp && mv tmp config.json; когда параллельный процесс заходил вget_config_value secretв момент между>иmv, он видел пустой/частичный файл.asyncio.Lockв боте ловил только внутри-процессные гонки, но не CLI-level. Фикс:flock -w 30 9 < /var/lock/gotelegram-bot-action.lockвокруг всего диспатчера. Новый error code:lock_timeout(EX_TEMPFAIL=75).
11. Telegram-бот
Файл gotelegram-bot/bot.py, python-telegram-bot v21+, systemd сервис gotelegram-bot.service.
Ключевые моменты:
- Admin ID — бот отвечает только пользователю с
ADMIN_TG_IDиз.env. Всё остальное игнорируется. - safe_edit_message — обёртка над
query.edit_message_text+query.edit_message_caption, глотаетBadRequest: message is not modified. Начиная с v2.4.2 принимает опциональныйdisable_web_page_preview— не забудь прокинуть его если показываешь ссылку-превью (раньше вызов с этим kwarg ловил TypeError в runtime). Используй её всегда вместо прямого вызова. - Language per-user — файл
locales/users.jsonхранит{user_id: "ru"/"en"}. При каждом сообщении бот читает язык пользователя и подставляет строку черезt(key, lang). - QR-коды — генерятся в
/tmp/gotelegram_qr_*.png, отправляются какInputFile, удаляются вfinally. - Шаблон preview в HTML — URL экранируется через
html.escape(url, quote=True)(баг #11). - Системные действия (v2.4.2+) — бот реально умеет менять шаблон и домен маскировки. Хелпер
run_bot_action(action, **kwargs)вызываетsubprocess.run(["/opt/gotelegram/install.sh", "--action=X", "--json", ...])и парсит JSON. Два коллбэка:cb_pro_confirm(change-template) иcb_lite_domain(change-lite-domain). Оба обёрнуты вasync with _BOT_ACTION_LOCK(глобальныйasyncio.Lock()) — сериализуют параллельные callback'и внутри процесса бота. Входы валидируются ДО subprocess:_TPL_ID_RE = r"^[A-Za-z0-9_-]{1,64}$",_DOMAIN_RE(RFC-like). Малформный ввод отвергается с понятным сообщением, не доходя до shell. - Поле
template_idв config.json — канонический ключ для текущего шаблона. Раньше (до v2.4.2) бот читалconfig['template']и писал в него же вhandle_text_message, ноsave_gotelegram_configвсегда писалtemplate_id→ поле статуса никогда не отображалось. Используй толькоtemplate_id. - Устанавливается из меню
install.sh → 12) Telegram-бот → Установить. Пользователь вводит BotFather token + свой Telegram ID,.envпишется в/opt/gotelegram-bot/.env. - Обновляется автоматически (v2.5.0 beta+) при повторном bootstrap/update:
auto_update_bot_if_possibleсравнивает новые файлы в$SCRIPT_DIR/gotelegram-bot/с установленными/opt/gotelegram-bot/{bot.py,i18n.py,requirements.txt,lang/*.json}. Если есть отличия и сервис уже установлен, вызываетсяbot_install >/dev/null,.envсохраняется, зависимости обновляются, systemd unit переписывается иgotelegram-botперезапускается. Это закрывает сценарий 2.4.x → 2.5.0, где bootstrap обновлял/opt/gotelegram/gotelegram-bot/, но рабочий сервис продолжал запускать старый/opt/gotelegram-bot/bot.py.
11.1 Non-interactive action bridge (install.sh ↔ bot)
Бот общается с CLI через жёсткий JSON-протокол. Единая точка входа — bot_action_dispatch в install.sh.
/opt/gotelegram/install.sh --action=<name> [--template=ID|--domain=HOST] --json
Доступные action'ы:
change-template --template=<tpl_id>— только в Pro режиме. Скачивает шаблон, деплоит в nginx, обновляетconfig.json.template_id.change-lite-domain --domain=<host>— только в Lite режиме. Регенерит telemt TOML с новымtls_domain, валидирует, рестартит telemt, обновляетconfig.json.{domain,mask_host}.
Формат ответа (stdout, последняя строка):
{"status":"success","message":"...","<extra>":"..."}
{"status":"error","message":"...","code":"<machine_code>"}
Коды ошибок: missing_arg, invalid_domain, wrong_mode, unknown_template, download_failed, deploy_failed, no_secret, gen_failed, validate_failed, restart_failed, unknown_action, lock_timeout.
Сериализация (v2.4.3+): bot_action_dispatch оборачивает вызов в flock -w 30 9 < /var/lock/gotelegram-bot-action.lock. Это защищает от гонок при:
- Одновременных callback'ах внутри бота (asyncio.Lock уже ловит это, но flock — defense-in-depth).
- Параллельных CLI-вызовах (бот + ручной SSH, или два бот-процесса — теоретически).
Если таймаут лока (30 с), диспетчер возвращает exit 75 (EX_TEMPFAIL) и JSON {"status":"error","code":"lock_timeout"}. flock идёт из util-linux — добавлен в critical зависимости в ensure_deps.
История: до v2.4.2 коллбэки были stub'ами («сделай через CLI»). В v2.4.2 подключили реальные action'ы. В iter3-тестировании на VPS обнаружилась гонка: bot_update_config_field делает jq ... > tmp && mv tmp config.json, и параллельный процесс мог прочитать config.json в промежутке, увидев пустоту → ошибка no_secret. v2.4.3 починил flock'ом.
12. i18n (bash CLI)
lib/i18n.sh экспортирует функции:
t "key" # вернуть строку на текущем языке
tf "key" arg1 arg2 # t + printf-интерполяция
switch_language ru|en
Под капотом — ассоциативный массив I18N, ключи в lib/lang/ru.sh и lib/lang/en.sh. ~328 ключей.
Добавление нового ключа:
- Придумай стабильный key (snake_case, без пробелов):
menu_install,error_port_busy. - Добавь строку в
lib/lang/ru.sh:I18N[menu_install]="Установить / обновить". - Добавь строку в
lib/lang/en.sh:I18N[menu_install]="Install / update". - В коде вызови
t menu_install. - Если есть интерполяция — используй
%s/%d:I18N[info_port]="Порт %s свободен"+tf info_port "$port".
Выбор языка сохраняется в $GOTELEGRAM_CONFIG → config.json → ключ lang. Первый запуск — интерактивный выбор.
13. Бекапы
lib/backup.sh. Собирает в .tar.gz:
/etc/telemt/config.toml/opt/gotelegram/config.json/opt/gotelegram/disabled_users.json/var/www/gotelegram-site/(если есть)/opt/gotelegram/custom_templates/,/opt/gotelegram/templates_catalog.json/opt/gotelegram/stats_history.csv,/opt/gotelegram/user_stats_history.csv,/opt/gotelegram/shared-443.json/opt/gotelegram-bot/.env, bot i18n/lang/opt/gotelegram-admin/server.py,/opt/gotelegram-admin/static//etc/letsencrypt/live/<domain>/+/etc/letsencrypt/archive/<domain>/+/etc/letsencrypt/renewal/<domain>.conf(если Pro)/etc/nginx/sites-available/gotelegram(если есть)
Складывает в /opt/gotelegram/backups/gotelegram_backup_YYYYMMDD_HHMMSS.tar.gz.
restore_backup <file> [password] [yes] разворачивает архив обратно, перезапускает telemt, nginx, bot и admin. Третий аргумент yes нужен для неинтерактивного restore из web-admin/бота; перед ним они создают свежий safety backup. Restore понимает legacy-архивы раннего бота backup_*.tar.gz, где внутри лежали только opt/gotelegram/config.json и etc/telemt/config.toml.
Расписания бекапов: set_backup_schedule off|daily|weekly|monthly пишет /etc/systemd/system/gotelegram-backup.{service,timer} и /opt/gotelegram/backup_schedule.json. OnCalendar: daily *-*-* 03:20:00, weekly Sun 03:20:00, monthly *-*-01 03:20:00. Автоматическая чистка держит 30 последних .tar.gz* архивов.
13.1 Local Web Admin (v2.5.0)
Локальная web-админка находится в admin-web/ и устанавливается в /opt/gotelegram-admin:
- backend:
admin-web/server.py, Python stdlib only, без pip/npm dependencies; - frontend:
admin-web/static/, vanilla JS/CSS, SVG-график без CDN; - systemd service:
gotelegram-admin; - bind:
127.0.0.1:1984, доступ только через SSH tunnel; - токена нет: после SSH tunnel открывается
http://127.0.0.1:1984/; - write-запросы дополнительно требуют
X-GoTelegram-Admin: 1, фронтенд добавляет его автоматически. - язык панели читается из
config.json.language, затем из/opt/gotelegram/.language, fallbacken;POST /api/settings/languageсохраняет RU/EN в общий конфиг, marker file и bot.env;gotelegram-bot/i18n.pyиспользует тот же источник как default до per-user override; - UI построен вкладками (
dashboard,traffic,keys,backups,logs,settings), есть иконки меню, полезный overview-блок по реальным TCP/UDP-слушателям 443, light/dark theme вlocalStorageи promo-modal раз в 24 часа черезlocalStorage; /api/overviewотдаётstats_status,admin_bind,site_status,port_443иbackup_schedule;/api/site/checkпроверяетhttps://config.domain/и считает OK только HTTP 200;/api/stats?range=15m|1h|24h|monthотдаёт выбранное окно иsummary_rows;/api/users/<name>/traffic?range=15m|1h|24h|monthотдаёт per-user историю поtelemt total_octets;/api/users/<name>/qrотдаёт PNG QR для Telegram proxy link черезqrencode;POST /api/users/<name>/max-ipsпишет[access.user_max_unique_ips](0удаляет строку и означает безлимит);/api/stats/collectделает разовый сбор,/api/stats/repairустанавливает/перезапускаетgotelegram-stats.
Функции: overview, проверка сайта на HTTP 200, service status/restart, чтение/запись [access.users], enable/disable ключей через /api/users/<name>/enabled, per-user лимит одновременных уникальных IP через [access.user_max_unique_ips], генерация proxy links и QR, общий traffic history из /opt/gotelegram/stats_history.csv, per-user traffic history из /opt/gotelegram/user_stats_history.csv с периодами 15m/1h/24h/month, current stats из /run/gotelegram/stats_current.json, список/создание backup, POST /api/backups/schedule, POST /api/backups/restore (background restore job, только basename из backup dir), структурированные journal logs (service, ok, exit_code, line_count, text).
Traffic retention: обе CSV-истории хранятся максимум 365 дней. Последние 31 день остаются с поминутным разрешением, более старые точки автоматически уплотняются до одной последней cumulative-точки в час. Чистка/уплотнение запускается не чаще одного раза в час, а per-user сбор пишет данные не чаще одного раза в минуту, даже если systemd-loop вызывает stats_collect каждую секунду. Параметры можно переопределить переменными STATS_RETENTION_DAYS, STATS_MINUTE_RETENTION_DAYS, STATS_CLEANUP_INTERVAL.
13.1.1 Shared TCP/443 with 3x-ui/Xray
lib/shared443.sh добавляет управляемую схему shared-443 через nginx stream ssl_preread:
- публичный вход:
0.0.0.0:443принадлежит nginx stream dispatcher; - default backend:
127.0.0.1:7443(telemt), аgeneral.links.public_portостаётся443; - сайт остаётся за telemt через
dns_overridesна127.0.0.1:8443; - Xray/3x-ui должен быть перенесён в панели на внутренний target, например
127.0.0.1:9443, после чегоshared443_enable <domain> <xray-sni> 127.0.0.1:9443пишет/opt/gotelegram/shared-443.jsonи/etc/nginx/stream-conf.d/gotelegram-shared443.conf.
Автоматически переписывать SQLite/JSON 3x-ui нельзя: панель может перегенерировать Xray config и потерять ручные правки. Поэтому goTelegram Pro показывает конфликт прямого bind на 443, даёт маршрут и включает dispatcher только на уровне собственных конфигов/nginx.
Отключённые ключи хранятся в /opt/gotelegram/disabled_users.json: active keys остаются в /etc/telemt/config.toml под [access.users], disabled keys удаляются из active block и могут быть возвращены обратно без потери secret. main защищён от удаления и отключения. Лимит уникальных IP сохраняется в [access.user_max_unique_ips] и не теряется при disable/enable; при удалении ключа строка лимита удаляется. Операции с ключами в web-admin и Telegram-боте берут общий file lock /run/gotelegram/admin-users.lock, TOML пишется через temp+replace и quoted keys ("a.b"), а telemt restart для add/delete/enable/disable/IP-limit ставится через systemctl --no-block restart, чтобы switch в UI не зависал на wait_tcp_port.
install_admin_web вызывается при установке Telegram-бота. auto_install_admin_web_if_possible подхватывает админку после bootstrap/update, если Python уже установлен и файлы отличаются. auto_update_bot_if_possible аналогично подхватывает уже установленный Telegram-бот и обновляет рабочий /opt/gotelegram-bot без запроса токена. При установке админки скрипт пытается установить/перезапустить gotelegram-stats; если это не удалось, оператор может нажать Restart collector в Traffic. Backup v1.6 сохраняет admin_web/server.py, admin_web/static/, disabled_users.json, stats_history.csv, user_stats_history.csv, backup_schedule.json и shared-443.json, restore возвращает их, удаляет legacy admin_web/token и пробует перезапустить gotelegram-admin.
13.2 Upgrade migration (v2.5.0)
install.sh вызывает auto_migrate_legacy_state перед интерактивным меню и перед non-interactive --action=... для бота. В интерактивном запуске после миграции также вызываются auto_update_bot_if_possible и auto_install_admin_web_if_possible, чтобы повторный bootstrap обновлял не только исходники в /opt/gotelegram, но и реально запущенные сервисы /opt/gotelegram-bot и /opt/gotelegram/admin-web. Цель — комфортно обновляться даже с кривой старой логики без переустановки прокси:
- перед изменениями создаётся
/opt/gotelegram/backups/preupgrade_2.5.0_*.tar.gz; - из старого
/etc/telemt/config.tomlвытаскиваются все строки[access.users], а не толькоmain; - если
mainотсутствует, он добавляется с первым найденным секретом, чтобы старые ссылки не потерялись; - сохраняются порт,
tls_domain,mask_port, режим Lite/Pro, домен, язык,stats_enabled; - старый telemt TOML нормализуется под v2.5.0 с
[server.api]и metrics, затем в него возвращается полный users block; - если сайт уже развёрнут, но template id неизвестен или старый
config.jsonврёт, в/var/www/gotelegram-site/.gotelegram_template_idпишетсяdeployed_site; config.jsonпереписывается в актуальный формат, но с сохранениемinstalled_atи пользовательских настроек;- если telemt был активен и TOML был изменён, сервис перезапускается один раз.
Инвариант: миграция должна быть идемпотентной. Маркер /opt/gotelegram/.migrated_2.5.0 предотвращает повторную нормализацию без причины.
14. Checklist: как обновить один файл и запушить
- Прочитай текущее состояние файла:
Readдля локальной версии +git_get_contents(raw.githubusercontent.com) если нужно убедиться что на GitHub то же самое. - Применяй правки через
Editв локальном каталоге/sessions/.../gotelegram-v2/. - Напиши
C:\Temp\push_<описание>.py:import os, base64, json, urllib.request, ssl TOKEN = os.environ["GOTELEGRAM_PAT"] REPO = "anten-ka/gotelegram_pro" BRANCH = "beta" API = f"https://api.github.com/repos/{REPO}" headers = { "Authorization": f"Bearer {TOKEN}", "Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28", "User-Agent": "gotelegram-push", } def req(method, path, body=None): data = json.dumps(body).encode() if body else None r = urllib.request.Request(API + path, data=data, headers={**headers, "Content-Type": "application/json"}, method=method) return json.loads(urllib.request.urlopen(r).read()) # 1. current ref ref = req("GET", f"/git/refs/heads/{BRANCH}") parent_sha = ref["object"]["sha"] commit = req("GET", f"/git/commits/{parent_sha}") base_tree = commit["tree"]["sha"] # 2. blobs files = { "lib/common.sh": open("C:/.../gotelegram-v2/lib/common.sh","rb").read(), "DOCS_AI.md": open("C:/.../gotelegram-v2/DOCS_AI.md","rb").read(), } tree_items = [] for path, content in files.items(): blob = req("POST", "/git/blobs", {"content": base64.b64encode(content).decode(), "encoding": "base64"}) tree_items.append({"path": path, "mode": "100644", "type": "blob", "sha": blob["sha"]}) # 3. tree (С base_tree — обязательно при частичном апдейте) tree = req("POST", "/git/trees", {"base_tree": base_tree, "tree": tree_items}) # 4. commit new_commit = req("POST", "/git/commits", { "message": "v2.4.1: docs + start_telemt restart-safe", "tree": tree["sha"], "parents": [parent_sha], }) # 5. patch ref req("PATCH", f"/git/refs/heads/{BRANCH}", {"sha": new_commit["sha"], "force": False}) print("pushed:", new_commit["sha"]) - Запускай через Desktop Commander
start_processсshell="cmd.exe":НЕ через PowerShell — там stdout не захватывается в нашем окружении.cmd /c "python C:\Temp\push_docs.py" - Проверь результат:
GET /commits/<sha>или открой ветку в браузере вручную.
Частые грабли:
- Забыл
base_tree→ все остальные файлы исчезли из коммита. ВСЕГДА передавайbase_treeкроме случая «чистый коммит со всеми файлами». cp1251в cmd ломает юникод → пиши в файл через Python сencoding='utf-8', не выводи кириллицу в stdout.- GitHub API кеширует raw-ответы по path → при проверке обновления используй
?ref=<commit_sha>, не ветку.
15. Checklist: тестирование на VPS
VPS: 95.163.176.222, root, пароль в CLAUDE.md.
Путь из Linux sandbox: ssh/sshpass нет, pip install paramiko падает (прокси 403). Идём через Windows Python, где paramiko уже установлен.
Хелперы:
C:\Temp\ssh_cmd.py— однократная команда, читает изC:\Temp\ssh_input.txt, пишет вC:\Temp\ssh_output.txt.C:\Temp\ssh_a1.py/ssh_a2.py/ssh_a3.py— для параллельных агентов (разные output-файлы).
Базовый шаблон ssh_cmd.py:
import sys, paramiko
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("95.163.176.222", username="root", password="...", timeout=20)
cmd = open("C:/Temp/ssh_input.txt", "r", encoding="utf-8").read()
stdin, stdout, stderr = ssh.exec_command(cmd, timeout=60)
out = stdout.read().decode(errors="replace")
err = stderr.read().decode(errors="replace")
open("C:/Temp/ssh_output.txt", "w", encoding="utf-8").write(f"STDOUT:\n{out}\nSTDERR:\n{err}")
ssh.close()
Заливка одного файла через SFTP:
sftp = ssh.open_sftp()
sftp.put("C:/.../lib/telemt.sh", "/opt/gotelegram/lib/telemt.sh")
sftp.close()
CRLF: файлы из GitHub API приходят с \r\n → ОБЯЗАТЕЛЬНО sed -i 's/\r$//' /opt/gotelegram/install.sh /opt/gotelegram/lib/*.sh перед запуском, иначе bash падает с bad interpreter.
chmod: chmod +x /opt/gotelegram/install.sh /opt/gotelegram/install_gotelegram_bot.sh — GitHub раздаёт как 644.
Быстрая проверка live-состояния:
systemctl is-active telemt nginx gotelegram-bot
telemt --version
cat /etc/telemt/config.toml | grep tls_domain
journalctl -u telemt --no-pager -n 30
curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:8443
Проверка что Lite-ключ реально работает через Fake-TLS:
import ssl, socket
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with socket.create_connection(("95.163.176.222", 443), timeout=5) as s:
with ctx.wrap_socket(s, server_hostname="google.com") as ss:
print(ss.version(), ss.getpeercert(True)[:40])
Ожидаемо: TLSv1.3, сертификат с CN=*.google.com (его telemt эмулирует через tls_fetch).
16. Меню (install.sh)
── Прокси ──
1) menu_install (Lite/Pro выбор, domain, template, certbot)
2) menu_status (telemt_status + show_proxy_info)
3) menu_link (ссылка + QR)
4) menu_share (текст «для друзей»)
5) menu_restart (restart_telemt)
6) menu_logs (telemt_logs 40)
7) menu_change_mode (lite↔pro, смена шаблона, смена домена маскировки)
── Управление ──
8) interactive_backup (create_backup)
9) interactive_restore (select_backup + restore_backup)
10) update_telemt (check_telemt_update → download → restart)
11) menu_website (nginx restart, certbot renew)
── Бот и прочее ──
12) menu_bot (install_bot / start / stop / logs / change_token / remove)
13) menu_remove (только прокси / только бот / всё)
14) menu_promo (подарочные ссылки — маркетинг)
0) exit
Диспатчер в install.sh (bot_action_dispatch) принимает --action= для автоматизации из бота. Полный контракт описан в разделе 11.1.
17. Changelog
- 2.5.0 (2026-04-24) — крупный maintenance pass в ветках
beta/alpha: единая версия2.5.0в runtime и документации; удалён дефолтный PAT изbootstrap.sh(токен теперь только черезGOTELEGRAM_PAT); повторный bootstrap/update автоматически обновляет уже установленный/opt/gotelegram-botи перезапускаетgotelegram-bot, сохраняя.env;generate_telemt_tomlдобавляет[server.api]на127.0.0.1:9091и metrics на127.0.0.1:9090, что нужно для управления пользователями и статистики; Telegram-бот получил меню🔑 Keysдля[access.users](добавить/отключить/включить/удалить/показать ссылку/QR/runtime info/IP-limit); добавлена локальная web-админка goTelegram Progotelegram-adminна127.0.0.1:1984с SSH-tunnel инструкцией в боте без отдельного web-admin токена, вкладочной UI-навигацией, иконками, блоком реальных TCP/UDP-слушателей 443, promo-modal раз в 24 часа, i18n от языка установки, ручным переключателем RU/EN, site check на HTTP 200, structured journal logs, light/dark theme, адаптивом, быстрыми switch-переключателями ключей, настройкой[access.user_max_unique_ips], QR-кодами, traffic history 15m/1h/24h/month с переключением график/строки, per-user traffic history изtelemt total_octetsи stats collector restart endpoint; исправлено чтение traffic CSV в боте (header больше не ломает parsing); бот сам делаетstats_collectперед показом статистики;iptablesдобавлен в optional deps и stats collector пытается установить его; CLI-смена шаблона теперь обновляетconfig.json.template_id, чтобы бот не показывал первый установленный шаблон; backup/restore версии1.6сохраняет bot.env, bot lang files, disabled user keys, backup schedule, web-admin server/static, custom templates, templates catalog, stats history, user stats history, shared-443 config и полноценную структуру Let's Encrypt (live/archive/renewal) для переезда на новый сервер; добавлен безопасный детект 3x-ui/Xray на 443 и управляемый nginx stream shared-443 dispatcher. - 2.4.6 (2026-04-10) — universal
apt_lock_waithelper: ожидание dpkg/apt lock при unattended-upgrades, исправляет установку nginx/certbot/python на свежих VPS. - 2.4.3 (2026-04-10) — iter3-фикс:
bot_action_dispatchоборачивается воflock -w 30на/var/lock/gotelegram-bot-action.lock. Обнаружена гонка: параллельныеchange-lite-domainполучали"no secret in config", потому что один процесс читалconfig.json, пока другой делалjq ... > tmp && mv.util-linux(содержитflock) добавлен вcriticaldeps,check_deps_presentи маппингиapt_pkg_for_cmd/dnf_pkg_for_cmd. - 2.4.2 (2026-04-10) — реализация non-interactive
bot_action_*в install.sh (change-template + change-lite-domain с JSON-ответом). bot.py подключаетrun_bot_action()и делает реальную работу вместо stub'ов. Критфиксы: (a)safe_edit_messageпринимаетdisable_web_page_preview(иначе TypeError в success-пути cb_pro_confirm); (b) чтение/записьconfig['template_id']вместоconfig['template'](save_gotelegram_config всегда писалtemplate_id, бот смотрел не туда); (c)bot_update_config_fieldиспользует shelldate -Isecondsвместоjq now|todate(jq 1.5 совместимость для Debian 10); (d)asyncio.Lock _BOT_ACTION_LOCKсериализует callback'и в процессе бота; (e) валидация_TPL_ID_RE/_DOMAIN_REдо subprocess. Полный аудит и автоустановка зависимостей:ensure_depsразделяет critical/optional, дедуплицирует пакеты, re-verify после install;apt_pkg_for_cmdиdnf_pkg_for_cmdмапят команды на пакеты (dig→dnsutils/bind-utils, xxd→xxd/vim-common, flock→util-linux).check_deps_present— быстрый чек безapt-get update. - 2.4.1 (2026-04-10) — баг #23:
start_telemtделаетrestartесли сервис активен (иначе stale in-memory config после переустановки Lite поверх Pro). Полная документация проекта —DOCS_HUMAN.mdиDOCS_AI.md(этот файл). - 2.4.0 — i18n EN/RU для CLI (328 ключей) и бота (99 ключей JSON с per-user persistence). Возможность загрузить свой шаблон сайта из произвольного git-репозитория (валидация URL, таймауты, лимит размера клона).
- 2.3.x — каталог шаблонов расширен до 1801, 4 источника, 18 категорий. Поддержка StartBootstrap
dist/структуры. - 2.2.1 — критические фиксы
$()capture (все UI через>&2), StartBootstrap dist, symlink SCRIPT_DIR черезreadlink -f, XSS в HTML-превью бота, OS-release injection. - 2.2 — переход с mtg на telemt v3, новый TOML-формат конфига, stealth-архитектура.
18. Быстрый справочник: «хочу сделать X»
Добавить новый пункт меню:
install.sh: добавьmenu_new_thing(), впиши в диспатчерcaseв главном цикле.- Добавь i18n ключи
menu_new_thingв ru.sh и en.sh. - Если функция интерактивная + возвращает значение → ВСЁ UI через
>&2.
Добавить новый домен в QUICK_DOMAINS:
lib/telemt_config.sh→ массивQUICK_DOMAINS=(...). Убедись что домен не заблокирован ни в одной из популярных стран и действительно отвечает на 443 с валидным сертификатом (telemt приtls_emulation=trueвынимает реальный cert через tls_fetch).
Сменить версию:
lib/common.sh:6→GOTELEGRAM_VERSION="X.Y.Z".DOCS_HUMAN.md/DOCS_AI.md→ раздел Changelog + версия в шапке.- Тэг (опционально):
PATCH /git/refs/tags/vX.Y.Zна новый commit sha.
Добавить новый шаблон в каталог:
- Найди git-репо со статическим HTML (index.html в корне или в
dist/). - Придумай id:
<source_prefix>_<name>(напримерh5up_future,sb_portfolio_x). - Добавь запись в
templates_catalog.jsonсid,name,source,repo,category,preview. - Убедись что
download_templateзнает префикс источника (case "$tpl_id" in h5up_*) ... sb_*) ... esac).
Отладить «ключ не работает»:
systemctl is-active telemt→ живой?cat /etc/telemt/config.toml→ какойtls_domain? Какойport? Какойsecret?journalctl -u telemt --no-pager -n 50→ естьunknown_sni_action=Drop?port in use?failed to bind?- Сравни
tls_domainв конфиге и hex-домен в конце ссылки клиента (hex(domain) === суффикс секрета после ee+32hex). - Если telemt жив но дропает — restart (не start). Это баг #23.
- Если порт занят —
ss -ltnp | grep :443→ убей конкурента. - Если Pro и не открывается сайт в браузере —
curl -k https://127.0.0.1:8443(nginx жив?),dig +short $domain(DNS правильный?).
19. Где НЕ копаться
install_gotelegram_bot.sh— legacy, функционал дублирован в install.sh пункте 12. Можно удалить после того как убедимся что никто им не пользуется.lib/stats.sh— опциональная телеметрия, не критичная для работы.ColorlibHQв каталоге — wordpress-темы, отброшены. Не возвращать.- Старый формат конфига mtg (
[security],[[users]],bind_to) — telemt v3 его игнорирует. Не пытаться «починить» совместимость.
20. Контрольные точки и инварианты
Перед любым пушем в alpha/beta/main:
bash -n install.sh lib/*.sh— синтаксис bash ОК.- Все новые
$()-вызываемые функции пишут UI через>&2. - Все пути к lib/ идут через
$SCRIPT_DIR/lib/..., аSCRIPT_DIR— черезreadlink -f. GOTELEGRAM_VERSIONобновлена если изменения меняют поведение.- Changelog в
DOCS_HUMAN.mdиDOCS_AI.mdдополнен. - Если бекап-формат изменился — прописать в
restore_backupобратную совместимость. generate_telemt_tomlне роняет telemt v3 (проверитьtelemt run --check config.toml).
После пуша:
- Подождать пока нужная ветка обновится (GitHub API мгновенно, raw кеш ~30 сек).
- На VPS: повторить bootstrap из ветки
betaсGOTELEGRAM_PATили явно передатьGOTELEGRAM_BRANCH=alpha/main; скрипт сам скачает файлы, обновит установленный бот/админку и покажет меню. telemt_status→ running.journalctl -u telemt→ нет ошибок. Ссылка открывается в Telegram-клиенте.
Если в чём-то сомневаешься — открой CLAUDE.md в корне MT-proxy/. Там суммированы все ранее пройденные грабли и рабочие паттерны под Windows + Desktop Commander + paramiko.