Пару месяцев мои агенты на Claude жили на зарубежном PaaS (Railway): пуш в репозиторий, автосборка, работает. В июле я перевёз всё на московский VPS. Сам переезд занял день. Разгребание последствий — неделю.
Ниже — что именно отваливается, как я это диагностировал и чем чинил. Часть граблей описана в интернете разрозненно, часть я не нашёл нигде и выяснял логами.
Главный вывод, к которому я пришёл не сразу, стоит вынести в начало: переезд в Россию — это не «сменить хостинг». Это обнаружить, что половина внешнего мира общается с вашим сервером односторонне. Вы к ним ходите — пожалуйста. Они к вам — нет. И всё, что построено на «внешний сервис постучится к нам», приходится переворачивать.
Зачем вообще переезжать
Два повода, оба скучные и практические.
Первый — персональные данные. Мои агенты разговаривают с клиентами компаний: отвечают на вопросы, считают стоимость, собирают заявки. В диалог неизбежно попадают имя, телефон, почта. Как только это уходит в модель, начинается обработка персональных данных со всеми вытекающими. Хранить их надо в России.
Второй — устойчивость. Прод на зарубежной платформе — это зависимость от чужого решения о том, кого обслуживать. Пока всё хорошо, об этом не думаешь. Когда станет плохо, думать будет поздно.
Задача формулировалась так: агенты работают в России, персональные данные не покидают страну, модель при этом остаётся внешней и никуда не денется.
Часть 1. Мелочи, которые ломаются сразу
Docker Hub отдаёт 429
Первая же сборка на новом сервере упала. Анонимные пуллы образов Docker Hub с российских адресов упираются в rate-limit — не «медленно», а просто отказ.
Лечится настройкой зеркал реестра в конфиге демона. У крупных российских хостеров свои зеркала, у моего оказалось рабочее. Пятнадцать минут, если знаешь, и полчаса недоумения, если не знаешь.
Дамп базы не забрать с нового сервера
Переносил базы со старой платформы. Логика простая: подключиться с нового сервера к публичному прокси старой базы и снять дамп. Не вышло — соединение просто виснет, без ошибки, как и запросы к модели (об этом ниже).
Пришлось снимать дамп с машины, у которой доступ есть, и заливать на сервер через пайп по ssh.
Внутри этой грабли обнаружилась ещё одна: если утилита дампа новее сервера, куда вы восстанавливаете, в дамп попадают параметры, которых старый сервер не знает. При восстановлении получаете красную ошибку про нераспознанный параметр конфигурации. Выглядит страшно, на деле безвредно — это SET-директива, данные приезжают целиком. Я на всякий случай сверил количество строк в таблицах до и после.
Свежий российский IP не знают geoip-базы
Хостер выдал новый адрес. Формально российский, фактически — его ещё нет в базах геолокации, которыми пользуются VPN-клиенты и правила маршрутизации.
Следствие: правило «российское — напрямую, остальное — через туннель» этот адрес не опознаёт и гонит трафик не туда. Сайт то открывается, то нет, в зависимости от того, с какого устройства смотришь.
Лечится явным правилом по домену. И важная деталь: после добавления правила надо сбросить DNS-кэш устройства, иначе оно продолжает держать старый маршрут и вы решите, что правило не сработало. Я на этом потерял вечер, добавляя правило второй и третий раз.
Часть 2. Главная стена
Дальше начинается то, ради чего я пишу эту статью.
Модель недоступна с российского адреса
Агент — это по большей части прокси к языковой модели. У меня это Claude, и первый же запрос с нового сервера вернул 403. Не «неверный ключ», не таймаут — отказ по стране, мгновенный, ещё до проверки авторизации.
Здесь есть диагностический приём, который экономит время. Смотрите, каким кодом вам отказывают. Если приходит 401 с жалобой на отсутствующий ключ — вас пустили, дело в конфигурации. Если 403 без упоминания ключа — вас отвергли раньше, по адресу. Разница принципиальная: в первом случае чините конфиг, во втором — чинить нечего, надо менять точку выхода.
Решение здесь инфраструктурное, а не программное: исходящие запросы к Anthropic должны уходить не с российского адреса. Конкретную схему своего контура не привожу — не из скромности, а потому что подобные лазейки закрывают тем быстрее, чем громче о них пишут.
Из полезного и безопасного: менять код приложения почти наверняка не придётся. Стандартные HTTP-клиенты уважают переменные окружения для прокси, так что вопрос решается на уровне окружения контейнера. Исключение — библиотеки, которые эти переменные игнорируют (мне попались две, обе про Telegram); там пришлось передавать настройку явно при создании клиента.
Вебхуки Telegram не доходят до российского сервера
Самое неочевидное и самое дорогое по времени.
Боты переехали, вебхуки зарегистрированы, всё выглядит правильно. Боты молчат. Очередь необработанных обновлений растёт.
Первая мысль была — я где-то ошибся: путь, сертификат, секрет. Проверил трижды, всё верно. Тогда я сделал то, что стоило сделать сразу — эксперимент с контролем:
поднял тот же самый обработчик на сервере за пределами страны, зарегистрировал вебхук туда → обновления приходят, 200;
вернул на московский → не приходит ни одного, таймаут на стороне отправителя;
прогнал внешними сервисами проверки доступности со всего мира → мой сервер открывается отовсюду нормально.
Вывод: сервер доступен всем, кроме отправителя. Трафик дата-центров Telegram к российским адресам фильтруется на входе.
Решение — перевернуть направление. Вместо вебхуков (они стучатся к вам) — длинный опрос (вы стучитесь к ним). Исходящие соединения никто не режет.
Грабли, которые встретились по дороге:
Два опрашивающих процесса на один токен дают конфликт. Пока старый экземпляр на прежней платформе жив, новый получает ошибку. Гасить старое надо до, а не после.
Опрос и вебхук взаимоисключающи. Если платформа автоматически передеплоит старую версию, она заново зарегистрирует вебхук и молча сломает вам опрос. Я на это напоролся дважды, пока не отвязал автодеплой совсем.
У ботов на бизнес-аккаунтах свой тип обновлений, и его надо запрашивать явным списком. Иначе бот работает, но конкретно бизнес-переписку не видит. Отладка веселая: логи чистые, ошибок нет, сообщений нет.
То же самое, но с картинками
Это случилось на днях и стало последним кусочком мозаики.
В Telegram обновился формат постов — появились карусели, длинный форматированный текст. Я переписал свой публикатор под новый API и упёрся: часть картинок не подтягивается. Ошибка «медиа не найдено». Причём одни картинки проходят, другие нет — при том, что файлы побайтово однотипные, лежат в одной папке и отдаются одним и тем же веб-сервером.
Что я проверил и отмёл, прежде чем понял:
формат, вес и параметры файлов — идентичны у рабочих и нерабочих;
блокировка ботов на веб-сервере — её нет, конфиг чистый;
user-agent — сервер отдаёт 200 всем, включая пустой и подставной;
цепочка сертификатов — полная и валидная;
повторные попытки — десять штук за минуту, без изменений;
обход кэша уникальным адресом — не помогает;
«прогрев» через отправку ссылки, чтобы сервис сам скачал картинку для превью — не помогает.
Разгадка нашлась в логах веб-сервера. За одними картинками загрузчик приходил и получал 200. За другими не приходил ни разу. Это не ошибка загрузки. Это отсутствие попытки.
Чтобы исключить версию «кривой хостер», я повторил эксперимент с контролем — одна и та же картинка, уникальные адреса, три источника подряд:
Откуда отдаём |
Первая попытка |
Вторая |
|---|---|---|
Российский хостинг, провайдер А |
не забрал |
не забрал |
Российский хостинг, провайдер Б (другая сеть, другой регион) |
не забрал |
не забрал |
Заграничное хранилище |
забрал |
забрал |
В логах второго хостинга запросов от Telegram — ноль. Два независимых провайдера ведут себя одинаково.
Это та же стена, что с вебхуками, просто с другой стороны: в одном случае к вам не приходит уведомление, в другом — не приходят за файлом.
Решение: отдавать медиа не со своего сервера, а с внешнего хранилища. У меня это оказался публичный репозиторий — картинки и так лежат в git, ссылка на файл в нём работает как обычный URL, и до него загрузчик дотягивается с первой попытки.
Часть 3. Ради чего всё затевалось: персональные данные
Тут главная мысль, которую легко упустить: сервер в России — это половина решения. Данные всё равно уходят в модель, а модель живёт снаружи. Значит, до модели они должны перестать быть персональными.
Как это устроено у меня
Перед отправкой в модель текст проходит маскировку: телефоны, адреса почты, имена, номера документов заменяются плейсхолдерами вида [PHONE], [NAME]. Реальные значения остаются на сервере в словаре соответствия — только в памяти обработки одного запроса.
Модель отвечает, оперируя плейсхолдерами. Перед показом пользователю ответ разворачивается обратно. Клиент видит своё имя и свой номер, модель их не видела.
Контакт для заявки я вытаскиваю локально, разбором текста на своей стороне, а не прошу модель «найди телефон в диалоге». Так надёжнее и дешевле: телефон — это структура, для неё не нужен интеллект.
Что оказалось неочевидным
Порядок замен важнее самих замен. Номера документов, записанные слитно, надо маскировать раньше телефонов. Иначе маска телефона срабатывает на фрагменте документа, съедает часть цифр, а хвост остаётся в тексте — и в модель уходит кусок того, что вы старались скрыть. Общее правило: сначала длинные и специфичные форматы, потом короткие и общие.
Маска должна быть обратимой ровно один раз. Если в одном сообщении два разных телефона, а плейсхолдер общий, обратно вы развернёте не то. Нумерация плейсхолдеров решает это, но её надо не забыть.
Не всё, что похоже на данные, ими является. Мой первый вариант жадно маскировал всё, что выглядит как последовательность цифр. В результате агент, который считает стоимость по размерам, начал получать на вход [NUMBER] на [NUMBER] метров — и, разумеется, перестал считать. Размеры, суммы, даты, артикулы должны оставаться нетронутыми. Это ограничивает жадность масок сильнее, чем кажется на старте.
Проверять надо круговым тестом. Берёте фразу с данными, маскируете, разворачиваете обратно — и сравниваете с исходником побайтово. Если не совпало, где-то маска съела лишнее. Этот тест поймал у меня три ошибки, которых я не видел глазами.
С голосом сложнее, и у меня это пока не закрыто. В расшифровке речи телефон приходит словами: «восемь девятьсот пять…». Никакая цифровая маска его не поймает. Нужна нормализация числительных до маскировки, и это отдельная задача, которую я честно ещё не сделал.
Что даёт такая схема
Формально — данные не уходят за границу: наружу уходит текст с плейсхолдерами, а ключ соответствия остаётся на сервере в России. Практически — если завтра внешний сервис скомпрометируют, в утёкших логах не будет ни одного реального телефона.
Это не юридическая консультация, и я не юрист. Но архитектурно связка «хранение внутри + обезличивание на выходе» выглядит куда спокойнее, чем «пусть модель видит всё, зато у нас есть галочка согласия».
Часть 4. Что в итоге получилось, кроме соответствия закону
Задержка упала. Неожиданный бонус. Голосовой агент использует Яндекс SpeechKit для распознавания речи. Когда сервер стоял за океаном, каждая реплика делала два трансатлантических рейса: пользователь → сервер → распознавание → сервер. Теперь и сервер, и распознавание в одной стране, разговор стал заметно живее. Если у вас связка «зарубежный хостинг + российский сервис», посчитайте, сколько вы платите километрами.
Расходы стали предсказуемыми. Фиксированная стоимость сервера против почасовой оплаты, где счёт зависит от трафика и настроения планировщика.
Зависимость от чужих решений уменьшилась. Не исчезла — модель по-прежнему внешняя, — но точек отказа стало меньше.
Чек-лист, если собираетесь переезжать
Всё, что описано выше, сводится к нескольким проверкам, которые лучше сделать до переезда, а не после:
Ходят ли ваши внешние API на российские адреса? Проверяется одним curl с любого российского сервера. Смотрите на код отказа: 401 — вас пустили, 403 — нет.
Есть ли у вас что-то, что работает через вебхуки или обратные вызовы? Всё это придётся переворачивать на опрос.
Забирает ли кто-то файлы с вашего сервера по ссылке? Проверьте заранее, доходят ли до вас за ними.
Собирается ли ваш образ с российского адреса? Если тянете публичные образы — заранее настройте зеркала.
Что вы отправляете в модель? Если там персональные данные — маскировку лучше написать до переезда, а не после.
Мораль простая. Исходящие соединения работают почти всегда. Входящие — как повезёт. Проектируйте так, чтобы инициатором связи были вы.
UPD из комментариев. Подсказали важное, чего в статье не хватало: обезличивание это только половина дела, данные надо ещё и удалять по достижении цели обработки.
Логика ровно та же, что с маскировкой: заявка ушла владельцу, цель достигнута, дальше держать переписку незачем. Просто эта часть не мешает работать, поэтому её легко отложить на потом.
Так что к чек-листу выше добавляется шестой пункт: решите, сколько вы храните диалоги и что с ними происходит потом.
Я делаю ИИ-агентов для малого бизнеса под брендом «Первый ИИ», сайт pervyyii.ru. Разборы вроде этого, про грабли на которые наступаю по дороге, пишу в телеграм-канале @pervyyii.
Комментарии (10)

VsBirdEye
18.07.2026 11:01Автор, ваши находки ложатся в более общую и простую канву, которую теперь необходимо держать в голове при организации сервисов, пересекающих виртуально-сетевую границу РФ
1) ТПСУ режет или унижает траффик по AS. Запросы из РФ в эти подсети могут не пройти вообще, могут троттлиться. В обратную сторону - без гарантии тоже, кейс с вебхуком блокированного телеграмма тому пример. Есть локации и подсети, с которыми покачто нормальная скорость и пинг, можно их использовать как релеи.
2) Оказание услуг и api-сервисов по запросам с РФ-адресом geoip может быть заблокировано, отказ может выглядеть как угодно, зависит от реализации. Антропики в этом очень упоротые.

eignatiev Автор
18.07.2026 11:01Да, вы точнее сформулировали то, к чему я пришёл на ощупь. Про обратную сторону добавлю наблюдение: с картинками было не “медленно” и не “оборвалось на середине”, а вообще ни одной попытки. В логах веб-сервера пусто, при том что за соседними файлами в той же папке приходили и спокойно забирали. На троттлинг не похоже, скорее что-то более грубое и избирательное. Про отказы api согласен, выглядят по-разному, и это отдельная боль при диагностике. У Антропик хотя бы честный мгновенный 403 по стране, ещё до проверки ключа - по нему сразу понятно, что дело не в конфиге. Хуже когда просто таймаут без объяснений, тогда полдня ищешь проблему у себя. Про релеи - да, но список живых локаций меняется, закладываться на конкретную надолго не стоит. Проверять периодически приходится заново.

yulia_voistinnykh
18.07.2026 11:01Как знакомо, переехали на российский сервер, чтобы соблюдать законы рф и 2 месяца уже возимся с ошибками.
У нас в мобильном приложении такая же система скрытия личных данных, юрист одобрил, долго с ним разбирали этот вопрос.
eignatiev Автор
18.07.2026 11:01О, вот это ценно. У нас юриста в проекте нет, схему собирал на своей логике и на здравом смысле, так что каждый раз есть сомнение - а точно ли это считается обезличиванием. Если не секрет, юрист смотрел на обратимость замены? Меня именно этот момент смущает больше всего. Таблица соответствий лежит у нас на сервере и наружу не уходит, но формально-то она существует. Где проходит граница между обезличиванием и псевдонимизацией - я так и не понял до конца. И про два месяца очень знакомо. У нас неделя ушла только на то, чтобы понять, что часть проблем вообще не наши и чинить их бесполезно.

yulia_voistinnykh
18.07.2026 11:01Юрист говорит, что раз зарубеж ничего не уходит, то тут на российском сервере неважно как я это храню, это в любом случае законно. Плюс я сделала политику удаления данных. Периодически все чищу и долго не храню.

eignatiev Автор
18.07.2026 11:01Вот про удаление вы мне прямо в больное место попали. Диалоги копятся в базе бессрочно, точечно удаляю только тестовое. Хотя логика ровно та же, что с обезличиванием: цель обработки достигнута, заявка ушла владельцу - дальше держать переписку незачем. Просто эта часть не мешает работать, поэтому до неё и не доходят руки. Про “не покидают Россию” тоже сходится. У нас за границу уходят плейсхолдеры, но раз в них ничего личного нет, то формально и передавать нечего. Видимо ваш юрист про это и говорил. Спасибо, реально полезно. Ради таких комментариев и пишу.

joeberetta
18.07.2026 11:01Тоже не юрист
Но помнится есть пару законов по типу закона яровой, который требует хранения данных даже после их удаления по запросу пользователя (типа аля gdpr для юзера, чтоб мы ему по его запросу предоставили и также удалили, если запросит; но при этом в "холодном" виде надо както хранить для обработки запросов госорганов, которые имеют право и могут потребовать от вас данные по конкретному(ым) пользователям)
Так что, думаю, если вы в настоящее время занимаетесь парковкой вашего сервиса под законодательство рф, то 1 из следующих действий так или иначе будет увлекательное занятие по политикам хранения и обработки перс данных и подготовке их для госорганов, ну и седня буквально гдето очередную статейку читал и там вскольз была тема про перс данные и "ошибки" микросервисной архитектуры, когда данные по пользаку расползаются по всей системе и будет больно потом собирать их (лучше заранее подготовиться)
З.ы. прошу прощения за поток мыслей в неструктурированном виде, пишу из телефона в перекуре между ужином

eignatiev Автор
18.07.2026 11:01Яровая это про организаторов распространения информации, тех кто в реестре РКН: мессенджеры, соцсети, форумы. Бот-консультант на сайте туда не попадает. У нас чистый 152-ФЗ, а там наоборот: отозвали согласие, удаляем в 30 дней. Хранить “на всякий” не надо. А про микросервисы в точку, только у нас с обратным знаком: сидим на монолите, все диалоги в одной базе. Прикрутили автоочистку на 90 дней, тексты сносим, сессии обезличиваем. Один запрос по расписанию. Был бы зоопарк сервисов, собирал бы неделю и всё равно что-то забыл.
himch
Погодите, если вы используете зарубежные модели для общения с клиентом, происходит трансграничная передача персональных данных и их обработка на зарубежных серверах.
Или я ошибаюсь?
eignatiev Автор
Не ошибаетесь, если слать как есть - так и будет. Поэтому и не шлём как есть. До модели текст доезжает уже с заменами: вместо телефона [PHONE], вместо имени [NAME], с документами так же. Таблица соответствий лежит на сервере и в запрос не уходит. Ответ разворачиваю обратно перед показом, клиент видит своё имя, модель его не видела. Момент, который вы скорее всего и имеете в виду: обезличивание работает только если по тексту нельзя понять кто это. Одного телефона мало, в диалоге хватает косвенных зацепок. Поэтому маскирую ещё имена, адреса, документы. А контакт для заявки вообще достаю локально регуляркой, модель для этого не нужна. Юрист из меня так себе, гарантий не даю. Но это всё равно другая история, чем слать переписку целиком и надеяться на галочку согласия. Утечёт у них лог - живых контактов там не будет.