[{"data":1,"prerenderedAt":42},["ShallowReactive",2],{"article:chatgpt-codex-ubuntu-vps":3},{"html":4,"toc":5},"\u003Cp>Чтобы работать с Codex в консоли удалённого сервера, нужно арендовать VPS с Ubuntu, подключиться по SSH, установить Codex CLI и войти в свой аккаунт ChatGPT. После этого можно просить помощника разбирать проект, менять файлы и запускать тесты прямо на сервере.\u003C\u002Fp>\n\u003Cp>Я покажу весь путь на небольшом учебном проекте: подготовим CSV с расходами и поручим Codex написать программу для подсчёта итогов. В конце проверим результат и научимся возвращаться в рабочий сеанс после закрытия терминала.\u003C\u002Fp>\n\u003Cp>Инструкция рассчитана на \u003Cstrong>Ubuntu 24.04 LTS, процессор x86_64 и Codex CLI 0.155.0\u003C\u002Fstrong>. Документация и версия CLI сверены 18 сентября 2026 года. На компьютере подойдут Терминал в macOS или Linux и PowerShell в Windows 10\u002F11. Покупку VPS выполняете вы в своём аккаунте; вид панели и доступность тарифов могут отличаться.\u003C\u002Fp>\n\u003Ch2 id=\"section-1\">Что будет работать на сервере\u003C\u002Fh2>\n\u003Cp>VPS — виртуальный сервер: отдельная Linux-система с собственным адресом и диском. На нём будут храниться проект и история терминальных сеансов. Codex CLI получает ваше задание, обращается к модели OpenAI и выполняет разрешённые действия в рабочем каталоге.\u003C\u002Fp>\n\u003Cp>Саму модель на VPS мы не устанавливаем. Поэтому для этого упражнения не нужна видеокарта. Потребность в памяти и процессоре определяется прежде всего программами, которые вы запускаете: маленький Python-скрипт и сборка большого приложения требуют разных ресурсов.\u003C\u002Fp>\n\u003Cp>Вход через ChatGPT использует доступ и лимиты вашего аккаунта. Это не безлимитный режим: доступные модели и объём работы зависят от плана и настроек рабочего пространства. Перед арендой сервера проверьте, что можете войти в ChatGPT и что Codex доступен вашему аккаунту. API-ключ для этой инструкции не нужен.\u003C\u002Fp>\n\u003Cp>VPS удобен, когда хочется возвращаться к одной рабочей среде с разных компьютеров или оставлять задачу выполняться после отключения SSH. Для знакомства с Codex можно обойтись собственным компьютером, но ниже я разбираю именно удалённый сервер.\u003C\u002Fp>\n\u003Ch2 id=\"section-2\">1. Выбираем VPS и готовим оплату\u003C\u002Fh2>\n\u003Cp>Для первого учебного проекта я бы взял обычный VPS с общими процессорными ресурсами: \u003Cstrong>2 vCPU, 4 ГБ RAM и 40 ГБ SSD\u003C\u002Fstrong>, публичным IPv4 и доступом по SSH. Это конфигурация с запасом для небольших экспериментов, а не официальный минимум Codex. Платная панель управления, GPU и предустановленный веб-сервер здесь не нужны.\u003C\u002Fp>\n\u003Cp>Перед заказом проверьте три вещи:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Провайдер регистрирует клиентов из вашей страны, принимает доступный вам способ оплаты и показывает итоговую сумму с налогами.\u003C\u002Fli>\n\u003Cli>Есть образ Ubuntu 24.04 LTS x86_64, SSH-ключи и консоль восстановления на случай ошибки в настройках доступа.\u003C\u002Fli>\n\u003Cli>Понятна полная стоимость: сервер, IPv4, резервные копии и дополнительные диски. Известно, как удалить ресурсы и остановить начисления.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Также проверьте доступность сервисов OpenAI для своей страны и выбранного региона сервера. Зарубежный IP сам по себе не гарантирует доступность аккаунта.\u003C\u002Fp>\n\u003Cp>В качестве примера панели я использую \u003Cstrong>Hetzner Cloud\u003C\u002Fstrong>. Если регистрация или оплата вам недоступна, выбирайте другого провайдера по тем же параметрам. Команды после получения Ubuntu останутся такими же, но первоначальный пользователь может называться \u003Ccode>ubuntu\u003C\u002Fcode>, а не \u003Ccode>root\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Не оплачивайте год вперёд ради первого эксперимента. Сначала проверьте короткий период использования, доступ к серверу и вход в Codex. У Hetzner выключение виртуальной машины не прекращает оплату: выделенные ресурсы продолжают учитываться до удаления. Снимки, диски и IP тоже проверяйте отдельно.\u003C\u002Fp>\n\u003Ch2 id=\"section-3\">2. Создаём SSH-ключ на своём компьютере\u003C\u002Fh2>\n\u003Cp>SSH — зашифрованное подключение к командной строке сервера. Для входа подготовим пару ключей. Открытую часть загрузим провайдеру, закрытая останется на компьютере.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>На своём компьютере\u003C\u002Fstrong> откройте терминал и проверьте клиент:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh -V\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В Windows, если команда не найдена, установите компонент \u003Cstrong>OpenSSH Client\u003C\u002Fstrong> через дополнительные компоненты Windows и заново откройте PowerShell.\u003C\u002Fp>\n\u003Cp>Создайте ключ:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh-keygen -t ed25519 -C \u003Cspan class=\"hljs-string\">\"codex-vps\"\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Программа спросит путь сохранения. Если ключей ещё нет, примите предложенный путь Enter. Если файл уже существует, \u003Cstrong>не подтверждайте перезапись\u003C\u002Fstrong>: укажите другое имя, например \u003Ccode>id_ed25519_codex\u003C\u002Fcode>, в том же каталоге \u003Ccode>.ssh\u003C\u002Fcode>. Ниже команды предполагают имя \u003Ccode>id_ed25519\u003C\u002Fcode>; для другого имени замените его везде, включая путь после \u003Ccode>-i\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Задайте парольную фразу и повторите её. Вводимые символы не отображаются — это нормально. Парольная фраза защищает закрытый ключ на вашем компьютере.\u003C\u002Fp>\n\u003Cp>Выведите \u003Cstrong>открытый\u003C\u002Fstrong> ключ. В macOS и Linux:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> ~\u002F.ssh\u002Fid_ed25519.pub\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В PowerShell:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-powershell\">Get-Content \"$HOME\\.ssh\\id_ed25519.pub\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Скопируйте всю строку, начинающуюся с \u003Ccode>ssh-ed25519\u003C\u002Fcode>. Файл без окончания \u003Ccode>.pub\u003C\u002Fcode> никуда не загружайте: это закрытый ключ.\u003C\u002Fp>\n\u003Ch2 id=\"section-4\">3. Заказываем сервер с Ubuntu\u003C\u002Fh2>\n\u003Cp>В браузере откройте официальный сайт Hetzner, перейдите в \u003Cstrong>Cloud → Console\u003C\u002Fstrong>, зарегистрируйтесь и завершите проверку аккаунта. Заполните платёжные данные и выберите предложенный в вашем аккаунте способ оплаты. Если сервис запрашивает подтверждение личности, завершите его до заказа.\u003C\u002Fp>\n\u003Cp>В панели создайте проект, например \u003Ccode>codex-lab\u003C\u002Fcode>. Внутри проекта откройте \u003Cstrong>Servers → Add server\u003C\u002Fstrong> и заполните параметры:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Location:\u003C\u002Fstrong> доступный вам регион с подходящими условиями доступа к OpenAI.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Image:\u003C\u002Fstrong> Ubuntu 24.04 LTS, обычный образ ОС.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Type:\u003C\u002Fstrong> x86_64, общие vCPU, не менее выбранных 2 vCPU и 4 ГБ памяти; сверяйте объём диска в карточке.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Networking:\u003C\u002Fstrong> публичный IPv4; IPv6 можно оставить дополнительно.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>SSH keys:\u003C\u002Fstrong> добавьте скопированную строку \u003Ccode>.pub\u003C\u002Fcode> и отметьте этот ключ для нового сервера.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Name:\u003C\u002Fstrong> \u003Ccode>codex-lab\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Дополнительный диск и приложение из каталога для упражнения не нужны. Если подключаете облачный Firewall, разрешите входящий TCP-порт 22 со своего IP. Исходящие соединения должны позволять загрузку пакетов и HTTPS-запросы к OpenAI. Для первого запуска не добавляйте неизвестные вам ограничивающие правила.\u003C\u002Fp>\n\u003Cp>Перед \u003Cstrong>Create &amp; Buy now\u003C\u002Fstrong> сверьте итоговую стоимость и все платные дополнения. Эта кнопка создаёт оплачиваемый ресурс. Дождитесь запуска сервера и скопируйте его публичный IPv4.\u003C\u002Fp>\n\u003Cp>Дальше в командах я использую \u003Ccode>203.0.113.10\u003C\u002Fcode> — это адрес для примера. \u003Cstrong>В каждой команде заменяйте его на адрес своего VPS.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Ch2 id=\"section-5\">4. Подключаемся и создаём рабочего пользователя\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>На своём компьютере\u003C\u002Fstrong> выполните:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh -i ~\u002F.ssh\u002Fid_ed25519 root@203.0.113.10\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В PowerShell при необходимости запишите путь явно:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-powershell\">ssh -i \"$HOME\\.ssh\\id_ed25519\" root@203.0.113.10\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>При первом подключении SSH покажет отпечаток ключа сервера и попросит подтвердить доверие. Сверьте его с данными провайдера или через доверенную веб-консоль сервера. В консоли отпечаток Ed25519 можно получить командой:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh-keygen -lf \u002Fetc\u002Fssh\u002Fssh_host_ed25519_key.pub\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>После совпадения введите \u003Ccode>yes\u003C\u002Fcode> в SSH-клиенте. Если потребуется, введите парольную фразу своего ключа. После входа команды выполняются уже на VPS.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>На сервере, под root\u003C\u002Fstrong>, проверьте ОС и архитектуру:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> \u002Fetc\u002Fos-release\n\u003Cspan class=\"hljs-built_in\">uname\u003C\u002Fspan> -m\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Ожидаем Ubuntu 24.04 и \u003Ccode>x86_64\u003C\u002Fcode>. При другом образе остановитесь и проверьте заказ: дальше команды рассчитаны на Ubuntu.\u003C\u002Fp>\n\u003Cp>Обновите пакеты и установите инструменты:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">apt update\napt upgrade -y\napt install -y ca-certificates curl git tmux python3 nodejs npm ufw bubblewrap\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>git\u003C\u002Fcode> сохранит версии проекта, \u003Ccode>tmux\u003C\u002Fcode> удержит терминальный сеанс после отключения SSH, Python понадобится для учебной программы. Node.js и npm используем для установки CLI. Если обновление просит перезагрузку, выполните \u003Ccode>reboot\u003C\u002Fcode>, дождитесь запуска сервера и подключитесь снова.\u003C\u002Fp>\n\u003Cp>Не будем работать с Codex под root. Создайте пользователя \u003Ccode>dev\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">adduser dev\nusermod -aG \u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> dev\ninstall -d -m 700 -o dev -g dev \u002Fhome\u002Fdev\u002F.ssh\ninstall -m 600 -o dev -g dev \u002Froot\u002F.ssh\u002Fauthorized_keys \u002Fhome\u002Fdev\u002F.ssh\u002Fauthorized_keys\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>adduser\u003C\u002Fcode> попросит новый пароль: он понадобится для \u003Ccode>sudo\u003C\u002Fcode>. Не путайте его с парольной фразой SSH-ключа. Необязательные поля имени и телефона можно пропустить Enter. Копирование \u003Ccode>authorized_keys\u003C\u002Fcode> подходит для нового сервера, созданного с вашим SSH-ключом; если файла нет, сначала выясните, какой способ входа настроил провайдер.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Не закрывая root-сессию\u003C\u002Fstrong>, откройте второе окно терминала на своём компьютере:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh -i ~\u002F.ssh\u002Fid_ed25519 dev@203.0.113.10\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В новом соединении проверьте:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">whoami\u003C\u002Fspan>\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> -v\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Первая команда должна показать \u003Ccode>dev\u003C\u002Fcode>, вторая — принять пароль нового пользователя. Если вход не работает, исправляйте его в оставленной root-сессии.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>На VPS, под dev\u003C\u002Fstrong>, разрешите SSH перед включением межсетевого экрана:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw allow OpenSSH\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw \u003Cspan class=\"hljs-built_in\">enable\u003C\u002Fspan>\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> ufw status\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Подтвердите включение. В выводе должны быть активный firewall и правило \u003Ccode>OpenSSH ALLOW\u003C\u002Fcode>. Мы используем стандартный порт 22; если вы его меняли, правило нужно адаптировать. Снова проверьте подключение из отдельного окна. Только после этого закрывайте исходную root-сессию командой \u003Ccode>exit\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"section-6\">5. Устанавливаем Codex без sudo\u003C\u002Fh2>\n\u003Cp>Все дальнейшие команды выполняйте \u003Cstrong>на VPS под dev\u003C\u002Fstrong>. Проверим зависимости:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">node --version\nnpm --version\npython3 --version\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Для указанной версии npm-пакета Codex требуется Node.js не ниже 16. Пакет Node.js из Ubuntu 24.04 подходит для этой установки. Для будущих версий CLI требования нужно сверять заново.\u003C\u002Fp>\n\u003Cp>Установим зафиксированную версию в личный каталог, чтобы не выдавать npm права администратора:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">mkdir\u003C\u002Fspan> -p \u003Cspan class=\"hljs-string\">\"\u003Cspan class=\"hljs-variable\">$HOME\u003C\u002Fspan>\u002F.local\u002Fbin\"\u003C\u002Fspan>\nnpm install --global --prefix \u003Cspan class=\"hljs-string\">\"\u003Cspan class=\"hljs-variable\">$HOME\u003C\u002Fspan>\u002F.local\"\u003C\u002Fspan> @openai\u002Fcodex@0.155.0\n\u003Cspan class=\"hljs-built_in\">export\u003C\u002Fspan> PATH=\u003Cspan class=\"hljs-string\">\"\u003Cspan class=\"hljs-variable\">$HOME\u003C\u002Fspan>\u002F.local\u002Fbin:\u003Cspan class=\"hljs-variable\">$PATH\u003C\u002Fspan>\"\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Сохраним путь для следующих SSH-сеансов:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">printf\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">'\\nexport PATH=\"$HOME\u002F.local\u002Fbin:$PATH\"\\n'\u003C\u002Fspan> &gt;&gt; \u003Cspan class=\"hljs-string\">\"\u003Cspan class=\"hljs-variable\">$HOME\u003C\u002Fspan>\u002F.bashrc\"\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Эту строку добавляют один раз. Проверьте установку:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">command\u003C\u002Fspan> -v codex\ncodex --version\ncodex login --\u003Cspan class=\"hljs-built_in\">help\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Путь должен вести в \u003Ccode>\u002Fhome\u002Fdev\u002F.local\u002Fbin\u003C\u002Fcode>, версия — \u003Ccode>codex-cli 0.155.0\u003C\u002Fcode>. Номер зафиксирован, чтобы инструкция воспроизводилась; это не обещание, что он всегда останется последним.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Farticles\u002Fchatgpt-codex-ubuntu-vps\u002F01-codex-install.webp\" alt=\"Установленная версия Codex и справка по входу\" loading=\"lazy\" decoding=\"async\" \u002F>\u003C\u002Fp>\n\u003Cp>Проверка установленного CLI в учебной среде Ubuntu 24.04. Справка показывает команды входа; она ещё не подтверждает авторизацию.\u003C\u002Fp>\n\u003Ch2 id=\"section-7\">6. Входим через аккаунт ChatGPT\u003C\u002Fh2>\n\u003Cp>На VPS нет графического браузера, поэтому используем вход по коду устройства. В настройках безопасности своего аккаунта ChatGPT разрешите \u003Cstrong>Device code login\u003C\u002Fstrong>, если эта настройка доступна. В рабочем пространстве разрешением может управлять администратор.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>На VPS\u003C\u002Fstrong> запустите:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">codex login --device-auth\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>CLI покажет адрес страницы входа и временный код. Откройте выданную страницу \u003Cstrong>в браузере своего компьютера\u003C\u002Fstrong>, войдите в нужный аккаунт ChatGPT и введите код. Оставьте команду на сервере работающей до подтверждения. Не отправляйте код в переписку и не используйте код из чужой инструкции.\u003C\u002Fp>\n\u003Cp>Проверьте результат:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">codex login status\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Ожидаемый статус:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-text\">Logged in using ChatGPT\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Farticles\u002Fchatgpt-codex-ubuntu-vps\u002F02-chatgpt-login.webp\" alt=\"Статус входа через ChatGPT\" loading=\"lazy\" decoding=\"async\" \u002F>\u003C\u002Fp>\n\u003Cp>Так выглядит подтверждённый вход через ChatGPT. Одноразовый код и данные аккаунта на скриншот не попадают.\u003C\u002Fp>\n\u003Cp>Если вход по коду устройства недоступен, используйте SSH-туннель. \u003Cstrong>На своём компьютере\u003C\u002Fstrong> откройте новое подключение:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh -i ~\u002F.ssh\u002Fid_ed25519 -L 1455:localhost:1455 dev@203.0.113.10\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Внутри этого соединения на VPS\u003C\u002Fstrong> выполните:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">codex login\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Откройте напечатанный адрес в браузере своего компьютера. Туннель доставит ответ браузера на серверный порт 1455. Не открывайте 1455 в публичном firewall: он нужен только внутри SSH-туннеля. После входа снова проверьте \u003Ccode>codex login status\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Не переносите на сервер историю браузера и cookies. Если CLI сохраняет данные входа в \u003Ccode>~\u002F.codex\u002Fauth.json\u003C\u002Fcode>, относитесь к этому файлу как к паролю: не добавляйте в Git и не показывайте в скриншотах.\u003C\u002Fp>\n\u003Ch2 id=\"section-8\">7. Готовим проект и запускаем рабочий сеанс\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>На VPS под dev\u003C\u002Fstrong> создайте каталог:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">mkdir\u003C\u002Fspan> -p ~\u002Fprojects\u002Fcodex-demo\n\u003Cspan class=\"hljs-built_in\">cd\u003C\u002Fspan> ~\u002Fprojects\u002Fcodex-demo\ntmux new -s codex\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Вы окажетесь внутри нового терминального сеанса. Снаружи почти ничего не изменится, но внизу появится строка состояния tmux. Даже если SSH-соединение пропадёт, сеанс продолжит работать, пока работает сервер.\u003C\u002Fp>\n\u003Cp>Создайте учебные данные. Блок нужно вставлять полностью, включая последнюю строку \u003Ccode>EOF\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> &gt; expenses.csv &lt;&lt;\u003Cspan class=\"hljs-string\">'EOF'\u003C\u002Fspan>\ncategory,amount\nhosting,200\nsoftware,100\nhosting,50\nEOF\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Здесь расходы в условных денежных единицах: 250 на хостинг и 100 на программы. Ожидаемый общий итог — 350. Это вымышленные данные для упражнения.\u003C\u002Fp>\n\u003Cp>Добавьте инструкции проекту:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> &gt; AGENTS.md &lt;&lt;\u003Cspan class=\"hljs-string\">'EOF'\u003C\u002Fspan>\n\u003Cspan class=\"hljs-comment\"># Учебный проект\u003C\u002Fspan>\n\nИспользуй Python 3 и только стандартную библиотеку.\nРаботай только в текущем каталоге. Не используй сеть и \u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan>.\nНе читай файлы за пределами проекта и не обращайся к секретам.\nДенежные суммы считай через decimal.Decimal.\nПосле изменений запусти тесты и покажи результат.\nНе создавай коммиты: я просмотрю изменения сам.\nEOF\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Codex читает \u003Ccode>AGENTS.md\u003C\u002Fcode> как инструкции проекта. Это удобное место для требований к работе, но сам файл не заменяет ограничения доступа. Режим доступа будем задавать явно при запуске CLI.\u003C\u002Fp>\n\u003Cp>Сохраним исходное состояние в Git — локальной истории изменений:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">printf\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">'__pycache__\u002F\\n.venv\u002F\\n'\u003C\u002Fspan> &gt; .gitignore\ngit init -b main\ngit config user.name \u003Cspan class=\"hljs-string\">\"Ваше имя\"\u003C\u002Fspan>\ngit config user.email \u003Cspan class=\"hljs-string\">\"you@example.com\"\u003C\u002Fspan>\ngit add expenses.csv AGENTS.md .gitignore\ngit commit -m \u003Cspan class=\"hljs-string\">\"Initial demo data\"\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В двух строках \u003Ccode>git config\u003C\u002Fcode> укажите своё имя и адрес: они попадут в подпись коммитов. Это настройка только текущего проекта, регистрации на GitHub не требуется.\u003C\u002Fp>\n\u003Ch2 id=\"section-9\">8. Получаем код от Codex и проверяем его\u003C\u002Fh2>\n\u003Cp>Начнём с последовательности, в которой хорошо видны границы действий: Codex подготовит программу по запросу, CLI сохранит ответ в файл, а запускать и проверять программу будем мы сами. Для этой задачи агенту не требуется читать файлы или выполнять команды.\u003C\u002Fp>\n\u003Cp>В каталоге проекта создайте файл с заданием. Вставьте весь блок:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> &gt; task.txt &lt;&lt;\u003Cspan class=\"hljs-string\">'PROMPT'\u003C\u002Fspan>\nОтветь только исходным кодом Python, без Markdown и пояснений. Не\nвызывай инструменты, не читай файлы и не запускай команды: все\nтребования ниже. Скрипт summarize.py запускается как python3\nsummarize.py expenses.csv. CSV содержит category,amount. Используй\nтолько стандартную библиотеку и decimal.Decimal. Группируй суммы по\ncategory, печатай категории по алфавиту в формате hosting: 250.00, затем\nTOTAL: 350.00. Суммы выводи с двумя знаками. Для CSV category,amount с\nтремя строками hosting,200 и software,100 и hosting,50 ожидается\nhosting: 250.00 затем software: 100.00 затем TOTAL: 350.00. Для файла\nтолько с заголовком — TOTAL: 0.00. При неверной, бесконечной или NaN\nсумме, пустой категории, неверных колонках, отсутствии файла или\nаргумента выведи понятную ошибку в stderr и верни ненулевой \u003Cspan class=\"hljs-built_in\">exit\u003C\u002Fspan> code\nбез traceback. Отрицательные конечные суммы разрешены. Программа ничего\nне меняет в файловой системе. Не создавай тесты или коммиты.\nPROMPT\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В запросе заданы формат входных данных, ожидаемый результат и обработка ошибок. \u003Ccode>Decimal\u003C\u002Fcode> нужен для десятичных сумм: так мы избегаем характерных для \u003Ccode>float\u003C\u002Fcode> погрешностей представления. Данные упражнения переданы прямо в запросе, поэтому чтение проекта агентом не требуется.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>В терминале VPS\u003C\u002Fstrong> выполните:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">codex \u003Cspan class=\"hljs-built_in\">exec\u003C\u002Fspan> --sandbox read-only --output-last-message summarize.py - &lt; task.txt\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>exec\u003C\u002Fcode> выполняет один запрос без интерактивного диалога. Знак \u003Ccode>-\u003C\u002Fcode> передаёт текст задания из стандартного ввода; \u003Ccode>&lt; task.txt\u003C\u002Fcode> подставляет содержимое файла. \u003Ccode>--output-last-message\u003C\u002Fcode> сохраняет заключительный ответ Codex в \u003Ccode>summarize.py\u003C\u002Fcode>. Этот файл записывает сам CLI; режим \u003Ccode>read-only\u003C\u002Fcode> ограничивает инструменты агента и не запрещает сохранение явно указанного выходного файла.\u003C\u002Fp>\n\u003Cp>Дождитесь окончания команды. Информация о ходе работы может отображаться в терминале, но в \u003Ccode>summarize.py\u003C\u002Fcode> должен попасть только Python-код. Команда использует уже выполненный вход через ChatGPT; нового API-ключа не нужно. Повторный запуск с тем же именем перезапишет файл — после ручных правок сохраняйте новый ответ под другим именем.\u003C\u002Fp>\n\u003Cp>Сначала \u003Cstrong>прочитайте код\u003C\u002Fstrong>, затем проверьте синтаксис:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> summarize.py\npython3 -m py_compile summarize.py\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Проверьте, что файл содержит Python без Markdown-ограждений, читает только переданный CSV и ничего не удаляет, не отправляет в сеть и не запускает через оболочку. Не запускайте непонятный код с \u003Ccode>sudo\u003C\u002Fcode>. Успешный \u003Ccode>py_compile\u003C\u002Fcode> подтверждает синтаксис, но ещё не правильность подсчёта.\u003C\u002Fp>\n\u003Cp>Теперь запустите программу:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">python3 summarize.py expenses.csv\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Ожидаемый вывод:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-text\">hosting: 250.00\nsoftware: 100.00\nTOTAL: 350.00\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Добавим независимую от сгенерированной реализации проверку: она запускает программу как отдельную команду и сравнивает выход. Скопируйте готовый тест:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cat\u003C\u002Fspan> &gt; test_summarize.py &lt;&lt;\u003Cspan class=\"hljs-string\">'PYTEST'\u003C\u002Fspan>\nimport subprocess\nimport sys\nimport tempfile\nimport unittest\nfrom pathlib import Path\n\nSCRIPT = Path(__file__).with_name(\u003Cspan class=\"hljs-string\">\"summarize.py\"\u003C\u002Fspan>)\n\n\nclass SummaryTests(unittest.TestCase):\n    def run_csv(self, content):\n        with tempfile.TemporaryDirectory() as directory:\n            path = Path(directory) \u002F \u003Cspan class=\"hljs-string\">\"input.csv\"\u003C\u002Fspan>\n            path.write_text(content, encoding=\u003Cspan class=\"hljs-string\">\"utf-8\"\u003C\u002Fspan>)\n            \u003Cspan class=\"hljs-built_in\">return\u003C\u002Fspan> subprocess.run(\n                [sys.executable, str(SCRIPT), str(path)],\n                capture_output=True, text=True, \u003Cspan class=\"hljs-built_in\">timeout\u003C\u002Fspan>=10,\n            )\n\n    def test_normal(self):\n        result = self.run_csv(\n            \u003Cspan class=\"hljs-string\">\"category,amount\\nhosting,200\\nsoftware,100\\nhosting,50\\n\"\u003C\u002Fspan>\n        )\n        self.assertEqual(result.returncode, 0, result.stderr)\n        self.assertEqual(result.stdout,\n                         \u003Cspan class=\"hljs-string\">\"hosting: 250.00\\nsoftware: 100.00\\nTOTAL: 350.00\\n\"\u003C\u002Fspan>)\n\n    def test_decimal(self):\n        result = self.run_csv(\u003Cspan class=\"hljs-string\">\"category,amount\\nhosting,1.10\\nhosting,2.20\\n\"\u003C\u002Fspan>)\n        self.assertEqual(result.returncode, 0, result.stderr)\n        self.assertEqual(result.stdout, \u003Cspan class=\"hljs-string\">\"hosting: 3.30\\nTOTAL: 3.30\\n\"\u003C\u002Fspan>)\n\n    def test_empty(self):\n        result = self.run_csv(\u003Cspan class=\"hljs-string\">\"category,amount\\n\"\u003C\u002Fspan>)\n        self.assertEqual(result.returncode, 0, result.stderr)\n        self.assertEqual(result.stdout, \u003Cspan class=\"hljs-string\">\"TOTAL: 0.00\\n\"\u003C\u002Fspan>)\n\n    def test_invalid(self):\n        \u003Cspan class=\"hljs-keyword\">for\u003C\u002Fspan> amount \u003Cspan class=\"hljs-keyword\">in\u003C\u002Fspan> (\u003Cspan class=\"hljs-string\">\"oops\"\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">\"NaN\"\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">\"Infinity\"\u003C\u002Fspan>):\n            with self.subTest(amount=amount):\n                result = self.run_csv(f\u003Cspan class=\"hljs-string\">\"category,amount\\nhosting,{amount}\\n\"\u003C\u002Fspan>)\n                self.assertNotEqual(result.returncode, 0)\n                self.assertTrue(result.stderr.strip())\n                self.assertNotIn(\u003Cspan class=\"hljs-string\">\"Traceback\"\u003C\u002Fspan>, result.stderr)\n\n\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> __name__ == \u003Cspan class=\"hljs-string\">\"__main__\"\u003C\u002Fspan>:\n    unittest.main()\nPYTEST\npython3 -m unittest -v\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Проверяем обычный CSV, дробные суммы, файл только с заголовком и неправильные суммы, включая \u003Ccode>NaN\u003C\u002Fcode> и бесконечность. В конце должно быть \u003Ccode>OK\u003C\u002Fcode>. Если вывод отличается, не сохраняйте результат как рабочую версию: дополните задание конкретной ошибкой и повторите генерацию в новый файл, например \u003Ccode>summarize-fixed.py\u003C\u002Fcode>. Просмотрите его и только затем замените исходный.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Farticles\u002Fchatgpt-codex-ubuntu-vps\u002F03-demo-tests.webp\" alt=\"Сгенерированная Codex программа и четыре пройденных теста\" loading=\"lazy\" decoding=\"async\" \u002F>\u003C\u002Fp>\n\u003Cp>Реальный запуск учебного примера на Ubuntu 24.04. Codex сгенерировал код; программу и тесты запустили отдельными командами в терминале. У вас реализация может отличаться, но проверяемый результат тот же.\u003C\u002Fp>\n\u003Cp>Теперь посмотрите состояние Git:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">git status --short\ngit diff\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Новые файлы помечаются \u003Ccode>??\u003C\u002Fcode> и \u003Cstrong>не отображаются обычным \u003Ccode>git diff\u003C\u002Fcode>\u003C\u002Fstrong>. Добавьте только ожидаемые файлы в область подготовки коммита и посмотрите их содержимое:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">git add task.txt summarize.py test_summarize.py\ngit diff --cached\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>git add\u003C\u002Fcode> ещё не сохраняет коммит. Он позволяет увидеть новые файлы в \u003Ccode>git diff --cached\u003C\u002Fcode>. Если в каталоге появились другие файлы, сначала разберитесь, зачем они нужны. Когда код просмотрен, а проверки пройдены:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">git commit -m \u003Cspan class=\"hljs-string\">\"Add expense summary and tests\"\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Локальный Git помогает вернуться к проверенной версии, но не заменяет резервную копию. Для настоящего проекта отдельно настройте сохранение кода за пределами VPS.\u003C\u002Fp>\n\u003Ch3>Как перейти к диалогу и изменениям файлов\u003C\u002Fh3>\n\u003Cp>Для разговора с Codex откройте интерактивный режим:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">codex --sandbox read-only --ask-for-approval on-request\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Например, попросите: «Объясни разницу между CSV и JSON на коротком примере. Не используй инструменты». Это обычный диалог в терминале. Для выхода в оболочку используйте \u003Ccode>\u002Fquit\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Codex также умеет сам читать проект, менять файлы и запускать проверки. Для этого в каталоге проекта запускают:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">codex --sandbox workspace-write --ask-for-approval on-request\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Если CLI запросит доверие каталогу, проверьте путь. \u003Ccode>workspace-write\u003C\u002Fcode> разрешает изменения в рабочем каталоге; \u003Ccode>on-request\u003C\u002Fcode> означает запрос подтверждения там, где он требуется, а не перед каждой записью файла.\u003C\u002Fp>\n\u003Cp>Пример следующего задания: «Добавь в summarize.py аргумент --category для фильтра по категории. Сначала объясни план, затем внеси изменение и добавь тест. Сохрани прежнее поведение без аргумента. Не используй сеть и sudo, не создавай коммиты».\u003C\u002Fp>\n\u003Cp>Этот режим требует работоспособной Linux-песочницы. В ограниченном контейнере она может не запуститься даже при правильной установке Codex. Если возникает ошибка \u003Ccode>bwrap\u003C\u002Fcode>, не отключайте защиту ради упражнения: используйте уже показанную генерацию кода без инструментов и запускайте проверки самостоятельно. Самостоятельные действия агента — отдельный шаг после проверки совместимости среды.\u003C\u002Fp>\n\u003Ch2 id=\"section-10\">9. Отключаемся и возвращаемся к работе\u003C\u002Fh2>\n\u003Cp>Чтобы оставить tmux-сеанс работающим, нажмите \u003Cstrong>Ctrl+B\u003C\u002Fstrong>, отпустите клавиши, затем нажмите \u003Cstrong>D\u003C\u002Fstrong>. Это последовательность, а не три клавиши одновременно.\u003C\u002Fp>\n\u003Cp>Вы вернётесь во внешнюю оболочку SSH. Теперь можно завершить соединение:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">exit\u003C\u002Fspan>\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Позже \u003Cstrong>на своём компьютере\u003C\u002Fstrong> снова подключитесь:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">ssh -i ~\u002F.ssh\u002Fid_ed25519 dev@203.0.113.10\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>На VPS\u003C\u002Fstrong> проверьте сеансы и войдите в нужный:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">tmux \u003Cspan class=\"hljs-built_in\">ls\u003C\u002Fspan>\ntmux attach -t codex\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Farticles\u002Fchatgpt-codex-ubuntu-vps\u002F04-tmux.webp\" alt=\"Сеанс tmux доступен после отсоединения\" loading=\"lazy\" decoding=\"async\" \u002F>\u003C\u002Fp>\n\u003Cp>На скриншоте проверка выполнена в отдельном тестовом сокете tmux (\u003Ccode>-L article-demo\u003C\u002Fcode>), чтобы не затрагивать другие сеансы. В своих командах этот параметр добавлять не нужно. Имя \u003Ccode>codex\u003C\u002Fcode> — метка терминального сеанса. tmux сохраняет запущенные процессы при отключении SSH, но не переживает перезагрузку VPS.\u003C\u002Fp>\n\u003Cp>Если сервер перезагрузился, создайте tmux-сеанс заново, перейдите в проект и откройте предыдущий разговор Codex:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">cd\u003C\u002Fspan> ~\u002Fprojects\u002Fcodex-demo\ntmux new -s codex\ncodex resume\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Выберите нужный разговор в списке. История Codex и живой процесс tmux — разные вещи: восстановление разговора не возвращает оборванную команду в память. Проверьте \u003Ccode>git status\u003C\u002Fcode> и состояние файлов перед продолжением.\u003C\u002Fp>\n\u003Ch2 id=\"section-11\">Что делать при ошибке\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>SSH отвечает \u003Ccode>Permission denied (publickey)\u003C\u002Fcode>.\u003C\u002Fstrong> Проверьте пользователя (\u003Ccode>root\u003C\u002Fcode> при первом входе или \u003Ccode>dev\u003C\u002Fcode> после настройки), адрес и файл после \u003Ccode>-i\u003C\u002Fcode>. Ключ должен быть выбран при создании сервера. Добавление ключа в панель после покупки не означает, что он автоматически появился внутри уже созданной Ubuntu. Для \u003Ccode>dev\u003C\u002Fcode> проверьте \u003Ccode>authorized_keys\u003C\u002Fcode> из оставленной root-сессии.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>SSH долго ждёт и завершается с timeout.\u003C\u002Fstrong> Проверьте, запущен ли VPS, выбран ли публичный IPv4 и открыт ли TCP 22 в облачном firewall. Если ошиблись в UFW, используйте консоль восстановления провайдера. Не удаляйте правила наугад через единственное оставшееся соединение.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>После повторного входа \u003Ccode>codex: command not found\u003C\u002Fcode>.\u003C\u002Fstrong> Проверьте наличие файла \u003Ccode>~\u002F.local\u002Fbin\u002Fcodex\u003C\u002Fcode> и строку PATH в \u003Ccode>~\u002F.bashrc\u003C\u002Fcode>. Для текущего сеанса выполните:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">\u003Cspan class=\"hljs-built_in\">export\u003C\u002Fspan> PATH=\u003Cspan class=\"hljs-string\">\"\u003Cspan class=\"hljs-variable\">$HOME\u003C\u002Fspan>\u002F.local\u002Fbin:\u003Cspan class=\"hljs-variable\">$PATH\u003C\u002Fspan>\"\u003C\u002Fspan>\ncodex --version\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Вход по коду устройства не разрешён.\u003C\u002Fstrong> Проверьте настройку Device code login и права рабочего пространства. Если она недоступна, используйте описанный SSH-туннель. При \u003Ccode>Address already in use\u003C\u002Fcode> порт 1455 уже занят: закройте старый туннель или приложение, которое его использует, и повторите подключение.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Codex сообщает о лимите аккаунта.\u003C\u002Fstrong> Проверьте план, доступные модели и время восстановления лимита в своём аккаунте. Более мощный VPS лимит ChatGPT не увеличит. Для продолжения не требуется переходить на API, если вы хотите работать через аккаунт ChatGPT.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Команда заблокирована песочницей.\u003C\u002Fstrong> Прочитайте причину и проверьте, требуется ли действие задаче. Для учебного CSV достаточно файлов проекта и Python. Не устраняйте любую ошибку запуском под root или отключением всех ограничений. Если сам механизм изоляции не запускается, сохраните текст ошибки и проверьте совместимость окружения с Codex.\u003C\u002Fp>\n\u003Ch2 id=\"section-12\">Как пользоваться этой средой дальше\u003C\u002Fh2>\n\u003Cp>Начинайте новую задачу с отдельного каталога и сохранённого состояния Git. В запросе указывайте конкретный результат, ограничения и способ проверки: например, «найди причину ошибки, добавь тест, исправь, покажи изменённые файлы». Не начинайте с просьбы «настрой весь сервер»: сначала освоите контроль одной небольшой задачи.\u003C\u002Fp>\n\u003Cp>Для обычного возвращения к работе достаточно SSH, \u003Ccode>tmux attach -t codex\u003C\u002Fcode> и текущего проекта. В интерактивном режиме команда \u003Ccode>\u002Fstatus\u003C\u002Fcode> показывает состояние сеанса; \u003Ccode>codex resume\u003C\u002Fcode> помогает выбрать сохранённый разговор. Обновлять CLI лучше между задачами, сохранив рабочую версию кода:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\" aria-label=\"Блок кода: sh\">\u003Ccode class=\"hljs language-sh\">npm install --global --prefix \u003Cspan class=\"hljs-string\">\"\u003Cspan class=\"hljs-variable\">$HOME\u003C\u002Fspan>\u002F.local\"\u003C\u002Fspan> @openai\u002Fcodex@latest\ncodex --version\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Это установит версию, актуальную на момент запуска; её поведение может отличаться от показанного. Если закончили пользоваться сервером, сохраните нужные файлы вне VPS, выполните \u003Ccode>codex logout\u003C\u002Fcode> и удалите ненужные ресурсы в панели провайдера, проверив оставшиеся начисления.\u003C\u002Fp>\n",[6,9,12,15,18,21,24,27,30,33,36,39],{"id":7,"title":8},"section-1","Что будет работать на сервере",{"id":10,"title":11},"section-2","1. Выбираем VPS и готовим оплату",{"id":13,"title":14},"section-3","2. Создаём SSH-ключ на своём компьютере",{"id":16,"title":17},"section-4","3. Заказываем сервер с Ubuntu",{"id":19,"title":20},"section-5","4. Подключаемся и создаём рабочего пользователя",{"id":22,"title":23},"section-6","5. Устанавливаем Codex без sudo",{"id":25,"title":26},"section-7","6. Входим через аккаунт ChatGPT",{"id":28,"title":29},"section-8","7. Готовим проект и запускаем рабочий сеанс",{"id":31,"title":32},"section-9","8. Получаем код от Codex и проверяем его",{"id":34,"title":35},"section-10","9. Отключаемся и возвращаемся к работе",{"id":37,"title":38},"section-11","Что делать при ошибке",{"id":40,"title":41},"section-12","Как пользоваться этой средой дальше",1790082845806]