HERON

Гайд 06 · для того, кто выкладывает

Сборка и выкладка

Как собрать сайт для прода, упаковать его в образ и вести несколько сайтов на разных версиях HERON. Для того, кто выкладывает, — человека или агента-сборщика.

Одна и та же папка сайта выходит из HERON либо обычными файлами, либо готовым образом. Здесь — оба пути и проверки, которые проходит сайт перед выкладкой.

Простыми словами

Сборка похожа на выпечку: папка с текстами — тесто, heron build — печь, готовый сайт — хлеб. Хлеб можно отдать как есть — папкой dist/ с готовыми страницами — или упакованным в коробку — образом, который запустит любой сервер с Docker. Эта страница объясняет оба способа и проверки, которые проходят до того, как хлеб покинет кухню.

Что выбрать. Бесплатный хостинг вроде GitHub Pages или обычный тариф хостинга принимает папку. Свой сервер с Docker принимает образ, и обновление превращается в «скачать новый образ и перезапустить». Если сомневаетесь, начните с папки; на странице Публикация способы сравниваются.

Пример. heron build . --env prod --strict делает dist/ со всеми страницами, картой сайта, llms.txt и готовым конфигом nginx. Скопируйте эту папку на хостинг — и сайт в интернете.

Эта страница нужна, когда сайт готов выйти в интернет и когда на одном сервере живут несколько сайтов.

Два выхода: папка или образ

Папка dist/ Образ nginx
Чем heron build scripts/site.sh САЙТ image
Что внутри HTML, картинки, карты, .heron-nginx.conf nginx-unprivileged, статика, конфиг под этот сайт
Куда любой хостинг статики, свой nginx любой хост с докером, Kubernetes
301, 410, своя 404 подключить .heron-nginx.conf в свой nginx уже включены

Выход выбирается командой, а не при создании сайта: одна и та же папка собирается и так, и так. Подробно — два выхода в спецификации.

Окружение сайта

Рабочая и боевая сборка — это флаг сборки, а не другой образ HERON:

--env dev (по умолчанию) --env prod
индексация закрыта: noindex и Disallow: / открыта
счётчики из analytics нет есть
метка сборки (версия, время, коммит) тема может показать не показывается

--strict превращает предупреждения в ошибки — для прода обязателен. Перебить по отдельности: SITE_INDEXABLE=false, SITE_ANALYTICS=false — прод-подобное превью, закрытое от поисковиков.

Домен по окружению. Рабочая сборка на своём адресе должна ссылаться на себя, а не на боевой домен. Для этого в site.yaml:

site:
  domain: example.com          # боевой
  domains:
    dev: dev.example.com       # canonical, sitemap, hreflang, robots — на этот адрес в рабочей сборке

Имя окружения то же, что в --env: один рычаг управляет и индексацией, и доменом.

Один сайт

H="docker run --rm -v $PWD:/site -w /site --user $(id -u):$(id -g) ghcr.io/fmstm/heron:prod"
$H build мой-сайт --env prod --strict

мой-сайт/dist/ — готовый сайт. Залейте папку на хостинг статики (тогда 301 и 410 настраиваются средствами хостинга по dist/redirects.map и dist/gone.map) или отдайте своему nginx — ниже.

Свой nginx на сервере

dist/.heron-nginx.conf — готовый блок server {} вместе с картами 301 и 410. Он подключается в контекст http, как любой файл сайта. Пример для Debian или Ubuntu с nginx из apt:

sudo cp -r мой-сайт/dist /var/www/мой-сайт
sudo cp мой-сайт/dist/.heron-nginx.conf /etc/nginx/sites-enabled/мой-сайт.conf
# в файле поправьте root на /var/www/мой-сайт и listen/server_name под свой хост
sudo nginx -t && sudo systemctl reload nginx

Размеры хэшей карт. В начале файла стоят map_hash_bucket_size и map_hash_max_size — HERON посчитал их по самому длинному адресу из redirect_from и gone. Без них длинный кириллический адрес не помещается в корзину размером с кэш-линию процессора, и nginx не стартует: could not build map_hash, you should increase map_hash_bucket_size: 64. Отчёт сборки показывает посчитанные значения.

Если /etc/nginx/nginx.conf хоста уже задаёт эти директивы, повтор в файле сайта даст directive is duplicate. Тогда в site.yaml:

nginx:
  hash_sizes: off     # auto (по умолчанию) — писать в конфиг сайта; off — их задаёт хост

Отчёт сборки напишет, сколько нужно, — например «картам 301/410 нужен map_hash_bucket_size ≥ 256». Это вписывается в http { … } файла /etc/nginx/nginx.conf:

http {
    map_hash_bucket_size 256;
    map_hash_max_size 2048;
    # … остальное как было
}

Если nginx есть на машине, где идёт сборка, HERON сам прогоняет nginx -t на собранном конфиге и пишет результат в отчёт; не прошёл — предупреждение, при --strict — ошибка.

Посмотреть локально — heron serve мой-сайт: та же 404, что увидит посетитель, сборка во временную папку, папка сайта не пачкается. 301 и 410 serve не изображает — их проверяет smoke на образе.

Образ из репозитория сайта

Сайт обычно живёт в своём репозитории, и клона HERON рядом нет. Образ собирает переиспользуемый workflow HERON — свой Dockerfile писать не нужно:

# .github/workflows/image.yml в репозитории сайта
name: image
on:
  push:
    branches: [main]

jobs:
  image:
    uses: FMSTM/HERON/.github/workflows/site-image.yml@prod
    permissions:
      contents: read
      packages: write
    with:
      env: dev          # dev или prod
      engine: prod      # тег HERON: prod, beta или 0.1.0

Workflow соберёт сайт HERON из образа, упакует dist/ в nginx по рецепту той же версии HERON, поднимет образ, прогонит дымовую проверку и отправит его в ghcr.io/ВЛАДЕЛЕЦ/РЕПОЗИТОРИЙ:ОКРУЖЕНИЕ. Параметры: path — папка сайта внутри репозитория, image и tag — своё имя образа, strict — true или false (по умолчанию строгая только prod), push: false — собрать и проверить без отправки. Пока бета не стала продом, звать @beta с engine: beta.

Несколько сайтов: scripts/site.sh

Из клона репозитория HERON:

git clone https://github.com/FMSTM/HERON.git && cd HERON && HERON_NOTES=ru ./scripts/site.sh мойсайт new ~/sites/мой-сайт

new создаёт папку сайта — в терминале с теми же вопросами, что и heron new, — и заводит env/.env.мойсайт.dev и .prod. Папка может уже существовать и быть под git. Дальше всё — одной командой:

./scripts/site.sh мойсайт check dev     # отчёт без сборки
./scripts/site.sh мойсайт build dev     # → out/мойсайт-dev
./scripts/site.sh мойсайт serve dev     # nginx на localhost:$PORT
./scripts/site.sh мойсайт stop          # погасить просмотр
./scripts/site.sh мойсайт build prod
./scripts/site.sh мойсайт image prod    # образ IMAGE_NAME:IMAGE_TAG
./scripts/site.sh мойсайт smoke prod    # поднять образ, проверить коды
./scripts/site.sh мойсайт push prod     # в REGISTRY
./scripts/site.sh мойсайт init          # достроить папку после правки site.yaml

Папка контента монтируется только на чтение: всё, что производит сборка, живёт в out/, контент ничем не пачкается.

Настройки сайта — env/.env.САЙТ.ОКРУЖЕНИЕ, в git не попадают. Образец с пояснениями — env/.env.example.

Переменная Что задаёт
SITE_PATH путь к папке сайта
SITE_ENV dev или prod — каким будет сайт
STRICT строгая сборка
ENGINE какой версией HERON собирать (ниже)
IMAGE_NAME, IMAGE_TAG имя образа сайта
REGISTRY, REGISTRY_CONFIG реестр для push и докер-конфиг для него; пусто — push запрещён
PORT порт просмотра
HERON_NOTES язык комментариев и записок, которые кладёт init: ru или en

Секреты форм (SMTP, вебхуки) сюда не кладутся: сборка статическая, всё, что она видит, может оказаться в HTML.

Дымовой прогон

site.sh САЙТ smoke ОКРУЖЕНИЕ поднимает собранный образ и сверяет ответы (саму проверку делает scripts/smoke-site.sh — тот же скрипт зовёт workflow образа сайта):

  • корень и robots.txt — 200, несуществующий адрес — 404;
  • языковой раздел — 200 и своя 404;
  • служебный конфиг рядом со статикой — 404;
  • каждый адрес из redirects.map — 301 туда, куда объявлено;
  • каждый точный адрес из gone.map — 410.

Упал — контейнер гасится, логи nginx печатаются. Подробно — проверки и дымовой прогон.

Версии HERON

Сайт закрепляет версию HERON сам — первой строкой site.yaml:

heron: ">=0.1,<0.2"

HERON не из диапазона откажется собирать (E012). Обновление HERON для сайта — смена этой строки, осознанно и по одному сайту.

Какой версией собирает site.sh — ENGINE в env-файле:

Значение Когда
пусто точная версия из site.yaml, если она там точная; иначе исходники рядом; иначе :prod
ghcr.io/fmstm/heron:prod стабильный — обычный выбор
ghcr.io/fmstm/heron:0.1.0 закрепиться на версии
source собрать из исходников рядом — только когда правите сам HERON

Теги образа HERON:

Тег Что это
:X.Y.Z точная версия, не меняется никогда
:prod то, на чём стоят сайты
:beta обкатка следующей версии на живых сайтах
:dev разработка HERON; для сайтов не предназначен

Какой образ на руках, показывает --version: ветка, коммит и время сборки, например heron, version 0.1.0 (beta, 55249f0, 2026-10-08 19:12 UTC). Номер версии один на всю ветку разработки, а по коммиту видно, свежая ли бета. Из исходников — (source, КОММИТ).

Подвижного :X.Y нет намеренно: сайт должен иметь возможность закрепиться на том, что не поедет под ним завтра.

Чек-лист перед выкладкой

  1. 1

    site.yaml

    Домен, языки, heron: с диапазоном, счётчики.
  2. 2

    Строгая сборка

    build --env prod --strict проходит без ошибок.
  3. 3

    Пустые секции

    Сводка «Не заполнено» пуста или осознанно принята.
  4. 4

    Дымовой прогон

    smoke prod зелёный: 200, 404, все 301 и 410.
  5. 5

    После выкладки

    Карта сайта — в Search Console.

Источник

Эта страница повторяет docs/guide/06-deploy.md из ветки prod. Репозиторий обновляется первым, поэтому там всегда самая свежая версия.

Справочник: спецификации Развёртывание и Поставка.