Развёртывание
Всё создаётся скриптами из каталога infra — вручную в веб-консоли Oracle ничего делать
не нужно и не следует.
infra/README.mdЗдесь оно намеренно не дублируется: это оперативная сводка, она меняется чаще документации, и вторая копия разъедется с первой молча. Что стоит знать из неё на входе — имён теперь четыре, сертификат один на все четыре и автопродление включено.
Как это устроено
Две машины Oracle Always Free, и разделение между ними — не вкусовое.
инт ернет
│ только 443 (80 → редирект, 22 → обслуживание)
▼
Машина B — публичная, nginx + TLS, один адрес и четыре имени
panel.… → панель оператора (статика) + её /api/ → машина A
api.… → только /device/* → машина A, всё прочее 404
ota.… → манифест обновлений и /assets/
docs.… → эта документация (статика)
голый IP → соединение рвётся (444)
│
▼ приватная сеть, снаружи недостижима
Машина A — сервер: NestJS + SQLite, публичного адреса нет вовсе
У сервера нет публичного адреса: наружу он ходит только сам, входящих соединений из интернета к нему не существует. Это дешевле любой настройки файрвола и надёжнее.
Почему имён четыре, а не одно, и что именно это даёт — четыре имени.
Коротко: в фильтр на роутере объекта попадают только api и ota, и панель оператора
становится постамату недоступна вовсе.
Документация
Сайт собирается в статику. Node в проде не нужен: на сервере лежат файлы, отдаёт их nginx.
cd apps/docs
npm run build # → build/
npm run serve # локальная проверка того, что собралось
npm start # режим разработки с перезагрузкой
Выкладка — тем же скриптом, что и панель:
infra/scripts/deploy-static.sh --docs ../apps/docs/build
Он кладёт содержимое в /srv/postamat/docs на машине B, откуда его отдаёт отдельный
блок server из infra/machine-b/postamat.nginx.conf — тот, что слушает имя
docs.1.router.thepragmaticdev.support.
baseUrl — это /, и обратно на /docs/ его менять нельзяДокументация переехала на собственное имя и живёт в его корне, поэтому
в docusaurus.config.ts задан baseUrl: '/'. Пока она стояла подкаталогом на общем
хосте с панелью, здесь было '/docs/' — и это было обязательно.
Ошибка тихая в обе стороны: страницы открываются, просто ссылки на стили и скрипты уезжают не туда, и сайт выглядит сломанным. Кода возврата 404 при этом не будет, поэтому проверять надо глазами — открыть собранный сайт и посмотреть, есть ли оформление.
Смена схемы адресов — это всегда две правки сразу: baseUrl здесь и блок server
в конфигурации nginx. По отдельности любая из двух ломает сайт.
url в конфигурации — https://docs.1.router.thepragmaticdev.support. Он влияет
на абсолютные ссылки в собранной статике, поэтому при переезде правится вместе с остальным.
Про установку зависимостей
Обычный npm install из корня монорепо ставит и зависимости документации — это рабочий путь.
Но он же тянет весь остальной репозиторий, включая тяжёлый мобильный проект, и падает
целиком, если у соседнего пакета сломан package.json.
Поэтому у apps/docs есть собственные node_modules и собственный package-lock.json,
поставленные так:
cd apps/docs && npm install --workspaces=false
Флаг говорит npm «поставь зависимости только этого каталога». Сборка документации после этого не зависит от состояния остального монорепо — полезно и на сервере сборки.
Панель оператора
Next.js со строго статической сборкой: npm run build --workspace=apps/panel кладёт
в out/ одиннадцать страниц. Выкладка — deploy-static.sh --panel ../apps/panel/out.
Адрес сервера задаётся при сборке (NEXT_PUBLIC_API_BASE, по умолчанию /api) — то есть
переезд API означает пересборку панели, а не правку конфига на сервере. Значение по умолчанию
не случайно относительное: панель держит свой /api/ на своём же имени, поэтому браузер
оператора остаётся в пределах одного источника и CORS не нужен вовсе.
Почему статика, а не Node: на машине B один гигабайт памяти, там уже живут nginx и сервер API, и второй Node-процесс держать нечем.
Сервер
apps/api — NestJS и SQLite, машина A. 🟡 Пишется прямо сейчас, поэтому здесь только то,
что уже зафиксировано инфраструктурой:
- выкладка —
deploy-api.sh, с откатом при неуспехе; - сервис под systemd с ограничением памяти, своп 2 ГБ — машина маленькая;
- резервная копия базы —
backup.sh, учебное восстановление —restore-drill.sh(боевую базу не трогает); - постаматы ходят только до нашего backend — на роутере в проде стоит фильтр. Значит
сервер обязан быть единственной точкой, откуда устройство получает и коды, и конфигурацию,
и обновления. В фильтр при этом заносятся только имена
apiиota— почему именно так.
Что мешает прямо сейчас
| Что | Почему |
|---|---|
| тревоги не уходят наружу (письма, SMS) | отправку делает сервер, он пишется |
Эта строка важна не только разработчику: пока каналы не работают, ночная тревога будет замечена утром. Панель говорит это прямым текстом на своём экране тревог, и то же самое написано оператору.
Про имена, сертификат и состояние машин смотрите infra/README.md — там оперативная сводка,
и она первична по отношению к этой странице.