- BrainTools - https://www.braintools.ru -
Думаю, практически каждый разработчик из России рано или поздно задавался вопросом: можно ли наконец перестать плясать с VPN и прокси, чтобы просто пользоваться нейросетями — и в собственных проектах, и непосредственно во время разработки?
Пока всё работает в браузере, проблема ещё выглядит терпимой. Но затем появляется Codex или Claude Code, несколько локальных проектов, Docker-контейнеры, тестовые интеграции — и внезапно оказывается, что доступ к моделям необходимо отдельно настраивать буквально для каждого инструмента. Где-то не проходит авторизация, где-то отваливается стриминг, а где-то терминал просто не видит прокси, который прекрасно работает в браузере.
Короткий ответ на поставленный вопрос: да, от этой конструкции можно избавиться. В статье мы соберём собственный AI-контур на зарубежном VPS и направим через него всю работу с моделями.
Внутри контура будут два основных компонента. OmniRoute позволит подключить модели, доступные в рамках подписок ChatGPT, Claude и других сервисов, а затем обращаться к ним через OpenAI-совместимый API. LiteLLM возьмёт на себя централизованное управление официальными API-ключами, моделями, маршрутами, пользовательскими ключами, лимитами и логами.
Сам VPS при этом станет не просто сервером с двумя прокси. Мы превратим его в полноценную среду разработки: подключимся через VS Code Remote SSH, установим Codex и другие CLI-инструменты и будем работать с проектами непосредственно на сервере. В результате и редактор, и терминал, и AI-агенты окажутся в одном контуре с единым зарубежным IP-адресом.
Отдельно разберёмся с подписками. Если у вас уже есть платный ChatGPT или Claude, часть доступных лимитов можно использовать не только в веб-интерфейсе, но и в инструментах разработки. Мы подключим такую авторизацию к OmniRoute и получим собственный OpenAI-совместимый endpoint.
Здесь важно сразу договориться о терминах. Мы не получаем официальный API-ключ OpenAI или Anthropic и не превращаем подписку в безлимитный API. OmniRoute хранит авторизацию вашего аккаунта, общается с провайдером от его имени и выдаёт отдельный локальный ключ для доступа к своему шлюзу. На практике для наших приложений это выглядит почти как обычный OpenAI API, но внутри работает совершенно другая схема авторизации.
Такой вариант отлично подходит для личной разработки, экспериментов и тестовых интеграций. Для публичного продакшена всё же следует использовать официальные API-ключи провайдеров, учитывать их правила и нормально оплачивать фактическое потребление. Мы же, конечно, будем проверять всё исключительно в тестовом контуре. Не станем ведь бездумно экономить на токенах топовых моделей, правда?
На всю настройку понадобится примерно один вечер. В результате вы получите удалённую среду разработки и собственный OpenAI-совместимый endpoint для приложений и локальных AI-агентов.
|
Выделенные и виртуальные серверы в Европе, США и России Готовые серверы + предустановленное программное обеспечение, а также индивидуальные конфигурации серверов. Посмотреть [1] |
Для повторения [2] материала потребуется следующее:
Подписка ChatGPT или Claude. Для демонстрации достаточно базового платного тарифа одного из сервисов. Если подписки пока нет, большую часть инфраструктуры всё равно можно собрать и подключить к ней обычные API-ключи.
API-ключ любого поддерживаемого провайдера. В примере я также подключу официальный ключ OpenAI и покажу, как централизованно управлять им через LiteLLM.
VPS с зарубежным IP-адресом. Если своего сервера нет, в следующем разделе мы выберем недорогой вариант и подготовим его с нуля.
Доменное имя. Строго говоря, для первых локальных тестов оно не обязательно, но с доменом мы сможем нормально настроить HTTPS и не передавать ключи по открытому соединению.
Общее понимание API. Желательно представлять, что такое endpoint, API-ключ, JSON и название модели. Впрочем, прямо сейчас проведём короткий ликбез, чтобы дальше говорить на одном языке.
Когда мы пишем сообщение в ChatGPT, техническая часть общения скрыта за интерфейсом. Мы вводим текст, нажимаем кнопку и получаем ответ. Но если с моделью работает наше приложение, примерно тот же процесс приходится описывать явно.
Приложение отправляет на сервер провайдера обычный HTTP-запрос. В нём указывается:
адрес API;
ключ, по которому сервер понимает, кто выполняет запрос;
модель, которая должна ответить;
история сообщений;
дополнительные параметры — например, нужен ли потоковый ответ.
Для OpenAI-совместимого API базовый запрос выглядит примерно так:
curl https://gateway.example.com/v1/chat/completions
-H "Authorization: Bearer sk-example-key"
-H "Content-Type: application/json"
-d '{
"model": "gpt-5.6",
"messages": [
{
"role": "system",
"content": "Ты помощник разработчика. Отвечай кратко и по существу."
},
{
"role": "user",
"content": "Объясни, чем HTTP 502 отличается от HTTP 504."
}
],
"stream": false
}'
Разберём запрос по частям.
https://gateway.example.com [3] — это базовый адрес сервера. Пока здесь указан абстрактный шлюз, но позднее его место займёт наш собственный домен с LiteLLM или OmniRoute.
/v1/chat/completions — endpoint, то есть конкретный путь, отвечающий за генерацию ответа в формате Chat Completions.
Заголовок Authorization содержит ключ доступа. Он может принадлежать непосредственно OpenAI, быть виртуальным ключом LiteLLM или локальным ключом, выпущенным OmniRoute. Для клиентского приложения принципиальной разницы почти нет: оно передаёт строку в формате Bearer <ключ>.
Поле model определяет, какая модель обработает запрос. Причём имя не обязательно должно совпадать с оригинальным названием провайдера. В LiteLLM мы сможем создать собственный псевдоним — например, main-coder — и позднее заменить стоящую за ним модель, не меняя настройки всех подключённых приложений.
Массив messages содержит историю диалога. Сообщение с ролью system задаёт общие правила поведения [4] модели, user передаёт пользовательский запрос, а ответы модели возвращаются с ролью assistant.
Параметр stream определяет способ получения результата. Если передать false, сервер сначала полностью сформирует ответ и только после этого вернёт его клиенту. При значении true текст будет приходить небольшими фрагментами по мере генерации — именно поэтому в ChatGPT и других интерфейсах мы видим ответ постепенно.
В упрощённом виде сервер вернёт примерно такой JSON:
{
"id": "chatcmpl-example",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "HTTP 502 означает, что прокси получил некорректный ответ от вышестоящего сервера..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 52,
"completion_tokens": 91,
"total_tokens": 143
}
}
Конкретная структура может немного различаться в зависимости от провайдера и используемого endpoint, но общий принцип остаётся тем же: передали модель и сообщения — получили ответ и информацию о расходе токенов.
Кстати, выражение «OpenAI-протокол», которое часто используют в разговоре, не совсем точное. Речь идёт не об отдельном сетевом протоколе, а о формате API, который из-за популярности OpenAI стал фактическим стандартом для LLM-инструментов. Его поддерживают локальные модели, облачные провайдеры, роутеры и практически все современные AI-клиенты.
Codex, Claude Code, Qwen Code и другие AI-инструменты разработки работают по тому же базовому принципу. Это не модели сами по себе, а специальные клиентские программы между разработчиком и моделью.
Когда мы просим Codex исправить ошибку [5], он собирает контекст проекта, читает нужные файлы, формирует запрос и отправляет его модели. В ответ модель может вернуть обычный текст или команду на использование инструмента: открыть ещё один файл, выполнить тесты, изменить код или проверить результат.
Один видимый запрос разработчика при этом легко превращается в серию обращений к модели. Агент читает проект, составляет план, вносит изменения, запускает команды, получает ошибки и снова обращается к модели с обновлённым контекстом. Добавьте сюда потоковую передачу, повторные попытки, сжатие истории и tool calling — получится более сложная система, но в её основе всё равно остаются HTTP-запросы, выбранная модель и авторизация.
Разница главным образом в том, кто выполняет всю вспомогательную работу. При ручном вызове через curl мы самостоятельно формируем JSON и разбираем ответ. В Codex или Claude Code этим занимается программа, а мы общаемся с ней через терминал или интерфейс редактора.
Следовательно, если AI-инструмент позволяет изменить базовый адрес API, мы можем направить его не напрямую к провайдеру, а к собственному шлюзу. Именно это позднее сделаем с OmniRoute и LiteLLM.
Но сначала нам понадобится место, где вся эта система будет работать.
Для выбранного стека не нужен сервер с видеокартой: модели останутся у облачных провайдеров. VPS будет принимать запросы, управлять авторизацией, вести логи, запускать Docker-контейнеры и одновременно служить удалённой средой разработки.
Поэтому начнём с первого строительного блока нашего AI-контура.
Начнём с VPS. В нашей схеме он будет одновременно шлюзом для запросов к нейросетям и полноценной удалённой средой разработки. На нём мы развернём OmniRoute, LiteLLM и остальные сервисы, а позднее подключимся к серверу из VS Code и сможем работать с проектами практически так же, как на локальной машине.
Сразу важный момент: GPU-сервер нам не нужен. Сами модели будут работать на стороне OpenAI, Anthropic и других провайдеров. Наш VPS только принимает запросы, передаёт их нужной модели и возвращает ответ. Поэтому переплачивать за видеокарту здесь нет никакого смысла.
Для этой статьи я буду использовать VPS от HOSTKEY [6]. Можно выбрать и другого провайдера, но есть одно принципиальное условие: сервер должен находиться за пределами РФ и получить зарубежный IP-адрес.
Это важно не только для работы LiteLLM. Именно с этого IP будут выполняться авторизация в сервисах, запросы к API и обращения из Codex, Claude Code и других инструментов. Если заказать сервер в российском дата-центре, мы просто перенесём на VPS те же региональные ограничения, от которых собираемся избавиться.
Поэтому при оформлении заказа смотрим не на страну регистрации хостера и не на валюту оплаты, а на фактическое расположение сервера. Для нашей задачи подойдут, например, Нидерланды. В этой статье я буду использовать именно зарубежную локацию.
После регистрации и входа в личный кабинет нажимаем Новый сервер, выбираем зарубежную локацию, а в качестве типа сервера указываем Виртуальный сервер.

Для запуска всей нашей системы я бы ориентировался на следующую минимальную конфигурацию:
4 vCPU;
6 ГБ оперативной памяти [7];
60 ГБ NVMe;
один публичный IPv4-адрес.

Это разумный минимум для Docker, OmniRoute, LiteLLM и удалённой разработки. Если вы планируете держать на сервере несколько проектов, базы данных и дополнительные контейнеры, лучше сразу взять 8 ГБ оперативной памяти. Но для прохождения статьи конфигурации с 6 ГБ будет достаточно.
В качестве операционной системы выбираем чистую Ubuntu 24.04 LTS без дополнительных панелей управления и предустановленного программного обеспечения. Всё необходимое мы установим самостоятельно — так будет проще понимать, что именно работает на сервере, и не придётся разбираться с чужими настройками.

Остальные параметры можно оставить по умолчанию. Ещё раз проверяем выбранную страну, конфигурацию и операционную систему, после чего оплачиваем заказ.
После оплаты переходим в раздел Мои серверы. Развёртывание VPS займёт некоторое время. Когда сервер будет готов, его статус изменится на Доступен.

Одновременно на электронную почту, указанную при регистрации, придёт письмо с данными для подключения. В нём нас интересуют три значения:
IP‑адрес сервера;
имя пользователя — обычно root;
временный пароль.

Сохраните письмо: эти данные понадобятся нам уже на следующем шаге. Если сервер получил статус Активен, а письмо с IP‑адресом и паролем пришло на почту, значит аренда завершена и можно переходить к первоначальной настройке VPS.
Если всё прошло успешно, у вас на руках должны быть:
IP‑адрес сервера;
имя пользователя — в нашем случае root;
временный пароль из письма.
Для начала убедимся, что сервер вообще доступен и выданные данные работают. Открываем терминал на своём компьютере и подключаемся:
ssh root@IP_СЕРВЕРА
Например:
ssh root@1.222.33.44
При первом подключении SSH предупредит, что раньше не видел этот сервер, и покажет отпечаток его ключа:
Are you sure you want to continue connecting (yes/no/[fingerprint])?
По возможности сравните отпечаток с данными в панели провайдера. Если всё совпадает, вводим:
yes
После этого SSH запросит пароль из письма. Во время ввода пароль никак не отображается — даже звёздочками. Это нормально: вводим его вслепую и нажимаем Enter.

Если подключение прошло успешно, мы окажемся в терминале сервера. Проверить текущего пользователя можно командой:
whoami
В ответ должно прийти:
root

Значит, сервер доступен и данные для подключения работают. Теперь выходим обратно на локальный компьютер:
exit
Технически уже можно каждый раз подключаться по IP и вводить пароль. Но дальше мы будем открывать этот же сервер через VS Code Remote SSH, поэтому лучше сразу потратить пару минут и настроить нормальный вход.
Сделаем две вещи:
создадим отдельный SSH-ключ для нашего VPS;
добавим в SSH-конфиг короткий алиас ai_vps_llm (или любое другое имя на ваше усмотрение).
После этого вместо длинной команды с IP-адресом достаточно будет написать:
ssh ai_vps_llm
Пароль сервер больше не запросит.
SSH-ключ состоит из двух частей. Публичный ключ мы загрузим на VPS, а приватный останется на нашем компьютере. Приватный ключ фактически заменяет пароль, поэтому его нельзя отправлять другим людям, публиковать или загружать в Git.
Открываем терминал, подставляем IP-адрес своего сервера и выполняем блок целиком:
# Данные нашего сервера
ALIAS_NAME=ai_vps_llm
SERVER_IP=1.222.33.44
SSH_PORT=22
SSH_USER=root
# Отдельная директория и ключ для этого VPS
KEY_DIR="$HOME/.ssh/project_keys/$ALIAS_NAME"
KEY_PATH="$KEY_DIR/id_ed25519"
mkdir -p "$KEY_DIR"
chmod 700 "$HOME/.ssh" "$KEY_DIR"
# Создаём ED25519-ключ без парольной фразы
ssh-keygen -t ed25519 -f "$KEY_PATH" -N "" -C "$ALIAS_NAME"
# Передаём публичную часть ключа на сервер
# Пароль из письма потребуется ввести в последний раз
ssh -p "$SSH_PORT" "$SSH_USER@$SERVER_IP"
'umask 077; mkdir -p ~/.ssh; touch ~/.ssh/authorized_keys; chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys; cat >> ~/.ssh/authorized_keys'
< "$KEY_PATH.pub"
# Создаём SSH-конфиг, если его ещё нет
touch "$HOME/.ssh/config"
chmod 600 "$HOME/.ssh/config"
# Добавляем алиас сервера
cat >> "$HOME/.ssh/config" <<EOF
Host $ALIAS_NAME
HostName $SERVER_IP
Port $SSH_PORT
User $SSH_USER
IdentityFile $KEY_PATH
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 3
EOF
Разберём, что здесь произошло. Мы создали отдельную пару ключей в директории ~/.ssh/project_keys/ai_vps_llm/. Публичную часть id_ed25519.pub добавили на сервер, а путь к приватной части id_ed25519 указали в локальном SSH-конфиге.
Параметры ServerAliveInterval и ServerAliveCountMax помогают не терять SSH-сессию при кратковременных сетевых сбоях. Это особенно пригодится позднее, когда мы подключим сервер к VS Code и будем подолгу работать с удалёнными проектами.
На Windows нам понадобится встроенный OpenSSH Client. Он уже входит в современные версии Windows 10 и Windows 11. Проверить его наличие можно в PowerShell:
ssh -V
Если команда вывела версию OpenSSH, можно продолжать.
Открываем PowerShell, указываем данные сервера и выполняем следующий блок:
# Данные нашего сервера
$AliasName = "ai_vps_llm"
$ServerIp = "1.222.33.44"
$SshPort = 22
$SshUser = "root"
# Пути к SSH-конфигу и отдельному ключу сервера
$SshDir = Join-Path $env:USERPROFILE ".ssh"
$KeyDir = Join-Path $SshDir "project_keys$AliasName"
$KeyPath = Join-Path $KeyDir "id_ed25519"
$ConfigPath = Join-Path $SshDir "config"
New-Item -ItemType Directory -Force -Path $KeyDir | Out-Null
# Создаём ED25519-ключ
ssh-keygen -t ed25519 -f "$KeyPath"
ssh-keygen дважды попросит указать парольную фразу. Для входа без дополнительных запросов оба раза просто нажимаем Enter.
Теперь передаём публичный ключ на сервер. Пароль из письма понадобится ввести в последний раз:
Get-Content -Raw "$KeyPath.pub" |
ssh -p $SshPort "$SshUser@$ServerIp" "umask 077; mkdir -p ~/.ssh; touch ~/.ssh/authorized_keys; chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys; cat >> ~/.ssh/authorized_keys"
Остаётся добавить алиас в SSH-конфиг:
if (-not (Test-Path $ConfigPath)) {
New-Item -ItemType File -Path $ConfigPath | Out-Null
}
$KeyPathForSsh = $KeyPath.Replace("", "/")
@"
Host $AliasName
HostName $ServerIp
Port $SshPort
User $SshUser
IdentityFile "$KeyPathForSsh"
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 3
"@ | Add-Content -Path $ConfigPath -Encoding utf8
Обратите внимание [8]: в PowerShell я использую переменную $ServerIp, а не $HOST. Имена переменных в PowerShell не зависят от регистра, а $Host — уже существующая системная переменная, которую нельзя просто перезаписать.
Независимо от операционной системы проверка будет одинаковой:
ssh ai_vps_llm
Теперь SSH должен подключить нас к серверу без запроса пароля. Убедимся, что мы по-прежнему вошли под root:
whoami
Ожидаемый ответ:
root

На этом всё. У нас появился короткий SSH-алиас, вход по ключу работает, а пароль от VPS больше не приходится вводить при каждом подключении.
Этот же алиас позднее появится в VS Code Remote SSH [9]: расширение использует стандартный SSH-конфиг и самостоятельно устанавливает на удалённой машине свою серверную часть. Именно поэтому мы не добавляли в конфигурацию RemoteCommand sudo -i и RequestTTY yes — для обычного терминала они допустимы, но при подключении из VS Code могут только помешать.
Если понадобится настроить ещё один сервер, достаточно повторить действия с другим алиасом:
ssh production
ssh staging
ssh backup
Мы вошли на VPS под пользователем root, поэтому в следующих командах sudo использовать не будем.
Начнём с обновления системы и установки нескольких пакетов, которые понадобятся нам дальше:
apt update && apt upgrade -y
apt install -y ca-certificates curl git gnupg jq unzip
После обновления проверим, установлены ли на сервере Docker и Docker Compose:
docker -v && docker compose version
Если Docker отсутствует, терминал вернёт ошибку примерно такого вида:
docker: command not found

Если Docker установлен, но не хватает Compose, первая команда покажет версию Docker, а вторая завершится ошибкой.
Docker будем устанавливать из официального репозитория [10]. Пакеты из стандартного репозитория Ubuntu могут отставать по версиям, а вместе с официальным репозиторием мы сразу получим Docker Engine, Buildx и современный Compose Plugin.
Сначала добавляем официальный GPG-ключ Docker:
apt update
apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg
-o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
Теперь подключаем официальный репозиторий Docker:
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
Обновляем список доступных пакетов:
apt update
И устанавливаем Docker Engine вместе с необходимыми дополнениями:
apt install -y
docker-ce
docker-ce-cli
containerd.io
docker-buildx-plugin
docker-compose-plugin
Включаем автоматический запуск Docker вместе с системой и сразу запускаем сервис:
systemctl enable --now docker
Повторно проверяем версии:
docker -v && docker compose version

Дополнительно запустим тестовый контейнер:

Теперь установим на VPS AI-инструмент, с которым будем работать непосредственно во время разработки.
Здесь выбирайте вариант в зависимости от имеющейся подписки:
для подписки ChatGPT устанавливаем Codex;
для подписки Claude устанавливаем Claude Code;
если есть обе подписки, можно установить оба инструмента — друг другу они не мешают.
Устанавливать и авторизовывать CLI нужно под тем же пользователем, под которым мы будем работать через VS Code. В нашем случае это root. Данные авторизации сохраняются в домашней директории пользователя, поэтому после перехода на другого пользователя вход пришлось бы выполнять повторно.
Для Linux OpenAI рекомендует нативный установщик Codex CLI [11]:
curl -fsSL https://chatgpt.com/codex/install.sh | sh

Проверяем, что команда появилась в системе:
codex --version

Поскольку мы работаем на удалённом VPS без графического интерфейса, обычная браузерная авторизация может не получить обратный ответ от локального браузера. Поэтому используем вход по коду устройства, но перед этим убедитесь, что в вашем аккаунте разрешен вход по коду устройства:

Далее вводим:
codex
Затем выбираем вход по коду устройства:

Codex покажет ссылку и одноразовый код. Открываем ссылку в браузере на своём компьютере, входим в аккаунт ChatGPT с активной подпиской и вводим полученный код.

После успешной авторизации создадим тестовую рабочую директорию:
mkdir -p ~/ai-workspace/test
cd ~/ai-workspace/test
Запускаем Codex:
codex
При первом запуске Codex может попросить подтвердить доверие к текущей директории. Подтверждаем и отправляем простое тестовое сообщение:
Привет, ты тут? Кто ты?
Если Codex ответил, значит установка завершена, подписка подхватилась, а обращения к моделям с зарубежного IP работают.

Чтобы завершить работу с Codex, нажимаем Ctrl+C или вводим команду выхода.
Для Claude Code Anthropic также рекомендует нативный установщик [12]:
curl -fsSL https://claude.ai/install.sh | bash
Проверяем установленную версию:
claude --version

Если команда вывела номер версии Claude Code, запускаем клиент:
claude
При первом запуске Claude Code предложит авторизоваться. Для этого потребуется подписка Claude Pro, Max, Team или Enterprise. Бесплатный аккаунт Claude.ai [13] доступ к Claude Code не предоставляет.
Поскольку мы запускаем Claude Code внутри SSH-сессии, браузер на сервере автоматически не откроется. Если это произойдёт, нажимаем c, копируем ссылку авторизации и открываем её в обычном браузере на своём компьютере.
После входа браузер либо автоматически завершит авторизацию, либо покажет код, который нужно вставить обратно в терминал. При успешном входе Claude Code выведет сообщение:
Login successful
После входа отправляем то же тестовое сообщение:
Привет, ты тут? Кто ты?
Если Claude Code ответил, значит клиент установлен, подписка подключена и можно переходить к нормальной работе.
На этом этапе у нас уже есть всё необходимое: зарубежный VPS, вход по короткому SSH-алиасу, Docker и AI-инструмент, авторизованный через нашу подписку.
Работать с сервером через обычный терминал уже можно, но постоянно редактировать файлы командами nano или vim, вручную переключаться между директориями и держать несколько SSH-окон не слишком удобно. Поэтому дальше подключим VPS к VS Code через расширение Remote SSH и превратим сервер в полноценную среду разработки, которая визуально почти не отличается от локальной.
Отлично. Надеюсь, что к этому моменту на вашем сервере уже появился доступ к Codex или Claude Code — в зависимости от того, какой сервис вы выбрали. А возможно, вы установили сразу оба варианта, что ещё лучше.
Работать с AI-ассистентом через обычный SSH-терминал уже можно, но для повседневной разработки этого всё-таки мало. Хочется видеть дерево проекта, открывать несколько файлов одновременно, пользоваться поиском, Git и остальными привычными инструментами.
Поэтому сейчас мы настроим полноценную среду для удалённой разработки:
интерфейс VS Code будет работать на нашем компьютере;
файлы проекта будут храниться на VPS;
команды, терминал, Codex и Claude Code будут запускаться на VPS;
обмен данными с AI-сервисами также будет происходить со стороны сервера.
В результате мы получим привычный редактор на локальном компьютере, но фактически будем работать внутри удалённого сервера.
Сначала устанавливаем Visual Studio Code [14], если его ещё нет на вашем компьютере.
После этого открываем раздел расширений и находим Remote — SSH. Обратите внимание на издателя расширения: это должна быть компания Microsoft.

Устанавливаем расширение и нажимаем F1. На некоторых ноутбуках потребуется сочетание Fn + F1. Также палитру команд можно открыть через Ctrl + Shift + P в Windows и Linux или Cmd + Shift + P в macOS.
В появившейся строке начинаем вводить:
Remote-SSH: Connect to Host...
Выбираем найденную команду. Именно такой порядок подключения описан в официальной документации VS Code Remote SSH [9].

В выпадающем списке должен появиться SSH-алиас, который мы настроили ранее. В нашем случае это:
ai_vps_llm
Выбираем его.

VS Code откроет новое окно и подключится к серверу. Убедиться в этом можно по индикатору в левом нижнем углу: там должна появиться надпись примерно такого вида:
SSH: ai_vps_llm
Если VS Code спросит, доверяете ли вы содержимому сервера, подтверждаем доверие — разумеется, только если это действительно наш VPS.
Теперь нажимаем Open Folder. Вместо стандартного окна выбора папки на локальном компьютере VS Code предложит указать путь на удалённом сервере.
Выбираем тестовую папку, которую создали ранее. Например:
/root/ai-workspace/test

После открытия папки мы можем редактировать находящиеся на VPS файлы так, будто они лежат на нашем компьютере. При этом сохраняться все изменения будут непосредственно на сервере.
Теперь у нас есть два варианта работы с Codex и Claude Code:
Через встроенный терминал VS Code.
Через официальные расширения для VS Code.
Рассмотрим оба.
Для первого варианта у нас уже всё готово.
В верхнем меню VS Code выбираем:
Terminal → New Terminal
Откроется терминал удалённого сервера. При желании можно проверить текущую папку:
pwd
После этого запускаем нужный инструмент. Для Codex:
codex
Для Claude Code:
claude

На этом всё — можно ставить задачу, просить AI-ассистента изучать файлы проекта, писать код, запускать команды и проверять результат.
Главное здесь то, что сам процесс codex или claude работает не на нашем компьютере, а на VPS. Соответственно, запросы к сервису отправляются с IP-адреса сервера.
Локальный IP-адрес компьютера в этой схеме не участвует в подключении AI-ассистента к провайдеру. При этом использование сервиса, конечно, должно соответствовать правилам выбранного провайдера, условиям подписки и законодательству вашей страны: наличие VPS само по себе эти требования не отменяет.
Работа через терминал — простой и надёжный вариант. Но Codex и Claude Code также можно открыть в виде отдельной панели внутри VS Code.
Здесь есть важный нюанс. Расширение необходимо устанавливать именно в удалённую среду, к которой мы подключились по SSH.
Когда открыта удалённая сессия, в разделе расширений VS Code может показывать отдельную кнопку:
Install in SSH: ai_vps_llm
После установки расширение должно появиться в группе примерно с таким названием:
SSH: ai_vps_llm — Installed
Ищем и устанавливаем нужные расширения:
официальное расширение Codex от OpenAI;
официальное расширение Claude Code от Anthropic.
После установки в интерфейсе VS Code появятся дополнительные значки для открытия Codex и Claude Code.

Покажу дальнейшую работу на примере Codex.
Поскольку ранее мы уже авторизовались в Codex CLI на этом же сервере и под тем же пользователем, расширение обычно сможет использовать сохранённые данные авторизации. CLI и расширение Codex совместно используют данные входа на одном хосте — это отдельно описано в документации OpenAI по авторизации Codex [15].
Если окно входа всё-таки появится, выбираем авторизацию через ChatGPT и завершаем её в браузере.
Открыть панель можно через значок Codex либо через палитру команд:
Codex: Open Codex Sidebar
После этого открываем проект, формулируем задачу и начинаем работать. Codex будет видеть файлы удалённой папки и сможет предлагать или вносить изменения в проект. Подробнее эта схема описана в официальной документации Codex для IDE [16].

С Claude Code логика [17] работы будет похожей: открываем его панель, передаём задачу и работаем с файлами проекта. Однако расширение Claude Code содержит собственный компонент для работы с ассистентом и при первом запуске может отдельно запросить вход через браузер — даже если до этого мы уже авторизовались в терминальном клиенте. Это нормальное поведение [18], описанное в документации Anthropic [19].
На этом настройку удалённой среды разработки можно считать законченной. Дальше подключаем Git, GitHub или GitLab и работаем с проектом практически так же, как на локальном компьютере.
Только учитывайте, что Git-команды теперь тоже выполняются на VPS. Поэтому SSH-ключи или другие данные для доступа к приватным репозиториям нужно будет отдельно настроить на сервере. Они не копируются с локального компьютера автоматически.
Мы получили удобную среду, в которой можно запускать Codex и Claude Code на VPS, редактируя файлы через привычный интерфейс VS Code.
Но пока эта схема решает в основном одну задачу — персональную разработку с помощью CLI или расширений.
Для интеграции нейросетей в приложения этого уже недостаточно. Нам потребуется единая точка входа, через которую смогут работать:
собственные приложения;
Telegram-боты;
AI-агенты;
фоновые скрипты;
внутренние сервисы;
инструменты автоматизации;
другие разработчики или члены команды.
При этом хочется не прописывать отдельные адреса и ключи для каждого AI-провайдера, а централизованно управлять моделями, доступом, лимитами и расходами.
Для решения этой задачи мы развернём на VPS собственный LLM-шлюз на базе LiteLLM.
LiteLLM [20] — это инструмент, который позволяет обращаться к большому количеству AI-провайдеров через единый OpenAI-совместимый интерфейс.

LiteLLM можно использовать как библиотеку внутри Python-проекта, но нас в рамках статьи интересует другой режим — LiteLLM Proxy, который также называют AI Gateway.
В этом режиме LiteLLM запускается как отдельный сервис и становится промежуточным слоем между нашими приложениями и поставщиками моделей.
Упрощённо схема выглядит так:
Приложение → LiteLLM на VPS → OpenAI, Anthropic, Gemini или другой провайдер
Приложению больше не нужно знать, к какому именно провайдеру оно обращается. Оно отправляет стандартный OpenAI-совместимый запрос на наш сервер, а LiteLLM определяет, куда его направить. Сама отправка запроса, как вы поняли, будет выполнена с зарубежного IP-адреса, а, следовательно, мы так обойдем региональные ограничения доступа.
Например, со стороны приложения мы указываем:
адрес нашего LiteLLM;
выданный нами ключ;
условное имя модели.
Внутри LiteLLM это имя можно связать с конкретной моделью OpenAI, Anthropic, Gemini, локальным сервером или другим OpenAI-совместимым API.
Во-первых, мы получаем единую точку входа. Вместо нескольких разных API можно использовать один адрес:
https://наш-домен/v1
Во-вторых, LiteLLM позволяет хранить ключи провайдеров централизованно. Приложениям не обязательно передавать настоящий ключ OpenAI или другого сервиса — вместо него можно создать отдельный виртуальный ключ для конкретного проекта или пользователя.
В-третьих, через LiteLLM можно:
назначать отдельные ключи приложениям и пользователям;
устанавливать бюджеты и ограничения;
отслеживать расходы;
собирать логи запросов;
создавать понятные названия и алиасы моделей;
переключать приложение между провайдерами без изменения его кода;
настраивать повторные попытки и резервные модели;
распределять запросы между несколькими моделями или провайдерами;
управлять всем этим через одну конфигурацию.
Например, сегодня наш внутренний сервис может обращаться к модели OpenAI, а завтра мы переключим тот же алиас на другую модель. Если формат ответа остаётся OpenAI-совместимым, код приложения менять не потребуется.
Здесь важно сразу провести границу.
LiteLLM не предоставляет собственные модели, не создаёт бесплатные токены и не превращает подписку ChatGPT или Claude в официальный API-ключ.
Если мы подключаем к LiteLLM официальный API-ключ OpenAI, запросы оплачиваются по правилам OpenAI API. То же самое относится к другим провайдерам.
LiteLLM в нашей схеме отвечает за маршрутизацию и централизованное управление. Способ подключения конкретного источника моделей — это уже отдельный слой.
Именно поэтому позднее нам понадобится OmniRoute. Он будет отвечать за работу с авторизацией подписочных сервисов, а LiteLLM станет центральным шлюзом, через который мы объединим доступные модели в один OpenAI-совместимый API.
Проще говоря:
OmniRoute подключает подписочные источники;
LiteLLM объединяет источники и управляет доступом к ним;
наши приложения работают с одним адресом и одним понятным протоколом.
Далее мы развернём LiteLLM на VPS, подключим к нему официальный API-ключ OpenAI и проверим первый запрос через собственный OpenAI-совместимый endpoint.
Прежде чем поднимать LiteLLM и OmniRoute, привяжем к серверу доменные имена. Технически оба сервиса можно открыть и по IP-адресу, но тогда придётся либо работать по обычному HTTP, либо отдельно бороться с сертификатами. Домен сразу даёт нам нормальный HTTPS, понятные адреса для API и аккуратные конфигурации клиентов.
Я использую домен, зарегистрированный в REG.RU [21], но регистратор здесь вообще не важен. Подойдёт любой сервис, в котором можно управлять DNS-записями. Более того, покупать новый домен необязательно: можно создать два поддомена у уже существующего.
В примере будут использоваться два адреса:
litellm-hk.yakvenalex.ru [22] — веб-интерфейс и единый API LiteLLM;
omni-hk.yakvenalex.ru [23] — веб-интерфейс и API OmniRoute.

В панели управления DNS создаём для каждого поддомена A-запись и указываем в ней публичный IP нашего VPS. Если используется корневой домен без поддомена, логика та же: A-запись должна вести на сервер.
Проверить, что записи уже обновились, можно прямо с сервера:
dig +short litellm-hk.yakvenalex.ru
dig +short omni-hk.yakvenalex.ru

Обе команды должны вернуть IP нашего VPS. Обновление DNS иногда занимает несколько минут, а в отдельных случаях — несколько часов. Пока адрес указывает не на тот сервер, переходить к выпуску сертификата рано.
Теперь развернём LiteLLM Proxy за nginx и HTTPS. В результате получится следующий стек: LiteLLM принимает OpenAI-совместимые запросы и даёт веб-админку, Postgres хранит модели и виртуальные ключи, nginx принимает внешний трафик, а certbot выпускает и автоматически продлевает сертификат Let’s Encrypt.
Установим необходимые пакеты:
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx openssl dnsutils
Создаём отдельную папку проекта:
sudo mkdir -p /opt/my_projects/lite_llm
cd /opt/my_projects/lite_llm
Секреты не будем размазывать по Docker-конфигу. Они будут лежать в отдельном файле .env, который не должен попадать в Git.
Сначала сгенерируем четыре случайных значения:
openssl rand -hex 24
openssl rand -hex 24
openssl rand -hex 24
openssl rand -hex 24

Одно значение используем для пароля админки, второе — для master key, третье — для salt key, четвёртое — для Postgres. Создаём файл .env:
# Вход в веб-интерфейс
UI_USERNAME=admin
UI_PASSWORD=<случайный_пароль>
# Root-ключ LiteLLM. Значение должно начинаться с sk-
LITELLM_MASTER_KEY=sk-<случайная_строка>
# Ключ шифрования токенов моделей
LITELLM_SALT_KEY=sk-<случайная_строка>
# Postgres
POSTGRES_USER=litellm
POSTGRES_PASSWORD=<случайный_пароль>
POSTGRES_DB=litellm
Закрываем доступ к файлу для остальных пользователей и добавляем его в .gitignore:
chmod 600 .env
printf '.envn' > .gitignore
Важно. LITELLM_SALT_KEY нельзя менять после добавления моделей. LiteLLM шифрует им учётные данные провайдеров в базе. Если заменить ключ, сохранённые токены перестанут расшифровываться.
В минимальном конфиге включаем хранение моделей в Postgres:
general_settings:
store_model_in_db: true
store_prompts_in_spend_logs: false
litellm_settings:
drop_params: true
set_verbose: false
Параметр store_model_in_db позволяет добавлять модели через веб-интерфейс и не терять их после перезапуска. store_prompts_in_spend_logs: false нужен, чтобы по умолчанию не сохранять тексты промптов в логах расходов. drop_params: true отбрасывает параметры, которые конкретный провайдер не поддерживает.
Поднимем два контейнера. LiteLLM будет запускаться только после того, как Postgres пройдёт healthcheck. Порт 4000 привязываем к 127.0.0.1: снаружи к нему будет обращаться только nginx.
services:
litellm:
image: ghcr.io/berriai/litellm:main-stable
container_name: litellm
restart: unless-stopped
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml:ro
command: ["--config", "/app/config.yaml", "--port", "4000"]
environment:
LITELLM_MASTER_KEY: ${LITELLM_MASTER_KEY}
LITELLM_SALT_KEY: ${LITELLM_SALT_KEY}
UI_USERNAME: ${UI_USERNAME}
UI_PASSWORD: ${UI_PASSWORD}
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
STORE_MODEL_IN_DB: "True"
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "python -c "import urllib.request; urllib.request.urlopen('http://localhost:4000/health/liveliness')" || exit 1"]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
postgres:
image: postgres:16-alpine
container_name: litellm-db
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- litellm_pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
litellm_pg_data:
Запускаем сервисы и проверяем их состояние:
docker compose up -d
docker compose ps
docker compose logs --tail=100 litellm
В списке должны быть два запущенных контейнера: litellm и litellm-db. Если LiteLLM ещё имеет статус starting, подождите полминуты и повторите docker compose ps.

Создаём конфигурацию /etc/nginx/sites-available/litellm:
server {
listen 80;
listen [::]:80;
server_name litellm-hk.yakvenalex.ru;
client_max_body_size 50m;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Включаем сайт и перечитываем конфигурацию:
sudo ln -s /etc/nginx/sites-available/litellm /etc/nginx/sites-enabled/litellm
sudo nginx -t
sudo systemctl reload nginx
proxy_buffering off особенно важен для потоковых ответов: без него nginx может накапливать части ответа вместо того, чтобы сразу отдавать их клиенту.
На этом этапе A-запись уже должна указывать на VPS, а порты 80 и 443 должны быть открыты. Выпускаем сертификат Let’s Encrypt:
sudo certbot --nginx -d litellm-hk.yakvenalex.ru
--non-interactive --agree-tos -m you@example.com --redirect
Замените домен и электронную почту на свои. Certbot сам дополнит nginx-конфиг, включит редирект с HTTP на HTTPS и создаст таймер автопродления.
Проверяем таймер и тестовый выпуск сертификата:
systemctl status certbot.timer --no-pager
sudo certbot renew --dry-run
Открываем веб-интерфейс:
У меня это: https://litellm-hk.yakvenalex.ru/ui/ [24]
Входим под UI_USERNAME и UI_PASSWORD из файла .env.

Переходим в Models → Add Model. LiteLLM поддерживает множество провайдеров, но сначала подключим обычный официальный API OpenAI.
Заполняем поля:
Provider — OpenAI;
Model — модель, доступная вашему API-проекту; в моём примере gpt-5.4-nano;
Mode — оставляем значение по умолчанию;
OpenAI API Key — официальный API-ключ OpenAI;
API Base — оставляем стандартным.

Сначала нажимаем Test Connect. Если тест прошёл успешно, добавляем модель кнопкой Add Model.


Для первой отладки можно выполнить запрос с master key. Сам ключ в статью и на скриншоты, разумеется, не вставляю:
curl https://litellm-hk.yakvenalex.ru/v1/chat/completions
-H "Authorization: Bearer sk-<master-key>"
-H "Content-Type: application/json"
-d '{
"model": "gpt-5.4-nano",
"messages": [
{"role": "system", "content": "Ты дружелюбный ассистент. Отвечай кратко."},
{"role": "user", "content": "Привет! Назови три факта о Луне."}
]
}'
Важно. Master key даёт административный доступ к прокси. Он подходит для короткой проверки, но его нельзя раздавать приложениям и хранить в клиентском коде.
Переходим в Virtual Keys или API Keys и нажимаем Create New Key. Даём ключу понятное имя, ограничиваем его нужной моделью и при необходимости задаём бюджет и срок действия.

После создания LiteLLM покажет значение sk-…. Копируем его сразу и храним как обычный секрет. Теперь повторяем запрос уже с виртуальным ключом:

curl https://litellm-hk.yakvenalex.ru/v1/chat/completions
-H "Authorization: Bearer sk-<virtual-key>"
-H "Content-Type: application/json"
-d '{
"model": "gpt-5.4-nano",
"messages": [
{"role": "user", "content": "Привет! Назови три факта о Луне."}
]
}'
Вызов работает так же, но теперь его можно отозвать независимо от остальных клиентов. А в разделе Usage появятся запрос, использованная модель, количество токенов, задержка и стоимость — если для модели доступен корректный прайсинг.

Итак, официальный API OpenAI уже доступен через наш домен и единый виртуальный ключ. Но это пока только половина контура: официальный API оплачивается отдельно и никак не связан с лимитами подписки ChatGPT или Claude. Для подписочных источников поднимем второй сервис — OmniRoute.
Внимание! Это важно. Мы переходим к методам, которые не являются официальными. Все действия с подпиской вы выполняете на свой страх [25] и риск. Этот способ не одобрен, и он может привести к блокировке аккаунта.
OmniRoute — self-hosted AI-шлюз с веб-интерфейсом и OpenAI-совместимым API. Он умеет подключать провайдеров по обычным API-ключам и через OAuth, хранить несколько подключений, следить за квотами, автоматически обновлять OAuth-токены и отдавать модели через один endpoint.
Важно. OmniRoute не извлекает из подписки официальный API-ключ Anthropic или OpenAI. Мы авторизуем в шлюзе собственную подписочную учётную запись, а затем создаём локальный ключ OmniRoute для доступа к этому шлюзу. Лимиты, правила использования и условия провайдера при этом никуда не исчезают. Такой доступ не стоит выдавать третьим лицам или использовать как основу публичного коммерческого API без отдельной проверки условий сервиса.
В нашем случае схема будет простой:
Подписка Claude Code или ChatGPT остаётся у провайдера.
OmniRoute хранит OAuth-авторизацию и обновляет её токены.
Мы создаём собственный клиентский ключ OmniRoute.
Клиент вызывает https://omni-hk.yakvenalex.ru/v1 [26] в OpenAI-совместимом формате.
При желании LiteLLM ставится поверх OmniRoute и становится единой точкой доступа ко всем источникам.
Исходный код и актуальная документация проекта находятся в репозитории OmniRoute [27]. В примере используем официальный Docker-образ diegosouzapw/omniroute:latest.
sudo mkdir -p /opt/my_projects/omni/data
cd /opt/my_projects/omni
sudo chown -R 1000:1000 data
OmniRoute хранит SQLite-базу, настройки и зашифрованные подключения в /app/data. На хосте это будет папка ./data. Владелец UID 1000 нужен контейнеру для записи.
Генерируем несколько независимых секретов:
openssl rand -hex 32
openssl rand -hex 32
openssl rand -hex 32
openssl rand -hex 32
openssl rand -hex 32
Создаём .env и подставляем разные значения в каждое поле:
# Первый вход в dashboard. После запуска пароль меняем в интерфейсе
INITIAL_PASSWORD=<сложный_первичный_пароль>
# Секреты приложения. Не использовать одно значение повторно
JWT_SECRET=<случайная_строка_1>
API_KEY_SECRET=<случайная_строка_2>
STORAGE_ENCRYPTION_KEY=<случайная_строка_3>
STORAGE_ENCRYPTION_KEY_VERSION=v1
MACHINE_ID_SALT=<случайная_строка_4>
OMNIROUTE_WS_BRIDGE_SECRET=<случайная_строка_5>
# Приложение и хранилище
PORT=20128
NODE_ENV=production
HOSTNAME=0.0.0.0
DATA_DIR=/app/data
STORAGE_DRIVER=sqlite
APP_LOG_TO_FILE=true
AUTH_COOKIE_SECURE=true
REQUIRE_API_KEY=true
# Публичный адрес
BASE_URL=https://omni-hk.yakvenalex.ru
NEXT_PUBLIC_BASE_URL=https://omni-hk.yakvenalex.ru
# Rate limiter и кэш
REDIS_URL=redis://redis:6379
chmod 600 .env
printf '.envndata/n' > .gitignore
Важно. JWT_SECRET, API_KEY_SECRET, STORAGE_ENCRYPTION_KEY и MACHINE_ID_SALT после начала работы не меняем без процедуры миграции. Иначе можно потерять активные сессии или возможность расшифровать сохранённые подключения. Для восстановления понадобятся и папка data, и исходный .env.
В базовом сценарии OmniRoute использует один основной HTTP-порт 20128: через него работают и dashboard, и API /v1. Мы публикуем его только на localhost [28]. Redis вообще не получает внешнего порта.
services:
omniroute:
image: diegosouzapw/omniroute:latest
container_name: omniroute
restart: unless-stopped
stop_grace_period: 40s
env_file: .env
depends_on:
redis:
condition: service_healthy
ports:
- "127.0.0.1:20128:20128"
volumes:
- ./data:/app/data
healthcheck:
test: ["CMD", "node", "healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
redis:
image: redis:7-alpine
container_name: omniroute-redis
restart: unless-stopped
command: redis-server --save 60 1 --loglevel warning
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
redis-data:
name: omniroute-redis-data
stop_grace_period: 40s здесь не декоративный параметр. OmniRoute использует SQLite в WAL-режиме, поэтому контейнеру нужно дать время корректно завершить запись перед остановкой.
Запускаем и проверяем:
docker compose up -d
docker compose ps
docker compose logs --tail=100 omniroute
curl -s -o /dev/null -w "%{http_code}n" http://127.0.0.1:20128/
Корневая страница может ответить 200 или перенаправлением на dashboard. Главное, чтобы контейнер был healthy, а в логах не было ошибок доступа к SQLite.

Создаём /etc/nginx/sites-available/omniroute:
server {
listen 80;
listen [::]:80;
server_name omni-hk.yakvenalex.ru;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:20128;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
sudo ln -s /etc/nginx/sites-available/omniroute /etc/nginx/sites-enabled/omniroute
sudo nginx -t
sudo systemctl reload nginx
Выпускаем сертификат:
sudo certbot --nginx -d omni-hk.yakvenalex.ru
--non-interactive --agree-tos -m you@example.com --redirect
После этого открываем:
У меня: https://omni-hk.yakvenalex.ru [29]
На странице входа вводим INITIAL_PASSWORD из .env. После первого входа сразу переходим в настройки и меняем пароль на новый.

Теперь открываем раздел Providers. В текущей версии он доступен из левого меню; прямой адрес выглядит так:
https://omni-hk.yakvenalex.ru/dashboard/providers

В списке много вариантов: обычные провайдеры с API-ключом, бесплатные тарифы сторонних сервисов и OAuth-подключения инструментов разработки. Нас интересует Claude Code, поэтому выбираем его и нажимаем Add Connection.

OmniRoute сформирует OAuth-ссылку. Открываем её, входим в собственную учётную запись Anthropic и подтверждаем доступ. Если страница провайдера недоступна из вашей текущей сети, этап авторизации придётся пройти из сети, в которой она открывается. После подключения обычные запросы уже будет отправлять VPS.

При удалённом развёртывании OAuth иногда завершается не автоматическим возвратом в dashboard, а страницей с callback-адресом. В этом случае копируем полный URL из адресной строки — вместе с параметрами code и state — и вставляем его в поле ручного завершения авторизации в OmniRoute.

После успешного подключения OmniRoute покажет доступные для этой учётной записи модели и информацию о квоте. Имена моделей имеют префикс провайдера. Например:
cc/claude-opus-4-6
Конкретный список зависит от версии OmniRoute и моделей, доступных вашей подписке, поэтому копируйте имя непосредственно со страницы своего подключения.

Открываем раздел API Manager или Endpoints. В текущем интерфейсе страница управления ключами доступна по адресу:
https://omni-hk.yakvenalex.ru/dashboard/api-manager
Создаём новый ключ, даём ему понятное имя и копируем значение sk-…. Это и есть наш локальный ключ шлюза. Он не является официальным ключом Anthropic и действует только на нашем домене OmniRoute.

Проверяем OpenAI-совместимый endpoint:
curl -s -X POST "https://omni-hk.yakvenalex.ru/v1/chat/completions"
-H "Authorization: Bearer sk-<omniroute-key>"
-H "Content-Type: application/json"
-d '{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Привет, как дела?"}
],
"stream": false
}'
Если в ответ пришёл JSON с сообщением модели, связка подписка → OAuth → OmniRoute → OpenAI-совместимый API работает.

Сейчас у нас уже есть два рабочих endpoint. LiteLLM обслуживает официальный API, а OmniRoute — подписочную авторизацию. Но смысл нашего контура как раз в том, чтобы клиентам не приходилось знать о двух разных адресах. Поэтому добавим OmniRoute в LiteLLM как OpenAI-совместимого провайдера.
В LiteLLM открываем Models → Add Model и заполняем поля:
Model Name — публичный алиас, например claude-opus-subscription;
Provider — OpenAI-Compatible;
Provider Model — openai/cc/claude-opus-4-6;
API Base — https://omni-hk.yakvenalex.ru/v1 [26];
API Key — созданный клиентский ключ OmniRoute.
Префикс openai/ нужен LiteLLM, чтобы отправить запрос на совместимый endpoint через OpenAI-клиент. Пользователи при этом будут вызывать короткий публичный алиас claude-opus-subscription.
Нажимаем Test Connect, добавляем модель и проверяем уже единый endpoint LiteLLM:
curl https://litellm-hk.yakvenalex.ru/v1/chat/completions
-H "Authorization: Bearer sk-<litellm-virtual-key>"
-H "Content-Type: application/json"
-d '{
"model": "claude-opus-subscription",
"messages": [
{"role": "user", "content": "Привет! Ответь одной строкой."}
]
}'
Теперь приложение знает только адрес LiteLLM и свой виртуальный ключ. За этим адресом могут одновременно находиться официальный OpenAI API, Claude Code через OmniRoute и любые другие источники. Модель переключается значением model, а ключи, лимиты и логи централизованно управляются в LiteLLM.
Для повседневного управления достаточно нескольких команд:
cd /opt/my_projects/omni
docker compose ps
docker compose logs -f omniroute
docker compose restart omniroute
docker compose pull && docker compose up -d
Перед обновлением делаем резервную копию. Копировать нужно и данные, и .env; без исходных ключей шифрования одна SQLite-база может оказаться бесполезной.
cd /opt/my_projects/omni
docker compose stop omniroute
sudo tar czf /root/omniroute-backup-$(date +%F).tgz data .env docker-compose.yml
docker compose start omniroute
Самые частые проблемы выглядят так:
HTTP 500 и ошибки SQLite — проверьте права на ./data и владельца UID 1000;
после перезапуска разлогинивает — вероятно, изменился JWT_SECRET;
подключения перестали расшифровываться — проверьте STORAGE_ENCRYPTION_KEY и API_KEY_SECRET;
nginx отдаёт 502 — проверьте docker compose ps и логи omniroute;
не сохраняется cookie за HTTPS — проверьте AUTH_COOKIE_SECURE=true и X-Forwarded-Proto;
долгий ответ обрывается — увеличьте proxy_read_timeout и proxy_send_timeout.
Важно. Не публикуйте наружу порты 20128 и 6379. Для внешнего доступа достаточно nginx на 443. Файл .env не коммитим, master key LiteLLM не вставляем в приложения, а клиентские ключи отзываем сразу после утечки.
К этому моменту VPS выполняет сразу три роли: служит удалённой средой разработки, принимает подписочные подключения через OmniRoute и отдаёт единый управляемый API через LiteLLM. Мы можем создавать отдельные ключи для приложений, ограничивать модели и бюджеты, а затем смотреть все вызовы в одном журнале.
Remote SSH удобен, когда проект действительно должен жить и выполняться на сервере. Но иногда хочется оставить исходники на своём компьютере и всё равно вайбкодить через собственный endpoint — без постоянного удалённого окна VS Code. В следующем разделе настроим локальный Qwen Code или OpenCode, укажем ему адрес нашего LiteLLM и проверим, как выглядит тот же рабочий процесс уже без Remote SSH.
До сих пор мы рассматривали два сценария. Сначала запускали Codex или Claude Code непосредственно на VPS, затем работали с тем же сервером через VS Code Remote SSH. Оба варианта удобны, но у них есть общее свойство: исходники и AI-инструмент живут на удалённой машине.
Теперь сделаем наоборот. Проект, Git, терминал и VS Code останутся на домашнем компьютере, а к моделям локальный агент будет обращаться через наш HTTPS-endpoint. VPN для самого инструмента при такой схеме не нужен: клиент соединяется с нашим доменом, а дальше запрос обрабатывает зарубежный VPS.
В качестве агента возьмём Qwen Code. По логике работы он близок к Claude Code и Codex: запускается в терминале, читает файлы проекта, предлагает изменения, выполняет команды с подтверждением и умеет работать из VS Code. При этом он не привязан только к моделям Qwen и позволяет подключить произвольный OpenAI-совместимый провайдер.
Тот же принцип работает и с OpenCode. Его короткую конфигурацию я покажу в конце раздела, но основную демонстрацию проведём в Qwen Code.
Актуальные варианты установки собраны в официальной инструкции Qwen Code [30]. Выбирайте команду для своей платформы.
Linux и macOS, быстрый установщик:
curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.sh | bash
Windows PowerShell:
irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.ps1 | iex
После быстрого установщика перезапускаем терминал. Есть и универсальный вариант через npm, но для него нужен Node.js 22 или новее:
npm install -g @qwen-code/qwen-code@latest
Проверяем установку:
qwen --version

Открываем терминал в папке локального проекта и запускаем Qwen Code:
cd /path/to/local/project
qwen
При первом запуске появится мастер авторизации. Если Qwen Code уже был настроен, тот же мастер можно открыть в любой момент командой /auth.
/auth
Выбираем Custom Provider, затем OpenAI-compatible. Этот вариант подходит и для Claude-моделей: значение имеет не компания-разработчик модели, а протокол endpoint, через который мы к ней обращаемся.

Далее мастер запросит Base URL. Для прямого подключения к OmniRoute вводим:
https://omni-hk.yakvenalex.ru/v1
На следующем шаге вставляем клиентский ключ OmniRoute, который создали в API Manager. Master key LiteLLM и секреты из .env здесь не нужны.
sk-<omniroute-client-key>

После этого Qwen Code предложит перечислить модели через запятую. Имена берём со страницы Providers или Endpoints в OmniRoute — вместе с префиксом cc/. Например:
cc/claude-sonnet-4-6,cc/<точное-имя-модели-2>,cc/<точное-имя-модели-3>
В моём случае я добавляю три модели. Не копируйте названия вслепую из статьи: OmniRoute и сами провайдеры обновляются, поэтому точный идентификатор лучше взять из собственного dashboard.

На следующих экранах можно включить reasoning, разрешить обработку изображений и указать размер контекстного окна. Эти параметры не делают модель мощнее сами по себе: включаем только те возможности, которые действительно поддерживают выбранная модель и наш upstream. Если сомневаетесь, сначала оставьте значения по умолчанию.

После сохранения открываем переключатель моделей:
/model
В списке должны появиться все модели, которые мы только что добавили. Выбираем рабочую — в моём примере это cc/claude-sonnet-4-6.

Для первого теста не стоит сразу поручать агенту переписывать половину проекта. Попросим его сначала изучить репозиторий без изменений:
Изучи структуру проекта. Ничего не меняй. Коротко объясни, как он устроен, какие команды запускают приложение и тесты.
Если агент прочитал локальные файлы и вернул осмысленный ответ, проверяем изменение на небольшой задаче:
Добавь в README короткий раздел «Локальный запуск». Сначала покажи предлагаемый diff и меняй файл только после моего подтверждения.
Qwen Code должен показать изменение и запросить разрешение. Это важнее простого ответа «Привет»: мы проверяем всю цепочку — чтение локального проекта, вызов модели через OmniRoute, возврат tool call и применение изменения на домашней машине.
Если вместо прямого OmniRoute хочется сохранить централизованные ключи, бюджеты и логи LiteLLM, в мастере указываем другой набор параметров:
Base URL — https://litellm-hk.yakvenalex.ru/v1 [31];
API key — виртуальный ключ LiteLLM;
Model — публичный алиас LiteLLM, например claude-opus-subscription.
Для повседневной работы это даже удобнее: Qwen Code знает только клиентский ключ LiteLLM, а реальный источник модели можно заменить на сервере, не перенастраивая локальную машину.
Если терминальный интерфейс не нравится, устанавливаем официальный плагин Qwen Code Companion. Делать это нужно в обычном локальном окне VS Code, а не в экземпляре, подключённом к VPS через Remote SSH.
Расширение доступно в Visual Studio Marketplace [32]. Проверяем название Qwen Code Companion и издателя qwenlm.

Открываем панель по иконке Qwen или через палитру команд: Qwen Code: Open. Расширение использует локальную конфигурацию Qwen Code. Если ранее созданный провайдер не появился, запускаем Qwen Code: Run и повторяем /auth уже из встроенного терминала расширения.
Выбираем ту же модель cc/claude-sonnet-4-6 и повторяем короткую проверку. Теперь дифф, история и контекст открытых файлов отображаются прямо в интерфейсе VS Code.


Если вам ближе OpenCode, архитектура не меняется. Он также поддерживает OpenAI-совместимых провайдеров. После установки запускаем /connect, выбираем Other, задаём идентификатор omniroute и сохраняем клиентский ключ.
/connect
# Provider: Other
# Provider ID: omniroute
# API key: sk-<omniroute-client-key>
Затем создаём в папке проекта opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"omniroute": {
"npm": "@ai-sdk/openai-compatible",
"name": "My OmniRoute",
"options": {
"baseURL": "https://omni-hk.yakvenalex.ru/v1"
},
"models": {
"cc/claude-sonnet-4-6": {
"name": "Claude Sonnet via OmniRoute"
}
}
}
}
}
Командой /models выбираем omniroute/cc/claude-sonnet-4-6. Чтобы пустить OpenCode через LiteLLM, достаточно заменить baseURL, сохранить виртуальный ключ LiteLLM под тем же provider ID и указать публичный алиас модели.
Важно. Локальный агент получает доступ к файлам и терминалу вашего компьютера. Не включайте безусловное автоматическое подтверждение команд в незнакомых репозиториях, не храните API-ключи в opencode.json и внимательно просматривайте diff перед применением.
В начале статьи у нас был один довольно бытовой вопрос: можно ли перестать перенастраивать VPN и прокси каждый раз, когда очередному AI-инструменту понадобился доступ к модели? Теперь ответ получился не теоретическим — мы собрали рабочую схему и прошли её от пустого VPS до локального AI-агента.
Если коротко, контур разделён на понятные слои:
VPS даёт стабильную зарубежную точку выхода и среду для удалённой разработки;
nginx и Let’s Encrypt дают нормальные домены и HTTPS;
OmniRoute подключает OAuth-авторизацию подписочных сервисов и выдаёт локальный API;
LiteLLM объединяет источники, создаёт клиентские ключи, лимиты и логи;
Codex и Claude Code работают прямо на VPS через Remote SSH;
Qwen Code и OpenCode используют тот же контур с локального компьютера.
Главный плюс здесь даже не в том, что исчезает VPN. Важнее, что доступ к моделям перестаёт быть набором случайных настроек в пяти приложениях. У нас появляется одна точка управления: можно добавить новую модель, выдать отдельный ключ проекту, ограничить бюджет, посмотреть расход или отозвать скомпрометированный доступ, не трогая остальные приложения.
При этом важно не приписывать схеме того, чего она не делает. Подписка не превращается в официальный API-ключ, лимиты провайдера не исчезают, а правила использования продолжают действовать. OmniRoute и LiteLLM дают контроль над маршрутом и доступом, но не отменяют тарифы, квоты и ответственность за учётные данные.
Дальше этот контур можно развивать под себя: добавить резервные модели и fallback, разнести ключи по проектам, подключить мониторинг, настроить регулярные резервные копии или ограничить dashboard отдельной авторизацией. Но базовая система уже готова — и для ежедневной разработки, и для тестовых AI-интеграций.
Надеюсь, теперь вместо очередного набора костылей у вас появится инфраструктура, которую вы понимаете, контролируете и можете спокойно перестраивать под следующую модель или инструмент.
|
Выделенные и виртуальные серверы в Европе, США и России Готовые серверы + предустановленное программное обеспечение, а также индивидуальные конфигурации серверов. Посмотреть [1] |
Автор: yakvenalex
Источник [33]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/34540
URLs in this post:
[1] Посмотреть: https://hostkey.ru/dedicated-servers/
[2] повторения: http://www.braintools.ru/article/4012
[3] https://gateway.example.com: https://gateway.example.com
[4] поведения: http://www.braintools.ru/article/9372
[5] ошибку: http://www.braintools.ru/article/4192
[6] HOSTKEY: https://hostkey.ru/vps/vps-abroad/
[7] памяти: http://www.braintools.ru/article/4140
[8] внимание: http://www.braintools.ru/article/7595
[9] VS Code Remote SSH: https://code.visualstudio.com/docs/remote/ssh
[10] официального репозитория: https://docs.docker.com/engine/install/ubuntu/
[11] нативный установщик Codex CLI: https://learn.chatgpt.com/docs/codex/cli
[12] нативный установщик: https://code.claude.com/docs/en/setup
[13] Claude.ai: http://Claude.ai
[14] Visual Studio Code: https://code.visualstudio.com/
[15] документации OpenAI по авторизации Codex: https://learn.chatgpt.com/docs/auth
[16] документации Codex для IDE: https://learn.chatgpt.com/docs/codex/ide
[17] логика: http://www.braintools.ru/article/7640
[18] поведение: http://www.braintools.ru/article/5593
[19] документации Anthropic: https://code.claude.com/docs/en/ide-integrations
[20] LiteLLM: https://docs.litellm.ai/
[21] REG.RU: http://REG.RU
[22] litellm-hk.yakvenalex.ru: http://litellm-hk.yakvenalex.ru
[23] omni-hk.yakvenalex.ru: http://omni-hk.yakvenalex.ru
[24] https://litellm-hk.yakvenalex.ru/ui/: https://litellm-hk.yakvenalex.ru/ui/
[25] страх: http://www.braintools.ru/article/6134
[26] https://omni-hk.yakvenalex.ru/v1: https://omni-hk.yakvenalex.ru/v1
[27] репозитории OmniRoute: https://github.com/diegosouzapw/OmniRoute
[28] localhost: http://localhost
[29] https://omni-hk.yakvenalex.ru: https://omni-hk.yakvenalex.ru
[30] официальной инструкции Qwen Code: https://qwenlm.github.io/qwen-code-docs/en/users/quickstart/
[31] https://litellm-hk.yakvenalex.ru/v1: https://litellm-hk.yakvenalex.ru/v1
[32] Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=qwenlm.qwen-code-vscode-ide-companion
[33] Источник: https://habr.com/ru/companies/hostkey/articles/1068632/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1068632
Нажмите здесь для печати.