← Назад в базу знаний

TikTok через IPv6 прокси: почему автопостинг срывается на этапе загрузки видео и как это чинится

Автопостинг в TikTok через прокси — задача с подводными камнями. Настройка выглядит рабочей: запросы проходят, токены получаются, профиль читается. А потом наступает момент загрузки видео — и всё разваливается. Разбираем, почему загрузка видео через IPv6 прокси срывается чаще, чем обычные API-вызовы, и что с этим делать.

Почему именно загрузка видео — самое слабое место

Любой автопостер делает три вещи: авторизуется, готовит метаданные, заливает файл. Первые два шага — это лёгкие JSON-запросы по 2-5 КБ. Загрузка видео — это multipart upload на десятки мегабайт, который держит TCP-соединение открытым минуты.

IPv6 здесь добавляет свой слой проблем. MTU у IPv6 минимально 1280 байт против 576 у IPv4. PMTUD (Path MTU Discovery) в IPv6 обязателен, и если ICMPv6-сообщения «Packet Too Big» где-то режутся — соединение зависает на передаче крупных пакетов. Мелкие запросы проскакивают, большой файл — нет.

Плюс сам TikTok относится к загрузке видео иначе, чем к чтению ленты. Серверная сторона проверяет consistency: IP-адрес, TLS-фингерпринт, заголовки, тайминги. Если между запросом на upload-init и фактической передачей байтов IP поменялся или соединение выглядит подозрительно — загрузка отбивается.

Что реально ломается: три сценария

Первый — таймаут на этапе `upload/init`. Клиент получает upload URL, начинает заливать, а соединение рвётся через 30-60 секунд. Причина чаще всего в том, что прокси-сервер закрывает долгоживущие соединения по idle-таймауту, не учитывая, что клиент ещё передаёт данные.

Второй — рассинхрон IPv6-адресов. Прокси пул ротирует адреса, и upload-init уходит с одного адреса, а чанки файла — с другого. TikTok видит несоответствие и возвращает 403 или молча обрывает соединение.

Третий — фрагментация. Если на пути стоит устройство с MTU меньше 1280 (редко, но бывает в туннелях), IPv6-пакеты дропаются без ICMPv6. Клиент ждёт, ретрансмитит, в итоге таймаут.

Как выглядит срыв в логах

Типичная картина при провале загрузки через curl:

```bash

curl -6 -v --max-time 120 \

-X POST "https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/upload/video/" \

-H "Content-Type: multipart/form-data" \

-F "video=@clip.mp4" \

--interface 2001:db8::1

```

В выводе видно `* Trying 2001:db8::1...`, потом `* Connected`, затем зависание на `> Expect: 100-continue`. Сервер не отвечает `100 Continue` вовремя — curl ждёт секунду по умолчанию и начинает слать тело, но соединение уже в подвешенном состоянии. Через 120 секунд — `curl: (28) Operation timed out`.

Лечится отключением Expect и явным управлением размером чанка:

```bash

curl -6 --max-time 300 \

-H "Expect:" \

-H "Transfer-Encoding: chunked" \

-X POST "https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/upload/video/" \

-F "video=@clip.mp4;type=video/mp4" \

--interface 2001:db8::1

```

Настройка MTU и PMTUD на прокси

Первое, что проверяем на прокси-сервере — MTU на интерфейсе. Для IPv6-туннелей часто ставят 1480 или 1420, но забывают про клиентскую сторону. Если клиент шлёт пакеты по 1500, а туннель держит 1420 — нужен рабочий PMTUD.

Проверка:

```bash

ping6 -M do -s 1400 -c 3 api16-normal-c-useast1a.tiktokv.com

```

Если `-s 1400` проходит, а `-s 1452` — нет, значит MTU на пути 1420-1440. На прокси фиксируем:

```bash

ip link set dev eth0 mtu 1420

sysctl -w net.ipv6.conf.eth0.accept_ra_mtu=1

sysctl -w net.ipv6.conf.all.mtu_expires=600

```

`accept_ra_mtu=1` позволяет ядру принимать MTU из Router Advertisement. Без этого параметра интерфейс может держать дефолтные 1500 и игнорировать реальный MTU пути.

Почему ротация IPv6-адресов убивает загрузку

Пул IPv6 — это тысячи адресов из одной /64 или /48. Соблазн ротировать адрес на каждый запрос велик. Для лёгких API-вызовов это работает. Для загрузки видео — нет.

Механика: upload-init возвращает upload_id и набор URL для чанков. Сервер привязывает upload_id к IP, с которого пришёл init. Следующий чанк с другим адресом — отказ. Логика простая: защита от подмены клиента в процессе загрузки.

Решение — sticky-сессия на время загрузки. Один файл = один IPv6-адрес от init до последнего чанка. В коде это выглядит как привязка адреса к объекту сессии:

```python

import requests

import ipaddress

class TikTokUploader:

def __init__(self, proxy_pool):

self.pool = proxy_pool

self.session_ip = None

def _pick_ip(self):

if self.session_ip is None:

self.session_ip = self.pool.next_ipv6()

return self.session_ip

def upload(self, filepath, metadata):

ip = self._pick_ip()

proxies = {

"http": f"http://[{ip}]:3128",

"https": f"http://[{ip}]:3128",

}

try:

with open(filepath, "rb") as f:

r = requests.post(

"https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/upload/video/",

files={"video": ("clip.mp4", f, "video/mp4")},

data=metadata,

proxies=proxies,

timeout=(10, 300),

)

return r.status_code, r.text

finally:

self.session_ip = None

```

Адрес освобождается только после завершения загрузки. Между файлами — можно менять. Внутри одного файла — нельзя.

Заголовки и TLS-фингерпринт

TikTok проверяет не только IP. TLS-отпечаток клиента, набор заголовков, порядок их передачи — всё это уходит на серверную проверку. Загрузка видео — самый «дорогой» запрос с точки зрения антифрода, поэтому проверки там строже.

Если используешь `requests` из Python — TLS-фингерпринт будет характерным для OpenSSL, который стоит под капотом. Это палится. Для загрузки лучше брать curl-impersonate или httpx с кастомным SSL-контекстом.

Заголовки для загрузки должны совпадать с теми, что уходили при авторизации. User-Agent, X-Request-Id, Cookie — единые в рамках сессии. Расхождение между upload-init и загрузкой чанков — красный флаг.

Кейс: nginx-прокси с дефолтными буферами

Сервер на nginx 1.24, настроен как forward-proxy для IPv6-клиентов. Автопостер на Python заливает видео по 40-80 МБ. Загрузка обрывается на 8-12 МБ стабильно.

Причина: `client_max_body_size` по умолчанию 1 МБ, но в forward-proxy это не работает так же, как в reverse. Проблема оказалась в `proxy_request_buffering on` — nginx буферизует весь запрос на диск перед отправкой апстриму. При 80 МБ и медленном диске буфер переполняется, соединение рвётся по таймауту.

Решение — отключить буферизацию и поднять таймауты:

```nginx

proxy_request_buffering off;

proxy_buffering off;

proxy_send_timeout 600s;

proxy_read_timeout 600s;

client_body_timeout 600s;

client_max_body_size 200m;

```

После правки загрузка 80 МБ прошла за 47 секунд без обрывов. До правки — стабильный обрыв на 12-15 секунде.

Кейс: ротация адреса в середине upload

Пул на 5000 IPv6-адресов, ротация каждые 30 секунд по таймеру. Автопостер заливал видео 60-90 секунд. На 31-й секунде адрес менялся — TikTok возвращал 403 с телом `{"status_code": 10013, "message": "invalid upload session"}`.

Причина — та самая привязка upload_id к IP. Ротация по таймеру не учитывает активные сессии. Фикс: ротация только по завершении сессии, плюс sticky-таймаут 5 минут на адрес после последнего запроса.

Цифры до и после: успешных загрузок было 34% от попыток, стало 96%. Среднее время загрузки 50-МБ файла — 38 секунд, дисперсия ±6 секунд.

Кейс: обрыв на Expect: 100-continue

Клиент на Go, загрузка через `http.Client` с IPv6-прокси. Файлы до 20 МБ проходили, больше — таймаут на 60 секунд. В логах прокси — соединение открыто, данные не идут.

Причина: Go-клиент шлёт `Expect: 100-continue` для тел больше 1 МБ. Прокси-сервер (Squid 5.7) не пробрасывает `100 Continue` от апстрима корректно для IPv6-соединений — известный баг в некоторых сборках. Клиент ждёт подтверждения, сервер ждёт тело. Взаимная блокировка до таймаута.

Решение — отключить Expect на клиенте:

```go

req.Header.Set("Expect", "")

transport := &http.Transport{

Proxy: http.ProxyURL(proxyURL),

ExpectContinueTimeout: 1 * time.Second,

DisableCompression: true,

}

```

Или обновить Squid до 6.x, где поведение исправлено. После отключения Expect загрузка 20 МБ пошла за 14 секунд вместо таймаута.

Мониторинг: что мерить

Без метрик срыв загрузки выглядит как «иногда не работает». Мерить нужно конкретное:

| Метрика | Норма | Тревога |

|---|---|---|

| Время до первого байта ответа | < 800 мс | > 3000 мс |

| Скорость загрузки | > 1.5 МБ/с | < 300 КБ/с |

| Доля успешных upload | > 90% | < 70% |

| Таймауты на 100 файлов | 0-2 | > 10 |

Логировать нужно код ответа, время каждого этапа (init, передача, финализация), IPv6-адрес сессии. Без привязки адреса к логу разбор инцидента превращается в гадание.

Чеклист перед запуском автопостера

Проверить MTU на всём пути от клиента до прокси. Убедиться, что PMTUD работает и ICMPv6 не режется. Настроить sticky-сессию по IP на время загрузки одного файла. Отключить `Expect: 100-continue` или убедиться, что прокси его корректно пробрасывает. Синхронизировать заголовки и TLS-фингерпринт между init и загрузкой. Поднять таймауты на прокси до 300-600 секунд. Проверить, что `proxy_request_buffering` выключен, если используешь nginx. Логировать IPv6-адрес для каждой загрузки.

Прокси-сервис вроде lexic.ml даёт пул IPv6 с 2015 года, и там есть возможность фиксировать адрес на сессию — это как раз то, что нужно для стабильной загрузки видео. Без sticky-режима любой пул превращается в лотерею.

Что делать, если ничего не помогло

Иногда проблема не в прокси, а в самом файле. TikTok отклоняет видео с нестандартным кодеком, битрейтом выше 8 Мбит/с, разрешением вне 540x960 — 1080x1920. Проверяй через ffprobe перед загрузкой:

```bash

ffprobe -v error -select_streams v:0 \

-show_entries stream=codec_name,bit_rate,width,height \

-of csv=p=0 clip.mp4

```

Если кодек h265 — конвертируй в h264. Если битрейт 12 Мбит/с — пережми до 6-8. Это не про прокси, но срыв на этапе загрузки часто путают с сетевыми проблемами, а на деле сервер отбивает файл по валидации и возвращает невнятную ошибку.

Второй момент — размер чанка. Некоторые реализации режут файл на куски по 5 МБ. Для IPv6-соединений с потерями лучше 2-3 МБ: меньше вероятность, что один потерянный пакет уронит весь чанк и вызовет ретрансмит всего куска.

Третий — параллельные загрузки. Если автопостер льёт 10 видео одновременно через один прокси-пул, адреса конфликтуют, sticky-сессии пересекаются. Ограничивай конкурентность до 3-5 на пул, остальное — в очередь.

✔️Купить прокси