Hostim Docs

Статический сайт

Статический сайт представляет собой тип сервиса, при котором платформа собирает репозиторий, берёт папку с результатом сборки и раздаёт её готовым веб-сервером. Своего процесса у такого сервиса нет: после сборки запускается не ваш код, а nginx с вашими файлами.

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

Когда выбирать

Есть ли в репозитории серверный код, который нужно запустить?

  • Нет, сборка выдаёт готовые файлы → Статический сайт
  • Да, свой сервер запускается и отвечает на запросы → Сервер с HTTP

Статический сайт подходит для лендинга, документации, SPA на Vite/React/Vue, сайтов на Astro, Hugo, Next.js в режиме статического экспорта. Данные такой сайт получает из внешних сервисов, запросами из браузера.

Собранный фронтенд сам по себе не делает сайт статическим. Если в репозитории есть свой сервер (Express, Fastify, NestJS), который отдаёт и API, и собранный фронтенд, выбирайте «Сервер с HTTP». То, что фронтенд написан на React, ничего не меняет.

Ошибка в эту сторону ломает приложение незаметно: сборка проходит, домен работает, но на все запросы, включая /api/…, приходит index.html. Ваш сервер при этом не запускается вообще.

Папка сборки

Единственная дополнительная настройка типа. Это относительный путь от корня репозитория до папки, куда сборка кладёт готовые файлы:

ИнструментОбычная папка
Vitedist
Create React App, Astrobuild или dist
Next.js (статический экспорт)out
Hugo, Jekyllpublic или _site

По умолчанию подставляется dist. Если файлы уже лежат в репозитории готовыми и собирать нечего, укажите папку с ними (. означает корень репозитория). Учтите: сборщик всё равно должен определить проект по файлу-манифесту в корне, обычно это package.json. Иначе развёртывание завершится ошибкой «Не поняли, чем собирать проект».

Что происходит при развёртывании

  1. Репозиторий собирается обычным способом: сборщик определяет стек, ставит зависимости и выполняет сборку (для Node.js это скрипт build).
  2. Из результата берётся указанная папка сборки.
  3. Её содержимое копируется в образ с nginx, который и отдаёт файлы по вашему домену.

Отсюда особенности статического сервиса:

  • Порт не задаётся. HTTP отдаёт nginx платформы, а не ваш код, поэтому поля порта у этого типа нет и переменная PORT в коде не нужна. Требование «слушать PORT на 0.0.0.0» относится только к типу «Сервер с HTTP».
  • Команда запуска не нужна. Скрипт start не используется, запускать нечего.
  • Клиентский роутинг работает. Любой путь, для которого нет файла, отдаёт index.html, поэтому ссылка вида /about открывается напрямую и после перезагрузки страницы.
  • Домен и HTTPS выдаются как обычному Web-сервису, можно подключить собственный домен.
  • Подключиться к базе данных проекта нельзя: подключаться нечему, процесса нет, а браузер во внутреннюю сеть проекта не ходит. Если сайту нужен свой API, добавьте в проект второй сервис типа «Сервер с HTTP», см. «Связь сервисов».
  • Сборка по Dockerfile к этому типу не применяется: Dockerfile сам задаёт, что запускать в контейнере.

Переменные окружения

У статического сайта все переменные окружения используются на сборке, а не во время работы: контейнер с вашим кодом не запускается, читать их некому. Значения подставляет сборщик фронтенда, и попадают они прямо в собранные файлы.

Отсюда два правила:

  • Изменение переменной требует нового развёртывания. Быстрый перезапуск ничего не даст: значения уже вшиты в файлы.
  • Секретов в переменных быть не должно. Всё, что попало в сборку, скачивается браузером и доступно любому посетителю. Это не особенность платформы, а свойство фронтенда: ключи API с правами на запись, пароли и токены держите на серверной стороне.

Сборщики подставляют не любые переменные, а только со своим префиксом: VITE_ у Vite, NEXT_PUBLIC_ у Next.js, REACT_APP_ у Create React App. Переменная без нужного префикса до кода не дойдёт. Как задавать переменные, описано в статье «Переменные окружения и секреты».

Если тип выбран неверно

Тип можно изменить, пока не прошло ни одного успешного развёртывания: в настройках сервиса, раздел «Тип сервиса». Это и есть выход из ошибки при создании: домен, переменные и deploy key остаются на месте.

После первого успешного развёртывания тип фиксируется. Чтобы сменить его, создайте новый сервис.

Что выбралиЧто было на самом делеКак это выглядит
Сервер с HTTPЧистая статикаСборка проходит, но контейнер не стартует: запускать нечего. Видно сразу, чинится сменой типа
Статический сайтПриложение со своим серверомСборка проходит, домен отвечает, но на любой запрос приходит index.html, а POST возвращает 405. Ваш код не выполняется

Вторая ошибка тихая, поэтому по умолчанию предлагается «Сервер с HTTP»: промах в эту сторону заметен сразу.

Частые ошибки

СимптомПричинаРешение
Домен отдаёт index.html вместо ответа APIДля приложения со своим сервером выбран тип «Статический сайт»Смените тип на «Сервер с HTTP», а если развёртывание уже прошло, пересоздайте сервис
Развёртывание завершается, контейнер не поднимаетсяНаоборот: для чистой статики выбран «Сервер с HTTP»Смените тип на «Статический сайт»
Развёртывание падает уже после успешной сборки или домен отдаёт 404Указана папка, которой нет в результате сборки, либо в ней нет index.htmlСверьте путь с конфигурацией сборщика (dist, build, out)
Развёртывание падает: «Не поняли, чем собирать проект»В корне репозитория нет файла-манифестаДобавьте package.json (или манифест своего стека) и проверьте, что он закоммичен
Изменил переменную, на сайте старое значениеЗначения вшиваются на сборкеРазверните сервис заново
Переменная не видна в кодеНет префикса сборщикаПереименуйте: VITE_…, NEXT_PUBLIC_…, REACT_APP_…
Сайт не может подключиться к базе данных проектаУ статики нет серверного процесса, браузер во внутреннюю сеть не ходитДобавьте отдельный сервис с API, см. «Связь сервисов»

Дальше