← Углубления  ·  Университет  ·  📗 Словарь чайника

DD — Азбука: терминал, git, docker, ssh, JSON, .env, порты, как читать ошибку

Микро-модуль 0.5 — операционный ликбез перед стройкой. Не теория курса, а инструменты в руках: без них ни один «живой якорь» курса не откроется, потому что каждый якорь начинается со слов «зайди на сервер и посмотри...».

Медицинская рамка: прежде чем говорить о консилиумах и иммунитете (модули 2 и 4), студент-медик должен уметь держать скальпель, читать анализы и мыть руки. Это тот самый уровень. Азбука — не про то, «как устроен организм», а про то, как физически войти в палату, открыть карту пациента и не перепутать шприцы.


0. Зачем это вообще нужно

У тебя уже есть завод: 16+ контейнеров на Hetzner VPS (), Caddy на входе, git-репозитории для каждого сервиса. Всё это построено вместе с ИИ — но чтобы проверять живое, не код (твой закон №4), нужны голые руки на терминале, а не только просьба к ассистенту. Пока эти восемь навыков не в мышечной памяти, у тебя фактически есть только один канал управления заводом — диалог с ИИ, и если он вдруг ошибается или недоступен, ты не можешь сам заглянуть под капот и проверить его слова. Это ровно та зависимость, которую этот модуль закрывает: не «замени ИИ», а «получи собственные глаза и руки рядом с ним».

Каждый из восьми пунктов ниже привязан к твоему заводу и заканчивается «живым якорем» — конкретной командой, которую можно набрать прямо сейчас, без ожидания следующего урока. Важная оговорка сразу: это НЕ курс программирования — писать код с нуля тебе для целей этой системы не нужно (этим занимается ИИ). Нужно ровно то, что нужно врачу-администратору клиники: уметь ЗАЙТИ в нужный кабинет, ПРОЧИТАТЬ карту и ПОНЯТЬ, что в ней написано, — не самому оперировать.


1. Терминал — окно прямого разговора с компьютером

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

Как называется по-настоящему (English): terminal / command line / shell. На Windows — PowerShell или cmd, на Mac/Linux — bash или zsh. Когда ты просишь Claude Code что-то сделать, он у тебя за спиной именно печатает такие команды.

Минимум, чтобы не потеряться: - pwd — «где я сейчас» (print working directory). - ls (Mac/Linux) или dir (Windows) — «что лежит в этой папке»; ls -la — показать и скрытые файлы (у .env имя начинается с точки не случайно — по умолчанию он спрятан от обычного списка). - cd имя_папки — «зайти в папку», cd .. — «выйти на уровень выше», cd ~ — «вернуться домой». - cat имя_файла (Mac/Linux) или type имя_файла (Windows) — «показать содержимое файла целиком прямо в терминале», не открывая редактор. - mkdir имя — создать папку. rm файл / rm -rf папка — удалить; это как ампутация без наркоза — нет корзины, нет отмены, дважды проверяй путь перед Enter. - Клавиша Tab — автодополнение имени файла/папки на середине ввода: печатаешь первые буквы, жмёшь Tab — экономит опечатки. - Стрелка вверх — повторить прошлую команду (не перепечатывать); история команд — твой личный «анамнез» действий за сессию. - Ctrl+C — «прервать», если команда зависла или ты передумал.

Для любопытных: терминал — это просто текстовый интерфейс к shell (командному интерпретатору: bash/zsh на Linux/Mac, PowerShell на Windows), который сам вызывает программы. Когда твой скилл .autodeploy.ps1 выполняется Stop-хуком, это буквально та же самая PowerShell-оболочка, только запущенная без тебя, в фоне, по тому же принципу «команда → ответ», который ты только что освоил руками.

Текстовый редактор прямо в терминале — пригодится на сервере. Через ssh у тебя чаще всего НЕТ VS Code, только терминал, поэтому для быстрой правки .env или .json на VPS нужен встроенный редактор: nano файл — самый дружелюбный (подсказки горячих клавиш прямо внизу экрана, Ctrl+O сохранить, Ctrl+X выйти); vim файл — мощнее, но требует привычки (главное, что нужно новичку: нажать i, чтобы начать печатать, Esc, затем :wq и Enter, чтобы сохранить и выйти — иначе легко застрять). Для разовых правок на сервере nano вполне достаточно.

Живой якорь: открой терминал на своём ПК и набери ssh root@ — уже наберёшь пароль/ключ и окажешься «внутри» сервера завода (подробнее в §4).


2. Git — журнал изменений, который не врёт

По-человечески: представь историю болезни пациента — каждая запись врача датирована, подписана, и её нельзя незаметно стереть, можно только дописать новую. Git — то же самое для кода: каждое изменение — отдельная «запись в карте» (commit), с автором, датой и объяснением, что изменилось.

Как называется по-настоящему (English): git — система контроля версий (version control), программа, которая работает на твоём компьютере. GitHub — отдельный, самый популярный САЙТ-хранилище для таких карт (роль «общего архива больницы»); git и GitHub — не одно и то же, первое — инструмент, второе — один из возможных удалённых складов для его результатов. Репозиторий (repo) — папка с полной историей проекта; origin — стандартное имя для «того самого удалённого склада», откуда ты pull-ишь и куда push-ишь. У тебя таких репозиториев 26+ (твой git-map).

Пять команд, которые реально нужны: - git clone <адрес> — «скопировать чужую/удалённую карту болезни себе» — забрать репозиторий целиком в первый раз. - git pull — «подтянуть свежие записи» — забрать изменения, которые появились на сервере/у другого человека (или у ИИ, работавшего без тебя). - git status — «что изменилось с последней записи, но ещё не зафиксировано» — самая частая команда, спроси её первой, если сомневаешься. - git diff — «показать построчно, что именно поменялось» — как сравнение двух анализов бок о бок. - git commit -m "текст" + git push — «зафиксировать запись в карте и отправить её на общий сервер».

Как это у тебя устроено: Stop-хук (auto-commit-push-deploy-hook) в конце сессии Claude Code сам делает commit + push за тебя для тронутых репозиториев — это то же самое действие, просто автоматизированное. Понимание команд нужно, чтобы проверить, что хук сделал, а не гадать.

Ещё две вещи, которые пригодятся раньше, чем кажется: - .gitignore — файл-«список того, что НЕ записывать в карту болезни»: секреты (.env), временные файлы, папки с гигабайтами сгенерированных видео. Если чего-то важного нет в git status, но оно должно быть — проверь, не попало ли оно туда случайно. - Конфликт слияния (merge conflict) — когда два человека (или ты и ИИ параллельно) поправили одну и ту же строку по-разному, git сам не решает, кто прав, а показывает оба варианта прямо в файле между маркерами <<<<<<< и >>>>>>> — это не поломка, а запрос на твоё врачебное решение, какую версию оставить.

Для любопытных: branch — отдельная параллельная «черновая карта», где можно пробовать рискованное лечение, не трогая основную (main); merge — слияние черновика обратно в основную запись, когда способ подтвердился. Именно так планируется изолировать варианты в веере MVP консультант-фабрики (Урок 9.3) — каждый explorer-агент работает в своей ветке/worktree, не наступая на соседа. В модуле 3.3 курса это же станет полноценной аналогией «git-памяти агента» (main.md / commit.md / log.md).

Живой якорь: cd в любую папку сервиса на ПК (например, D:\PROJECTS\channel-hq) → git log --oneline -5 — увидишь последние 5 «записей в карте болезни» этого сервиса.

🔧 Пять команд git — нажми на шаг цепочки
git status1 git diff2 git commit -m3 git push4
Нажми на любой шаг цепочки — узнаешь, что он делает и зачем.

3. Docker и контейнер — герметичная палата, а не общая казарма

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

Как называется по-настоящему (English): Docker — платформа контейнеризации; container — запущенный экземпляр; image — «рецепт», по которому контейнер собирается; docker-compose — «список назначений на несколько палат сразу», который описывает, как несколько контейнеров работают вместе (у тебя — один docker-compose.yml на сервис). Volume — отдельная, ВНЕШНЯЯ по отношению к контейнеру полка для хранения файлов: если контейнер пересоздать (новый образ, свежий деплой) — сам контейнер «одноразовый» и стирается вместе со всем, что внутри, а вот подключённый volume переживает пересоздание. Это ровно причина, по которой твои генераторы (omni/photo) хранят проекты не «где попало» в контейнере, а в закреплённом volume /app/projects — твоя же запись в базе ошибок про то, что /app/backend/projects пуст и никогда не был локацией, это как раз путаница «временная папка контейнера» vs «постоянный volume».

Три команды, которые ты будешь набирать чаще всего (твой закон №4 — «проверяй живое»): - docker ps — «кто сейчас дышит» — список работающих контейнеров, их имена, порты, сколько времени живут. - docker logs <имя_контейнера> — «журнал наблюдений за пациентом за последнее время» — вывести, что контейнер печатал (тут чаще всего видно причину поломки). - docker exec -it <имя_контейнера> bash — «зайти прямо в палату» — открыть терминал ВНУТРИ контейнера, посмотреть его файлы или переменные (printenv) изнутри, не веря докладам снаружи.

# твой пример из 06-errors-and-gotchas.md — "код умеет X, но фича выключена":
docker exec videopipeline-backend-1 printenv | grep FEATURE_FLAG

Как выглядит «рецепт» (упрощённый docker-compose.yml одного из твоих сервисов):

services:
  channel-hq:
    build: .
    ports:
      - "127.0.0.1:8030:8030"   # снаружи видно только с самого сервера
    env_file: .env               # сюда подтягиваются секреты из §6
    networks:
      - factory                  # общая сеть, чтобы видеть memory-bank по имени
networks:
  factory:
    external: true

Три вещи, на которые смотреть в первую очередь при разборе чужого/нового сервиса: ports (какая дверь и кому видна — сверься с §7), env_file (откуда секреты — §6), networks (с кем сервис может «разговаривать» напрямую по имени).

Ещё несколько команд, которые встречаются в твоих же граблях (06-errors-and-gotchas.md): - docker restart <имя> — «перезапустить палату» — самый грубый инструмент, применять с оглядкой: твоя же грабля гласит «не рестартить shared-контейнер (governor, генераторы) — бьёт по параллельным сессиям», рестарт годится только когда контейнер реально idle. - docker compose up -d --build — «пересобрать и поднять по свежему рецепту» — то, что делает твой типовой деплой-цикл после git pull в папке сервиса на сервере. - docker inspect <имя> — «полная карта пациента»: какой образ, какие порты, какая политика авто-рестарта, к каким сетям подключён — полезно, когда docker ps даёт слишком мало. - docker cp file <c>:/app/file — «подложить файл в палату без пересоздания», твой же приём для статики без рестарта (не роняет активные соединения).

Как это у тебя устроено: все 16+ сервисов завода — это отдельные контейнеры на общей docker-сети factory (имя сети как общая «больничная инфраструктура» — трубы, провода — по которой палаты обмениваются сигналами, не выходя наружу). У каждого сервиса, кроме того, есть и свой персональный *_default bridge — как отдельная внутренняя разводка внутри одной палаты (её собственные под-контейнеры вроде базы данных). docker ps — первая команда, которую стоит набирать, когда что-то «не работает», прежде чем спрашивать ИИ.

Для любопытных: контейнер — не полноценная виртуальная машина (это была бы отдельная больница со своими стенами и фундаментом), а изолированный процесс с урезанными правами на том же ядре ОС хоста — легче и быстрее VM, запускается за секунды, но изоляция менее строгая (общее ядро — общий риск). Это ровно причина, почему для ночного строителя приложений курс рекомендует ОТДЕЛЬНЫЙ Docker-контекст (а в идеале — более строгую изоляцию вроде microVM) без секретов завода — модуль 4.4.

Живой якорь: ssh root@docker ps — увидишь свой завод живьём: channel-hq, memory-bank, resource-governor и остальных.

🔧 Три команды docker — что каждая покажет

4. SSH — как физически попасть внутрь сервера

По-человечески: VPS — это как удалённая клиника, куда ты не можешь прийти ногами. SSH — защищённый телефонный/видео-канал, через который ты «оказываешься» внутри и можешь отдавать команды так, будто сидишь за тем компьютером лично.

Как называется по-настоящему (English): SSH (Secure Shell) — зашифрованный протокол удалённого доступа к терминалу другого компьютера.

Как заходишь ты:

ssh root@

root — имя пользователя (в твоём случае — администратор сервера), — адрес VPS. У тебя это уже настроено без пароля — по ключу (файл-«отпечаток пальца», который лежит на твоём ПК и подтверждает личность автоматически, BatchMode проходит без вопросов). Как только зашёл — ты «внутри», и все команды из §1–§3 работают уже НА СЕРВЕРЕ, а не на твоём ПК.

Для любопытных: SSH по умолчанию слушает порт 22 🟢 [стандарт, не число «на глаз» — общеизвестный факт протокола]. Ключевая пара (публичный/приватный ключ) надёжнее пароля: приватный ключ никогда не покидает твой ПК, сервер проверяет подпись, а не сам секрет — украсть пароль перебором на порядки проще, чем подделать подпись без приватного ключа.

Ещё два полезных приёма поверх голого ssh: - scp файл root@:/root/ — «переслать файл по тому же защищённому каналу», без отдельной программы для передачи файлов; для папок добавь -r. - Файл ~/.ssh/config на твоём ПК — «телефонная книга серверов»: один раз прописываешь алиас (Host factory → адрес, пользователь, путь к ключу), дальше просто ssh factory вместо длинного адреса каждый раз.

Отдельно стоит понимать разницу между твоими двумя «удалёнными точками»: сам VPS-сервер (прод, всё живёт там) и reverse-ssh туннель с домашнего ПК (openmontage :8053) — это SSH, вывернутый наизнанку: не ты заходишь на чужую машину, а твой ПК сам держит постоянное соединение с сервером, чтобы сервер мог достучаться ОБРАТНО до твоего локального сервиса (нужен только пока ПК включён — это ровно то ограничение, которое курс отмечает в модуле 8.1: домашняя машина не должна быть в критическом пути).

Живой якорь: зайди по ssh и набери hostname && uptime && df -h — увидишь имя сервера, сколько он «не спал» без перезагрузки и сколько места осталось на диске (твой завод сейчас на 91% — полезно проверять регулярно, это буквально первый пункт роадмапа первой недели курса).


5. API и JSON — как сервисы разговаривают друг с другом

По-человечески: API — это регистратура клиники: ты не бродишь по кабинетам сам, а подаёшь стандартный бланк-запрос в окошко («хочу анализ крови такого-то пациента») и получаешь стандартный бланк-ответ. JSON — это язык, на котором написаны эти бланки: структурированный, машиночитаемый, но и человеку понятный при небольшой привычке.

Как называется по-настоящему (English): API (Application Programming Interface) — контракт, по которому одна программа просит другую что-то сделать или отдать. JSON (JavaScript Object Notation) — формат данных: фигурные скобки {} = «карточка полей», квадратные [] = «список карточек», всё в парах "ключ": значение.

Пример из твоего завода (запрос твоего own broker'а — резюмирован из §08-contracts):

{
  "jobId": "img-8271",
  "status": "done",
  "download_url": "https://photo.rbrstack.com/media/img-8271.png",
  "cost_credits": 1
}

Читается буквально: «работа с номером img-8271 готова, вот ссылка на файл, стоила 1 кредит». Если тебе нужно ЧТО-ТО поменять в конфиге (а не в коде) — почти всегда это правка одного значения в похожей структуре, например в settings.json Telegram-бота или profile.json канала.

Пример посложнее, с вложенностью и списком (структура ближе к твоему profile.json канала):

{
  "channel_id": "lightning-news-01",
  "voice": "moss-v3",
  "topics": ["breaking-news", "tech", "politics"],
  "limits": {
    "videos_per_day": 12,
    "min_gap_minutes": 180
  }
}

Читается по вложенности сверху вниз: у канала lightning-news-01 голос moss-v3, три темы в СПИСКЕ (квадратные скобки — значит порядок и повтор допустимы, это не «карточка», а «список карточек» или значений), а limits — это отдельная ВЛОЖЕННАЯ карточка внутри карточки, со своими двумя полями. Если нужно добавить четвёртую тему — допиши "health" внутрь списка через запятую, ничего больше трогать не надо.

Как читать/править JSON, не сломав: 1. Открой файл в любом текстовом редакторе (VS Code подсвечивает скобки и парные пары — сильно помогает не заблудиться во вложенности). 2. Найди нужный "ключ", поменяй только значение СПРАВА от двоеточия, не трогай кавычки/скобки/запятые вокруг. 3. Перед сохранением проверь: у каждой открывающей скобки {/[ есть закрывающая, у предпоследнего поля в списке НЕТ запятой в конце (частая причина «файл не грузится» — этот один лишний символ разваливает весь файл целиком, JSON не прощает опечаток так, как прощает их обычный текст). 4. Валидатор (сайт типа jsonlint.com или команда python -m json.tool файл.json) — если сомневаешься, пусть машина скажет, не гадай; она либо молча подтвердит структуру, либо укажет точную строку ошибки.

Разница GET и POST (два самых частых типа запроса): GET — «спроси и покажи» (получить статус, список, файл — ничего не меняет на той стороне), POST — «сделай действие» (создать задание на генерацию картинки, опубликовать видео). Практически: curl https://адрес без флагов — это GET; если нужно что-то ЗАПУСТИТЬ, а не просто посмотреть, обычно требуется POST с телом-JSON (curl -X POST -d '{"key":"value"}' https://адрес).

Для любопытных: HTTP-статусы ответа — тоже часть контракта API. 200 = «всё хорошо», 404 = «такого пациента/адреса не существует», 429 = «слишком много запросов, притормози» (твой FastGen-лимит), 500/502 = «сломалось на стороне сервера» (502 у тебя буквально означает «Caddy достучался, а контейнер за ним не отвечает» — см. §8). 🟢 [деление кодов на классы 2xx/4xx/5xx — стандарт HTTP, не внутренняя договорённость завода]

Живой якорь: открой в браузере https://bank.rbrstack.com/api/health (или curl его с сервера) — увидишь живой JSON-ответ от memory-bank прямо сейчас.


6. .env и переменные окружения — тайный ящик с ключами от палаты

По-человечески: у каждой палаты есть свой набор ключей и кодов доступа — их не пишут мелом на двери (в коде, который все видят и коммитят в git), а держат в отдельном опечатанном конверте рядом с постом медсестры. .env — это и есть такой конверт: файл с секретами и настройками, который лежит РЯДОМ с кодом, но не является частью кода и не отправляется в git.

Как называется по-настоящему (English): environment variables (переменные окружения) — значения, которые программа читает из своего «окружения» при старте, а не из кода. .env — просто самый частый способ ИХ хранить и подгружать (файл вида КЛЮЧ=значение, строка на строку).

Твой реальный пример (упрощённо, по мотивам карты секретов из 08-contracts.md):

FASTGEN_API_KEY=sk-xxxxxxxxxxxx
BANK_URL=http://memory-bank:4600
GOVERNOR_URL=http://resource-governor:4700
IMAGES_VIA_BROKER=1

Каждая строка — один секрет или настройка. Контейнер при запуске читает этот файл и получает эти значения как будто они «в воздухе» вокруг него.

Главная грабля, которую ты уже словил живьём (твоя же запись в 06-errors-and-gotchas.md, пункт 5): «код умеет X, но фича выключена» — .env-файл существует и содержит правильное значение, но docker-compose.yml его не пробрасывает внутрь контейнера. Цепочка проверки всегда одна и та же:

.env (файл на диске) → docker-compose.yml (пробрасывает ли переменную?) → docker exec <c> printenv (что реально видит программа)

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

Для любопытных: правило «секреты — только в .env, никогда в код/репозиторий/чат с ИИ» (у тебя это прямо прописано в карте секретов) — не паранойя, а стандартная гигиена: если ключ попадёт в git-историю, его придётся считать скомпрометированным даже после удаления файла, потому что старые коммиты помнят всё. Это же правило — прямая причина, почему ночной строитель приложений (модуль 6, 11.2) не должен иметь доступа к боевым .env-файлам завода: агент, которому дали ключи «на всякий случай», рано или поздно случайно засветит их в логе, коммите или ответе.

Небольшая тонкость, которая экономит часы недоумения: переменные окружения можно задать и БЕЗ файла .env — прямо в терминале (export FASTGEN_API_KEY=xxx на Mac/Linux, $env:FASTGEN_API_KEY="xxx" в PowerShell). Такая переменная живёт только в текущем окне терминала и исчезает при закрытии — удобно для разового теста, но именно поэтому воспроизводимость и надёжность даёт только файл .env, который перечитывается при каждом запуске контейнера.

Живой якорь: на сервере cat /root/channel-hq/.env | grep -v KEY (без вывода настоящих ключей на экран) — увидишь список настроек одного из твоих сервисов вживую.

🔧 «Код умеет X, но фича выключена» — где рвётся цепочка
.env (файл на диске) docker-compose.yml docker execprintenv
Нажми на звено цепочки — узнаешь, что там может сломаться.

7. Порты и сеть: кто с кем может говорить

По-человечески: представь больницу с сотнями кабинетов на одном этаже (сервере). Порт — номер конкретного кабинета: «зайти к терапевту» и «зайти к рентгенологу» — это один и тот же этаж, разные двери. localhost / 127.0.0.1 означает «этот же корпус, для внешних пациентов вход закрыт» — только свои сотрудники могут туда попасть. 0.0.0.0 означает «дверь открыта на улицу для кого угодно» — это то, что стоит проверять на предмет случайной уязвимости.

Как называется по-настоящему (English): port — номер (0–65535) конкретного «канала связи» на одном IP-адресе; localhost / 127.0.0.1 — «этот же компьютер, снаружи недоступно»; 0.0.0.0 — «слушай на всех сетевых интерфейсах, доступно снаружи, если файрвол не против».

На твоём заводе это выглядит так (снимок 04-server.md): большинство контейнеров биндятся на 127.0.0.1 — наружу их видно ТОЛЬКО через Caddy (единственный публичный вход, порты 80/443, дальше он сам решает, в какой «кабинет» перенаправить запрос по имени поддомена — channel.rbrstack.comlocalhost:8030). Несколько сервисов (photo-генератор, omni-генератор, статик-карты) исторически открыты на 0.0.0.0 — это прямо отмечено как то, что стоит регулярно аудировать (твой roadmap, этап 1 первой недели).

Между «недоступно снаружи вообще» и «доступно всему интернету» есть и третий, средний вариант — частные IP-адреса (диапазоны 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 🟢 [зарезервированы стандартом RFC 1918 для приватных сетей — проверено по первоисточнику]): видны внутри локальной/облачной сети, но не маршрутизируются в открытый интернет напрямую — это тот же принцип, что «внутренняя больничная связь между этажами», не выходящая на городскую телефонную линию. Твоя docker-сеть factory работает именно в такой частной адресации — контейнеры получают внутренние IP из этого диапазона, а наружу их выпускает уже только Caddy на настоящем публичном адресе VPS.

Внутри docker-сети factory — отдельное правило: контейнеры видят друг друга по ИМЕНИ, не по localhost и не по IP — например, http://memory-bank:4600, а не http://localhost:4600 (это сработает только если ты уже ВНУТРИ того же контейнера, что и адресат). 🟢 [это встроенное поведение Docker: контейнеры в одной пользовательской bridge-сети получают друг для друга DNS-имена по имени контейнера — задокументированное поведение Docker, не особенность твоего завода]

Для любопытных: диапазон 0–1023 называется «известные порты» (well-known ports, закреплены за стандартными службами — 22 = SSH, 80/443 = веб), 1024–65535 — свободные для приложений. 🟢 [деление на диапазоны портов — стандарт IANA]. Порты твоих сервисов (8000, 8030, 8600...) выбраны произвольно из свободного диапазона — это НЕ протокольное требование, просто соглашение внутри завода, чтобы не пересекались.

Ещё один слой, который встретится в roadmap (модуль 8.1, 11.2): Tailscale. Это не порт и не Docker-сеть, а частная «телефонная линия» между твоими устройствами (VPS, ПК с 3090, ноутбук) — они видят друг друга по своим внутренним адресам, как будто сидят в одной локальной сети, даже физически находясь в разных городах, и это НЕ видно и НЕ доступно снаружи вообще. Это тот механизм, которым домашний ПК с 3090 сможет по требованию давать VPS доступ к GPU, оставаясь при этом закрытым для всего остального интернета — прямая противоположность случайно открытому 0.0.0.0.

Живой якорь: на сервере ss -tlnp | grep LISTEN — список всех открытых портов и того, кто их слушает; сверь с таблицей контейнеров в 04-server.md — если появился новый порт, которого там нет, стоит разобраться, откуда он.

🔧 Кто снаружи может постучаться в эту дверь

8. Как читать ошибку и лог, когда сломалось

По-человечески: ошибка — это симптом, а не диагноз. «Болит живот» само по себе не говорит, что делать, — важно ГДЕ болит, КОГДА началось и ЧТО было перед этим. Лог (журнал) — это анамнез: хронологическая запись событий, по которой ищется первопричина, а не просто последняя жалоба.

Как называется по-настоящему (English): log — журнал событий; stack trace / traceback — «путь», по которому ошибка всплыла наружу через код: это не хаотичный текст, а строгий маршрут вызовов одной функции за другой. Направление чтения зависит от языка (в Python традиционно самая ВАЖНАЯ строка — последняя, внизу, «где реально сломалось»; в JavaScript часто наоборот, важное — сверху) — если не уверен, ищи глазами не позицию, а саму фразу ошибки (Error:, Exception:) и текст вокруг неё, а не пытайся угадать по одному правилу для всех языков.

Порядок действий, когда «что-то не работает» (твой закон №4 в действии): 1. docker ps — контейнер вообще жив? Если его нет в списке или он в статусе Restarting — вот и причина. 2. docker logs --tail 100 <имя> — последние 100 строк журнала. Ищи глазами не первую попавшуюся строку с «error», а самую раннюю ошибку в цепочке — часто дальше идёт лавина повторов одной и той же причины. 3. HTTP-код, если проблема при обращении к сервису через браузер/Caddy: 502 почти всегда значит «Caddy достучался, а сам сервис за ним не ответил» (контейнер упал/перезапускается); 429 — «слишком много запросов, ты уперся в лимит» (твой FastGen-кейс); 404 — «неверный адрес/сабдомен». 4. Твоя собственная база граблей (06-errors-and-gotchas.md) — прежде чем гадать заново, проверь, не наступал ли ты УЖЕ на эту грабли месяц назад. Симптом «висит на running» у тебя уже расшифрован (залипший семафор), «429 при свободном usage-окне» — тоже (зомби-задачи).

Пример из твоей же практики (реальный кейс, не гипотетический): Learningo после передеплоя без override терял порт 8110, и Caddy отвечал 502 — снаружи это выглядело как «бот не отвечает», хотя сам Telegram-поллинг был жив. Диагноз нашёлся не гаданием, а строго по цепочке порт → docker-compose override → Caddy — то есть теми же тремя инструментами (docker ps, конфиг, лог), что и в §6.

Небольшой словарь фраз, которые будут попадаться постоянно (переводя их сразу на «диагноз», а не пугаясь текста): - Connection refused — «дверь заперта»: адрес верный, но по этому порту никто не слушает (контейнер не запущен или слушает другой порт). - Permission denied — «нет допуска в палату»: не тот пользователь, не тот ключ, не те права на файл. - Timeout / Connection timed out — «дверь не отвечает вообще»: не отказ, а тишина — часто файрвол, не тот адрес в сети, или сервис реально завис (см. п.1 твоей же базы граблей про залипший семафор). - No such file or directory — «в карте нет такой страницы»: опечатка в пути или файл ещё не создан/уже удалён. - Address already in use — «кабинет уже занят»: кто-то другой уже слушает этот порт — обычно означает, что старый контейнер не до конца остановился перед новым запуском.

Для любопытных: «тихий отказ» (silent failure) — самый опасный вид ошибки для ночной автономии: программа не падает с текстом ошибки, а просто молча делает не то (или ничего). Именно поэтому курс (модуль 6.3, 8.3) требует явных чекпоинтов и структурного лога решений — умение читать docker logs руками сегодня прямо готовит тебя понимать, ПОЧЕМУ это архитектурное требование, а не бюрократия.

🔧 Переведи фразу ошибки на «диагноз»

9. Собираем всё вместе: разбор одного вымышленного, но типичного вечера

Представь: ты открываешь channel.rbrstack.com — портал не грузится, браузер показывает 502. Вот как расследование выглядит, используя ровно те восемь навыков выше, по порядку, а не хаотично:

  1. Терминал + ssh (§1, §4): ssh root@ — заходишь на сервер.
  2. Docker (§3): docker ps — видишь, что channel-hq в списке ЕСТЬ, но колонка STATUS показывает Restarting (1) 12 seconds ago — контейнер падает и перезапускается по кругу, а не просто «висит».
  3. Логи (§8): docker logs --tail 50 channel-hq — в самом верху пачки повторяющихся строк видишь однократную первопричину: Error: connect ECONNREFUSED memory-bank:4600 — «дверь заперта», channel-hq пытался достучаться до memory-bank и не смог.
  4. Проверяешь соседа (§3 снова): docker ps | grep memory-bank — а его вообще нет в списке. Значит, упал он, а channel-hq просто честно сообщает о последствиях.
  5. .env / порт (§6, §7): проверяешь, не менялся ли недавно .env memory-bank или его порт в docker-compose.yml — например, кто-то (ты сам вечером, или ИИ во время сессии) поправил BANK_URL и забыл, что имя контейнера в сети factory должно совпадать буква в букву.
  6. Git (§2): git log --oneline -5 в папке memory-bank — смотришь, было ли сегодня изменение конфигурации, которое могло всё это спровоцировать; git diff покажет ТОЧНО что поменялось.
  7. Чинишь и проверяешь JSON/API (§5): после исправления и docker compose up -d --buildcurl https://bank.rbrstack.com/api/health, ждёшь {"ok":true} в ответ, а не гадаешь по внешнему виду сайта.

Ни один отдельный навык здесь не решил бы задачу — только их последовательность, применённая методично (твой закон №4 «проверяй живое», а не первое предположение). Заметь и то, чего в этом расследовании НЕ произошло: ты ни разу не написал ни строчки нового кода — только читал состояние системы и поправил один настроечный файл. Это ровно тот уровень, который требуется от директора завода, а не от разработчика.


Где здесь деньги: каждая минута, которую ты сейчас тратишь на docker ps вместо переписки с ассистентом «а что там с сервером», — это минута, отвоёванная у роли «человек-клей» (твоя боль №1 из профиля). Больше того: без этой азбуки ты физически не сможешь САМ проверить ночной прогон строителя приложений или консультант-фабрики утром — а значит, не сможешь доверить системе полную автономию, потому что «доверяй, но проверяй» требует уметь проверить. Азбука — это цена входного билета в ночную автономию, а не бюрократия ради бюрократии.


Чек-лист внедрения

Отметь каждый пункт, сделав его руками, не через ИИ-ассистента (цель — мышечная память, а не разовый просмотр):

Когда все пункты отмечены — «живые якоря» остальных модулей курса перестают быть страшными: это те же самые 8-9 движений, просто применённые к новой теме. Не обязательно проходить чек-лист за один вечер — это ежедневная разминка на первую неделю, пока руки не привыкнут искать docker ps раньше, чем вопрос к ассистенту.

Мини-проверка себя (3 вопроса, ответь вслух, не подглядывая, потом сверься с подсказкой в скобках): 1. Портал channel.rbrstack.com не открывается, браузер пишет 502 — с какой ОДНОЙ команды ты начнёшь расследование и почему именно с неё? (подсказка: та, что покажет, жив ли контейнер вообще, прежде чем читать журнал). 2. В .env сервиса есть правильное значение ключа, но фича всё равно не работает — какое из трёх звеньев цепочки ты проверишь ПЕРВЫМ и почему не сразу «код»? (подсказка: цепочка идёт от файла на диске к тому, что реально видит запущенная программа, не наоборот). 3. Чем 127.0.0.1 отличается от 0.0.0.0 в одном предложении, без терминов из учебника? (подсказка: вопрос «кто снаружи может постучаться в эту дверь», а не «где физически находится сервер»).

Если на все три вопроса ответ пришёл без подглядывания в текст выше — азбука усвоена, дело за практикой, а не за повторным чтением.

Куда это в курсе

Этот модуль — несущие леса (Приложение COURSE-GAPS, пункт №3), место в структуре: между Модулем 0 (Введение) и Модулем 1 (Основы агента), как «Модуль 0.5» — ставится рано специально, потому что от него зависит интерактивность (живые якоря) всего, что идёт дальше. Прямая зависимость: КАЖДЫЙ «живой якорь» с М1 по М11 предполагает, что студент уже умеет открыть терминал, зайти по ssh, прочитать docker ps/docker logs и не бояться JSON — это ровно то, что здесь закрыто.

Отдельные пункты дальше углубляются предметно, азбука — это их фундамент, не замена: - git-паттерн памяти агента (main/commit/log) — Урок 3.3 «Git-память для строителя». - матрица портов и биндингов 0.0.0.0 — Урок 4.4 «Sandbox и безопасность: изолируй ночного строителя от секретов завода». - .env-цепочка секретов и карта секретов завода — Урок 4.1 (матрица риска) и Урок 11.2 (изоляция ночного билдера от боевых .env). - чтение логов при тихих отказах (silent failure) — Урок 6.3 «Ночь без человека» и Урок 8.3 «Единая веб-панель». - docker/контейнеры как единица изоляции — Урок 4.4 и Урок 11.2 (сравнение Docker/gVisor/microVM). - JSON и API-контракты — Урок 1.3 «Инструменты (tool use)», где тот же формат станет языком, которым агент описывает свои функции.

Если проверка себя (три вопроса выше) прошла легко — двигайся в Модуль 0 «Введение: организм, а не программа». Если нет — вернись к чек-листу и повтори живые якоря ещё раз, не читая теорию заново: это навык рук, а не знание.