Как задеплоить сайт на Astro

Astro по умолчанию собирает сайт в набор готовых HTML-страниц, поэтому публикация обычно сводится к одной задаче: где-то выполнить npm run build и отдать получившуюся папку dist/ в интернет. Звучит легко, но на деле нужен сервер с подходящей версией Node.js, веб-сервер, смотрящий в правильную папку, сертификат, а если в проекте включён серверный режим — ещё и постоянно работающий процесс, который поднимется после падения. На Dockbox эту часть берёт на себя платформа: вы загружаете исходники, сборка идёт на её стороне, на выходе — публичный HTTPS-адрес. Ниже — что подготовить в проекте, чтобы всё заработало с первого раза.

Почему статичный сайт на Astro всё равно упирается в сервер

Привычный путь — длинный чек-лист: арендовать VPS, поставить нужную версию Node.js, прогнать npm install, собрать проект, положить dist/ туда, откуда его отдаёт nginx, выпустить сертификат.

Версия Node.js. Astro последних версий требует Node.js 18 и новее. На сервере со старой версией npm run build падает ещё до первой страницы, а внятной причины в выводе может не быть.

Где запускать сборку. Сборку можно сделать локально, но тогда папка dist/ устаревает после первой же правки в контенте: добавили пост — снова собирайте и снова заливайте.

Серверная часть. Если включён output: server, без запущенного процесса сайт не откроется: статичных файлов просто нет, страницы рисуются на каждый запрос. Такому проекту нужен менеджер процессов, перезапуск после сбоя и правильный порт.

Порт и сертификат. Процесс должен слушать порт, который даёт окружение, а не тот, что прописан в коде, иначе ссылка не открывается. Плюс HTTPS и продление сертификата.

Платформа деплоя снимает эту часть: она видит package.json, ставит зависимости, выполняет сборку и выдаёт публичную HTTPS-ссылку.

Шаг 1. Посмотрите в astro.config: static или server

Это ключевой шаг, от него зависят остальные. В конфиге Astro есть поле output, и по умолчанию его нет — это значит статическую генерацию (SSG): сайт собирается в готовые страницы, которые ничего не должны исполнять. Второй вариант — output: "server" (в старых версиях встречался hybrid): тогда часть страниц рендерится по запросу.

Косвенные признаки серверного режима: собственные эндпоинты, обработка форм, работа с сессией. Если ничего этого нет, у вас обычный статичный сайт — самый простой случай.

Шаг 2. Загружайте исходники, а не папку dist

Сборка идёт на стороне платформы по вашему package.json, поэтому dist/ и node_modules/ в архив класть не нужно. Они только утяжеляют загрузку и устаревают с первой же правкой. Достаточно проверить, что в package.json есть скрипт сборки:

{
  "scripts": {
    "build": "astro build",
    "preview": "astro preview"
  }
}

Collections обрабатываются при сборке. Посты в Markdown и MDX, а также оптимизация картинок происходят во время npm run build, а он выполняется на платформе. Отдельно включать ничего не надо — важно, чтобы исходники и изображения лежали в проекте, а не были уже собранными.

Шаг 3. Для серверного режима подключите Node-адаптер

Если сайт рендерится на сервере, Astro нужен адаптер. Ставьте официальный @astrojs/node в режиме standalone — тогда по итогам сборки получается самодостаточный сервер, который достаточно просто запустить:

import node from "@astrojs/node";
export default defineConfig({
  output: "server",
  adapter: node({ mode: "standalone" }),
});

Второй режим того же адаптера — middleware — рассчитан на то, что вы сами встраиваете Astro в свой сервер. Здесь он не подходит: запускать будет нечего. Статичный сайт этот шаг пропускает полностью.

Шаг 4. Порт и хост берите из PORT и HOST

Порт прослушивания платформа передаёт через переменную окружения PORT. Жёстко прописанный в проекте номер — причина номер один, по которой сайт собрался, а ссылка не открывается. Сервер, который строит Node-адаптер, сам читает PORT и HOST, так что обычно делать ничего не нужно: главное — не переопределять их в конфиге или команде запуска.

Слушайте на 0.0.0.0, а не на localhost. Первый адрес принимает трафик извне контейнера, второй виден только внутри него. Обратите внимание: острова на React, Vue или Svelte этой настройки не касаются — это обычные клиентские компоненты, и порт им не нужен.

Шаг 5. Секреты — в переменные окружения

Если сайт ходит в headless CMS, сервис форм или платный API, ключи не должны лежать в коде и в папке проекта. Их переносят в переменные окружения проекта — они хранятся зашифрованными и не попадают ни в архив, ни в репозиторий.

Помните правило Astro: в браузер попадают только переменные с префиксом PUBLIC_. Секретный ключ нельзя называть так — иначе он окажется в исходном коде страницы. И ещё: при статической сборке значения «запекаются» в готовые файлы на этапе сборки, поэтому после смены ключа нужна новая публикация.

PUBLIC_SITE_URL=https://example.com
CMS_API_TOKEN=***

Шаг 6. Загрузите код и получите HTTPS-ссылку

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

Сколько это стоит и как работают контейнеры

Администрировать сервер не нужно — контейнеры работают постоянно, без ограничения по часам и без «засыпания». Упавший контейнер платформа перезапускает сама.

Starter — 990 ₽/мес. 1 vCPU, 2 GB RAM, первый месяц бесплатно. Для одного сайта на Astro этого достаточно, лимита по времени работы у тарифа нет.

Pro — 2 490 ₽/мес. Больше ресурсов и до пяти проектов — если рядом с сайтом живут база, очередь и воркер.

Team — 4 990 ₽/мес — для команд, которым нужен запас ресурсов и SLA.

Тарифы и подробности — на dockbox.host.

Частые вопросы

Нужно ли собирать сайт самому и загружать папку dist?

Нет, загружайте исходники. Платформа сама ставит зависимости из package.json, запускает сборку и отдаёт результат по вашей ссылке. Локально собранный dist/ только утяжеляет архив и устаревает при первой же правке кода.

Как понять, статичный у меня сайт или серверный?

Откройте конфиг Astro: если поля output нет или там static, сайт статичный — это режим по умолчанию. Значение server (в старых версиях hybrid) означает, что часть страниц рендерится по запросу, и такому проекту нужен адаптер Node.js. Косвенный признак серверного режима — свои эндпоинты или обработка форм внутри сайта.

Сайт собрался, но ссылка не открывается — почему?

Чаще всего дело в порте: приложение слушает свой номер вместо PORT из окружения или слушает localhost вместо 0.0.0.0. Вторая причина — сборка без Node-адаптера или адаптер в режиме middleware, тогда запускать просто нечего. Что именно произошло, видно в логах панели.

Работают ли content collections и оптимизация картинок?

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

Можно ли использовать острова на React, Vue или Svelte?

Да, для платформы это обычная часть проекта: интеграции перечислены в package.json и устанавливаются во время сборки вместе со всем остальным. Никакой отдельной настройки острова не требуют.