14 KiB
Docker: образ mtproxy_checker
Что внутри образа
| Компонент | Описание |
|---|---|
| База runtime | Alpine Linux 3.20 |
| Бинарники | CLI: /usr/local/bin/mtproxy_checker. HTTP-сервис списка: /usr/local/bin/mtproxy_checkerd (см. ниже) |
| Сертификаты | Пакет ca-certificates (для TLS к реальным хостам при необходимости) |
| ENTRYPOINT | Скрипт docker-entrypoint.sh: есть аргументы после имени образа → mtproxy_checker (разовая проверка); нет аргументов → mtproxy_checkerd (HTTP API) |
| Порты | В режиме CLI ничего не слушает (только исходящий TCP). В режиме API слушает 8080 (или MTPROXY_HTTP_ADDR). Образ объявляет EXPOSE 8080 |
docker run … ИМЯ_ОБРАЗА tg://… или с флагами — одна проверка, код выхода 0…4. docker run … ИМЯ_ОБРАЗА без command — долгоживущий API (нужны volume/env к файлу со списком).
HTTP API: mtproxy_checkerd
Лёгкий сервер на стандартной библиотеке Go: читает файл со списком tg:// (как в разделе «файл — одна ссылка на строку»), сразу после старта выполняет первый цикл проверок, затем повторяет с интервалом. Результаты последнего цикла отдаются по HTTP в JSON.
Запуск контейнера в режиме API
Без command / аргументов после образа entrypoint сам запускает mtproxy_checkerd.
Linux / macOS:
docker run -d --name mtproxy-api --restart unless-stopped -p 8080:8080 \
-v /path/to/proxies.txt:/data/proxies.txt:ro \
-e MTPROXY_CHECK_INTERVAL=60m \
mtproxy_checker:local
Windows (PowerShell):
docker run -d --name mtproxy-api --restart unless-stopped -p 8080:8080 `
-v "${PWD}/proxies.txt:/data/proxies.txt:ro" `
-e MTPROXY_CHECK_INTERVAL=60m `
mtproxy_checker:local
Явно указать демон (редко нужно): --entrypoint /usr/local/bin/mtproxy_checkerd.
Готовый пример: docker-compose.api.yaml — docker compose -f docker-compose.api.yaml up --build.
Переменные окружения
| Переменная | По умолчанию | Назначение |
|---|---|---|
MTPROXY_LIST_FILE |
/data/proxies.txt |
Путь к файлу: одна tg:// ссылка на строку; пустые строки и строки с # в начале пропускаются |
MTPROXY_CHECK_INTERVAL |
5m |
Интервал между циклами (time.ParseDuration, например 5m, 1h) |
MTPROXY_HTTP_ADDR |
:8080 |
Адрес прослушивания HTTP |
MTPROXY_CHECK_TIMEOUT |
45s (в демоне по умолчанию; CLI по-прежнему 15s если не задано) |
Таймаут всей одной проверки; для MTPROXY_PROBE=deep нужен запас (TLS + drain + ответ DC) |
MTPROXY_PROBE |
(пусто) → fast |
fast — рукопожатие + init + короткое ожидание как в Telethon TcpMTProxy (#1134): OK, если прокси не рвёт TCP сразу после init (входящие байты не обязательны). deep — req_pq/resPQ через DC (строже, дольше) |
MTPROXY_DC_ID |
2 |
DC id (аналог -dc-id CLI) |
MTPROXY_ALLOWED_IPS |
(не задана) | Если задана непустая строка — доступ к всем маршрутам только с перечисленных IP/CIDR; остальные получают 403 и JSON {"error":"forbidden"}. Формат: через запятую, пробелы допускаются: 192.168.1.10, 10.0.0.0/8, IPv6 и CIDR вида 2001:db8::/32. Учитывается только RemoteAddr TCP-соединения; заголовок X-Forwarded-For не используется |
HTTP
| Метод | Путь | Ответ |
|---|---|---|
| GET | /health |
200, {"status":"ok"} |
| GET | /api/v1/proxies |
200, JSON с полями cycle_finished_at, next_check_after, массив proxies |
Элемент proxies[]: raw_line, при успешном разборе — url, ok, exit_code (0 OK — при MTPROXY_PROBE=fast: рукопожатие + init и прокси не закрыл TCP сразу (как Telethon #1134); при deep: дополнительно получен resPQ от DC через туннель); 1 ошибка проверки, в т.ч. нет resPQ за время ожидания в deep; 2 ошибка разбора URL/секрета; 3 прокси закрыл соединение; 4 таймаут всего запроса), error, при необходимости parse_error, checked_at.
Whitelist IP и Docker
Процесс видит IP источника TCP таким, каким его передал стек в контейнер. При пробросе порта с хоста (-p 8080:8080) на Linux часто это адрес шлюза bridge или userland-proxy, а не «настоящий» IP клиента с хоста. Имеет смысл задавать CIDR подсети Docker (например 172.17.0.0/16), слушать только внутреннюю сеть, использовать --network host (на Linux) или ограничивать доступ на обратном прокси (nginx allow и т.п.).
Требования
- Docker Engine (Linux) или Docker Desktop (Windows/macOS).
- Для
docker pullиз приватного registry — логин и токен.
Сборка образа локально
Linux / macOS:
cd /path/to/mtproxy_checker
docker build -t mtproxy_checker:local .
Windows (PowerShell):
cd C:\path\to\mtproxy_checker
docker build -t mtproxy_checker:local .
Проверка, что образ собран (нужен хотя бы один аргумент, иначе стартует API):
docker run --rm mtproxy_checker:local -timeout 5s 2>&1 | head -1
# ожидается сообщение usage CLI (код выхода 2 — нормально без URL)
Запуск под Linux
Один прокси (ссылка tg://)
docker run --rm mtproxy_checker:local \
'tg://proxy?server=example.com&port=443&secret=eeYOURHEX...'
С флагами утилиты (таймаут, DC):
docker run --rm mtproxy_checker:local \
-timeout 25s -dc-id 2 \
'tg://proxy?server=example.com&port=443&secret=eeYOURHEX...'
Чтобы не светить секрет в истории shell, прочитайте его из файла и передайте флагами (аргументы уходят в CLI через docker-entrypoint.sh):
SECRET=$(tr -d ' \n' < secret.hex)
docker run --rm mtproxy_checker:local \
--server example.com --port 443 --secret "$SECRET"
Сеть и DNS на Linux
- По умолчанию контейнер использует bridge Docker; нужен исходящий доступ к
server:portи рабочий DNS. - Если имена не резолвятся:
docker run --rm --dns 8.8.8.8 mtproxy_checker:local 'tg://proxy?...'
- Режим сети хоста (как на машине без NAT; используйте осознанно):
docker run --rm --network host mtproxy_checker:local 'tg://proxy?...'
На Docker Desktop для Windows/macOS --network host ведёт себя иначе, чем на Linux.
Несколько MTProxy ссылок подряд
Утилита принимает ровно один прокси за запуск. Чтобы проверить много tg:// ссылок, обходите их в оболочке.
Вариант 1: цикл в bash
IMAGE=mtproxy_checker:local # или registry/owner/mtproxy_checker:latest
for url in \
'tg://proxy?server=a.example.com&port=443&secret=ee1111...' \
'tg://proxy?server=b.example.com&port=8443&secret=ee2222...' \
'tg://proxy?server=c.example.com&port=443&secret=dd3333...'
do
echo "=== $url ==="
if docker run --rm "$IMAGE" -timeout 20s "$url"; then
echo "OK"
else
echo "FAIL (код $?)"
fi
done
Вариант 2: файл — одна ссылка на строку
proxies.txt (пустые строки и строки с # в начале можно пропускать):
tg://proxy?server=one.example.com&port=443&secret=ee...
tg://proxy?server=two.example.com&port=8443&secret=ee...
Скрипт:
IMAGE=mtproxy_checker:local
while IFS= read -r line || [ -n "$line" ]; do
line="${line#"${line%%[![:space:]]*}"}" # trim leading spaces
[ -z "$line" ] && continue
case "$line" in \#*) continue ;; esac
echo "=== $line ==="
docker run --rm "$IMAGE" -timeout 20s "$line" && echo OK || echo "FAIL ($?)"
done < proxies.txt
Вариант 3: параллельно (xargs)
Осторожно: одновременно много контейнеров нагружают сеть и целевые прокси.
IMAGE=mtproxy_checker:local
grep -v '^\s*$\|^\s*#' proxies.txt | xargs -I{} -P 4 sh -c \
'echo "=== {}"; docker run --rm '"$IMAGE"' -timeout 20s "{}" || echo FAIL'
-P 4 — не более четырёх проверок одновременно; уменьшите при необходимости.
Вариант 4: итоговый код для CI
Если нужен «провал всего job при любом FAIL»:
set -e
IMAGE=mtproxy_checker:local
while IFS= read -r url; do
[ -z "$url" ] && continue
case "$url" in \#*) continue ;; esac
docker run --rm "$IMAGE" -timeout 25s "$url"
done < proxies.txt
Запуск из PowerShell (Windows)
Одинарные кавычки с tg:// в PowerShell неудобны; проще двойные:
docker run --rm mtproxy_checker:local `
"tg://proxy?server=example.com&port=443&secret=eeYOURHEX..."
Несколько ссылок:
$urls = @(
"tg://proxy?server=a.com&port=443&secret=ee...",
"tg://proxy?server=b.com&port=8443&secret=ee..."
)
foreach ($u in $urls) {
Write-Host "=== $u ==="
docker run --rm mtproxy_checker:local -timeout 20s $u
if ($LASTEXITCODE -ne 0) { Write-Host "FAIL exit $LASTEXITCODE" }
}
Загрузка образа из Container Registry Gitea
- Включите Packages / Container Registry на инстансе Gitea (документация).
- Создайте токен с правом на пакеты.
- Логин:
docker login git.shts.su
# или ваш registry
- Сборка workflow публикует теги
latest, имя ветки/тега иsha-…— см..gitea/workflows/docker.yaml.
docker pull git.shts.su/owner/mtproxy_checker:latest
docker run --rm git.shts.su/owner/mtproxy_checker:latest 'tg://proxy?...'
Пример docker-compose
Одна проверка за compose run:
services:
mtproxy-check:
image: mtproxy_checker:local
build: .
command: ['tg://proxy?server=example.com&port=443&secret=ee...']
docker compose run --rm mtproxy-check
Для списка прокси удобнее внешний bash-цикл или отдельный command: ["sh","-c","..."] с циклом по файлу, смонтированному в volume.
Использование в CI другого проекта
docker run --rm registry.example.com/owner/mtproxy_checker:latest \
"tg://proxy?server=${MTPROXY_HOST}&port=${MTPROXY_PORT}&secret=${MTPROXY_SECRET}"
Коды выхода и диагностика
| Код | Значение |
|---|---|
| 0 | fast: Fake-TLS/dd + MTProxy init, прокси не закрыл соединение сразу (как Telethon). deep: плюс подтверждён resPQ от DC |
| 1 | Ошибка (сеть, протокол; в deep — в т.ч. нет валидного resPQ) |
| 2 | Неверные аргументы CLI |
| 3 | Прокси закрыл TCP сразу после начального payload |
| 4 | Общий таймаут (-timeout) |
Не путать с ping: ICMP не используется.
Типичные сообщения:
connection refused— порт закрыт или фильтр.FAIL: timeout— нет ответа за-timeout.no resPQ from telegram through proxy— до DC достучаться не удалось или ответ не похож наresPQ(часто совпадает с «Недоступен» в клиенте).- Ошибки чтения/проверки ServerHello — несовместимый ответ или обрыв соединения.
Для отладки без --rm можно посмотреть логи контейнера по id; с --rm контейнер удаляется сразу после выхода.