Коротко: получилось! Из одного промпта агент создал репозиторий, написал приложение и тесты, добился зелёного CI, поднял Postgres и задеплоил готовое приложение за HTTPS — без единого дополнительного сообщения от автора. Если хочется сразу увидеть результат, демо-видео есть в конце статьи.

LLM снова стали интересными. Может, они всегда были такими, а всё дело в личном разочаровании, которое со временем прошло. Теперь, когда нужен небольшой инструмент, его просто создают на месте.

Как-то раз в спортзале захотелось трекер тренировок с весами. Приложение по задумке было максимально CRUD-простым, но все варианты в сторах просили £12 в месяц, поэтому его быстро собрали с помощью Claude одним промптом. Получилось весело, но давать LLM root-доступ к своей машине в автоматическом режиме всё ещё некомфортно.

Отсюда и возникла задача: как построить полностью удалённую агентную среду разработки, где LLM структурно ограничена, а не просто работает на доверии? Идея — дать модели инструкцию и позволить ей автономно пройти весь SDLC:

  • Исследовать подходящий стек и пакеты.
  • Спланировать и написать код и тесты.
  • Закоммитить в Git, собрать и запустить CI-пайплайн.
  • Задеплоить результат на «продакшн»-сервер с базами данных, наблюдаемостью (o11y) и доменом с SSL.

И всё это — на домашнем сервере, без счетов за облачную инфраструктуру. Единственные расходы, связанные конкретно с этим экспериментом, — подписка на Codex за £20.

Сервер(-а)

Серверы

Вот они во всей красе.

Нижний — двухъядерный i3 2014 года, уже пять лет работающий как домашняя лаборатория. Он героически хостит этот блог и ещё около 45 Docker-контейнеров — от Pi-hole до полного стека Prometheus / Loki / Grafana. У него же проброшен 443 порт с роутера. Если бы LLM его сломала, это было бы обидно, поэтому для эксперимента используется не он.

Верхний сервер — i7 10-го поколения 2021 года с 32 ГБ ОЗУ, куплен на eBay совершенно пустым. Идеальный кандидат.

Стек

Основной стек разработки полностью self-hosted и работает через Coolify. Наружу выходят только инференс и интеграции вроде Tailscale, Telegram, DNS и ACME. Инференс тоже можно было бы держать локально, но подходящего железа нет, а субсидировать эксперименты за счёт OpenAI — вариант удобнее.

КомпонентЗаметки
Pi-holeЛокальные DNS-правила, заодно меньше рекламного мусора.
TailscaleДомашняя сеть «следует» за пользователем.
CoolifySelf-hosted PaaS в стиле Heroku на базе Docker.
Forgejo (с раннерами)Self-hosted Git и CI.
Hermes (с веб-интерфейсом)Виртуальный ассистент в стиле OpenClaw, использующий Codex для инференса.
TelegramОбщение с агентом хоть из туалета, хоть откуда угодно.
Firecrawl (self-hosted)Слой скрапинга и трансляции данных между агентом и вебом.
Porkbun (регистратор) и Let's EncryptДомен и SSL-сертификаты на лету.
Всё остальноеPostgres, Redis — что угодно, что нужно приложениям. Под капотом всё равно просто Docker.

Источники

Это не полноценное пошаговое руководство. Можно было бы написать Ansible-скрипт для настройки всего с нуля — если такой нужен, стоит оставить issue в репозитории на GitHub ниже. Впрочем, если статья дочитана до этого места, разобраться будет несложно.

ИсточникЗаметки
Coolify Setup BlogГайд по установке Coolify на Hetzner.
Coolify DockerfilesProduction Dockerfile'ы, которые реально работают на Coolify. Достаточно добавить env-переменные.
Forgejo Hermes SkillНавык для Hermes под Forgejo CLI; нужен только ключ.

Сетевая настройка

Первый защитный барьер очевиден: сервер физически отдельный. Даже если Hermes выполнит rm -rf /, в худшем случае это будет стоить пары часов на восстановление.

Следующий уровень защиты — сеть. У старого сервера проброшен 443 порт с роутера, у нового — нет. Внешнего входящего трафика нет вовсе, что убирает огромную поверхность атаки и весь фоновый интернет-шум от ботов, перебирающих /wp-admin на каждой созданной DNS A-записи.

Но если входящих соединений нет, как тогда:

  • Получить доступ ко всем новым приложениям с телефона?
  • Сгенерировать SSL-сертификат для красивого домена вроде https://cool-new-app.internal.jakeshomelab.me?

Для этого настроен Tailscale со старым сервером в роли exit node. Когда пользователь не дома, выбор этого exit node маршрутизирует трафик через старый сервер и Pi-hole, который используется для кастомного DNS. В Pi-hole можно добавлять dnsmasq-правила вроде:

address=/internal.jakeshomelab.me/192.168.1.201

Теперь любой запрос к *.internal.jakeshomelab.me резолвится на новый сервер, где обратный прокси Coolify подхватывает его и отдаёт новенькие сервисы.

SSL-сертификаты

С Caddy или Traefik и Docker-лейблами можно раздавать порт 3000 контейнера X по адресу https://my-service.internal.jakeshomelab.me. Указываете A-запись на сервер — и он свяжется с Let's Encrypt, пройдёт ACME-челлендж и получит SSL-сертификат. Это было изучено ещё три года назад и до сих пор выглядит как магия.

Проблема в самой A-записи. Публично привязывать my-service.internal.jakeshomelab.me к своему IP не хочется, независимо от того, доступен ли сервис извне. Нужен SSL-сертификат для сервиса-призрака.

Решение — DNS-01. Честно говоря, метод новый, но работает так:

  • Покупается домен (в данном случае у Porkbun).
  • Генерируются API-ключи Porkbun и добавляются в окружение Coolify с правом записи в домен.
  • Docker Compose файл Coolify модифицируется для использования lego и Porkbun API:
      - '--certificatesresolvers.letsencrypt.acme.dnschallenge=true'
      - '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=porkbun'
      - '--log.level=INFO'

Дальше при регистрации нового URL Traefik / Coolify:

  • Использует API Porkbun для создания TXT-записи по адресу _acme-challenge.my-service.internal.jakeshomelab.me.
  • Let's Encrypt проверяет челлендж и выдаёт валидный SSL-сертификат.
  • Traefik удаляет запись.

Готово — рабочий HTTPS-URL, доступный внутри tailnet, без публичной A- или AAAA-записи, указывающей на сервис. Имя хоста всё же может попасть в публичные логи прозрачности сертификатов, но сам сервис доступен только из tailnet.

Самое приятное — Coolify делает всё это на лету. Агент может создать сервис на любом сабдомене, и всё ✨магически✨ настроится само.

Если собрать всё вместе, получается следующая схема:

Схема сети

Та же схема покрывает и инструменты: Coolify, Hermes, Forgejo и Firecrawl живут на своих локальных сабдоменах.

Стек разработки и MCP

Когда изолированная (более-менее) машина готова, дело за инструментами. Сами по себе они хорошо известны — самое интересное в том, как их соединить.

Forgejo

Нужно надёжное место для хранения кода и запуска CI. От GitHub решено было отказаться по нескольким причинам:

  • Передача токена GitHub машине во многом подрывает саму идею изоляции. К тому же это не self-hosted решение.
  • Лимиты API и минут CI не годятся для масштаба такой «фабрики ПО».
  • В последнее время GitHub и так часто лежит.

Forgejo стал отличной self-hosted альтернативой. Docker Compose файл, упомянутый выше, поднимает Forgejo и раннеры; регистрация себя и раннера требует немного дополнительной работы, но хорошо задокументирована.

Также добавлен Compose файл для синхронизации проектов обратно в GitHub. Это подразумевает передачу токена GitHub в окружение — компромисс на усмотрение каждого.

Упомянутый навык Forgejo для Hermes даёт агенту полный контроль над инстансом.

Hermes

Hermes — персональный ассистент в стиле OpenClaw с агентными возможностями. Хайп вокруг OpenClaw прошёл мимо, поэтому сравнить их напрямую сложно, но у Hermes нашлось несколько полезных особенностей:

  • Веб-интерфейс: стандартный ChatGPT-подобный интерфейс для работы с ноутбука и управления навыками.
  • Общая файловая система: рабочее пространство Hermes примонтировано с Docker-хоста и расшарено по Samba. Агент и пользователь работают с одними и теми же файлами вместо копирования кода и Markdown туда-сюда.
  • Интеграция с Telegram: можно писать агенту с телефона. Настройка заняла две минуты и не потребовала логина — это хорошо вписалось в песочничную модель.
  • Самостоятельное создание навыков: Hermes умеет создавать и регистрировать собственные навыки. Готового навыка под Coolify не нашлось — агент прочитал документацию, изучил MCP и написал его сам.
  • Firecrawl: self-hosted Firecrawl даёт агенту гораздо более удобный доступ к данным поисковой выдачи и скрапингу веба в масштабе.

Настройка Hermes и Firecrawl с правильными ключами в нужных местах — та ещё морока. Дружественные к Coolify Docker Compose файлы добавлены в репозиторий, упомянутый выше.

Hermes в процессе сборки демо веб-приложения для этого поста

Coolify

Coolify — клей, который держит всю систему вместе: self-hosted PaaS на базе Docker и Compose, стремительно развивающийся с каждым обновлением. Тем, кто хочет удобства Heroku или DigitalOcean App Platform на собственном железе, он однозначно стоит внимания.

Несколько любимых особенностей:

  • Под капотом просто Docker. Существующие деплойменты в основном продолжают работать, а если Coolify не умеет чего-то нестандартного, всегда можно выполнить docker exec <что угодно> с ноутбука. Абстракции присутствуют только тогда, когда они нужны.
  • Стек SSL / роутинга, подробно описанный выше.
  • Coolify поставляется с набором готовых рецептов для самых распространённых приложений. Postgres, Redis, Hermes, Forgejo и почти всё остальное разворачивается в один клик.
  • Бэкапы Postgres в S3 настраиваются за три клика, управление env-переменными и пользователями встроено.
  • Вебхуки GitHub дают автоматический деплой при пуше в main.

Пара скриншотов настроенного Coolify в действии:

Экран инструментов в Coolify Сервис Firecrawl и Docker Compose

Что получилось на практике

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

Please build me an app for tracking my calorie intake. It should be similar to MyFitnessPal but with a form to
add specific food and meals for quick selection later.

Your task is to build it, commit it to a new repo with tests, test it with CI, and deploy it to
http://calories.internal.jakeshomelab.me.

I'd like it to be a full stack svelte kit app with Drizzle and Postgres for the database layer.
I'd like tailwind for the CSS. It should be mobile first.

For deployment, please use docker and docker compose and deploy your own Postgres instance.

Дальше агент просто взял и сделал всё сам:

  • Создал новый Git-репозиторий и развернул SvelteKit, Drizzle, Postgres и Tailwind.
  • Написал приложение и тесты, коммитя работу разумными этапами.
  • Настроил CI-пайплайн.
  • Разбирался с падающими тестами, пока CI не стал зелёным.
  • Контейнеризировал приложение и собственный инстанс Postgres через Docker Compose.
  • Задеплоил всё на Coolify по отдельному URL.

И всё это — без единого дополнительного промпта. Не пришлось подталкивать агента через упавшие тесты или копировать ошибки обратно в чат. Он просто продолжал работу, пока приложение не заработало.

После этого приложение опробовали в деле и наткнулись на проблему с CSRF при отправке данных. Хватило ещё одного промпта: агент диагностировал проблему, исправил её, добавил регрессионные тесты и передеплоил приложение.

И всё заработало!

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

Хватит слов, покажите результат!

Демо-видео, без претензий на профессиональный монтаж:

Мысли об изоляции и дальнейших шагах

Между полностью агентной разработкой и безопасностью всегда есть компромисс. Этот пример достаточно искусственный: приложение работает полностью изолированно. Большинство полезного софта общается с другими сервисами, а значит требует передачи API-ключей, и каждый ключ — ещё одна маленькая дырка в песочнице.

Даже в такой конфигурации Hermes всё ещё способен:

  • Уничтожить новый сервер и всё, что на нём запущено.
  • Удалить репозитории, базы данных и деплойменты.
  • Слить или злоупотребить любыми выданными ему учётными данными.
  • Сжечь токены инференса так, будто от этого зависит годовая премия.
  • Отправлять произвольные исходящие запросы и скачивать любой мусор из интернета.
  • Дотянуться до чего угодно ещё в сети, куда пропускает файрвол.

Так что нет, безобидным это не назвать. Что действительно удалось — сделать саму машину расходным материалом и резко сузить круг того, до чего агент может дотянуться и что реально важно. Худший сценарий теперь звучит как «пересобрать коробку с eBay и сменить пару ключей», а не «обнаружить, что LLM с энтузиазмом реорганизовала настоящий рабочий ноутбук». Это лучше, но не волшебная таблетка.

Очевидные следующие шаги:

  • Вынести машину в отдельный VLAN и явно заблокировать доступ к остальной домашней сети.
  • Максимально сузить права каждого учётного данных, насколько позволяет провайдер, и регулярно их ротировать.
  • Автоматизировать бэкапы и сделать пересборку всей машины задачей в один клик.
    • Бэкапы БД в Coolify и общие Docker Compose точки монтирования должны сильно упростить эту задачу.
  • Требовать подтверждения перед любыми по-настоящему публичными или труднообратимыми действиями.

Впрочем, в какой-то момент избыток контрольных точек превращает магическую автономную фабрику ПО обратно в набор форм, которые нужно заполнять вручную. Поиск баланса между «требует внимания каждые пять минут» и «получил коды запуска» — задача для следующего эксперимента.