Files
mtproxy_checker/docs/docker.ru.md
T

300 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:**
```bash
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):**
```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](https://docs.docker.com/engine/install/) (Linux) или Docker Desktop (Windows/macOS).
- Для `docker pull` из приватного registry — логин и токен.
## Сборка образа локально
**Linux / macOS:**
```bash
cd /path/to/mtproxy_checker
docker build -t mtproxy_checker:local .
```
**Windows (PowerShell):**
```powershell
cd C:\path\to\mtproxy_checker
docker build -t mtproxy_checker:local .
```
Проверка, что образ собран (нужен хотя бы один аргумент, иначе стартует API):
```bash
docker run --rm mtproxy_checker:local -timeout 5s 2>&1 | head -1
# ожидается сообщение usage CLI (код выхода 2 — нормально без URL)
```
## Запуск под Linux
### Один прокси (ссылка `tg://`)
```bash
docker run --rm mtproxy_checker:local \
'tg://proxy?server=example.com&port=443&secret=eeYOURHEX...'
```
С флагами утилиты (таймаут, DC):
```bash
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`):
```bash
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.
- Если имена не резолвятся:
```bash
docker run --rm --dns 8.8.8.8 mtproxy_checker:local 'tg://proxy?...'
```
- Режим сети хоста (как на машине без NAT; используйте осознанно):
```bash
docker run --rm --network host mtproxy_checker:local 'tg://proxy?...'
```
На Docker Desktop для Windows/macOS `--network host` ведёт себя иначе, чем на Linux.
## Несколько MTProxy ссылок подряд
Утилита принимает **ровно один** прокси за запуск. Чтобы проверить много `tg://` ссылок, обходите их в оболочке.
### Вариант 1: цикл в bash
```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...
```
Скрипт:
```bash
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`)
Осторожно: одновременно много контейнеров нагружают сеть и целевые прокси.
```bash
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»:
```bash
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 неудобны; проще двойные:
```powershell
docker run --rm mtproxy_checker:local `
"tg://proxy?server=example.com&port=443&secret=eeYOURHEX..."
```
Несколько ссылок:
```powershell
$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
1. Включите **Packages / Container Registry** на инстансе Gitea ([документация](https://docs.gitea.com/usage/packages/container)).
2. Создайте токен с правом на пакеты.
3. Логин:
```bash
docker login git.shts.su
# или ваш registry
```
4. Сборка workflow публикует теги `latest`, имя ветки/тега и `sha-…` — см. `.gitea/workflows/docker.yaml`.
```bash
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`:
```yaml
services:
mtproxy-check:
image: mtproxy_checker:local
build: .
command: ['tg://proxy?server=example.com&port=443&secret=ee...']
```
```bash
docker compose run --rm mtproxy-check
```
Для списка прокси удобнее внешний bash-цикл или отдельный `command: ["sh","-c","..."]` с циклом по файлу, смонтированному в volume.
## Использование в CI другого проекта
```bash
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` контейнер удаляется сразу после выхода.