
Публикация сайта: что именно переносится на сервер
Разбираем путь сайта от исходников до домена: что такое сборка, какие файлы публиковать, какую роль выполняют сервер, Nginx и DNS.
Содержание
До публикации у владельца сайта есть исходные файлы: шаблоны, стили, тексты и настройки сборки. Посетителю они обычно не нужны. Его браузер получает готовые HTML, CSS, JavaScript и изображения либо ответ работающего серверного приложения. Поэтому сначала важно понять тип сайта и только затем решать, какие файлы переносить на сервер.
Как выглядит путь от исходников до страницы
Разработчик меняет исходники и запускает проверку. Сборщик создаёт каталог с готовыми HTML, CSS, JavaScript и изображениями. Его переносят в отдельный каталог релиза, после чего Nginx начинает отдавать выбранную версию. DNS направляет домен на сервер, а TLS защищает соединение. Production не должен быть единственным местом хранения исходников.
За что отвечает каждая часть
У простого сайта есть пять разных частей:
- Исходники — компоненты, шаблоны, стили, данные и сценарии сборки.
- Зависимости — пакеты, необходимые инструментам и приложению.
- Результат сборки, или артефакт — готовые HTML, CSS, JavaScript, изображения и служебные файлы.
- Сервер публикации — каталог, из которого веб-сервер читает готовые файлы, либо процесс приложения.
- Адрес сайта — домен, DNS, HTTP/HTTPS и сертификат.
Ошибка в каждой части выглядит по-разному. Синтаксическая ошибка останавливает build. Неверный DNS ведёт не на тот адрес. Неправильный root Nginx даёт 404. Недостаточные права приводят к 403. Не запущенное серверное приложение вызывает 502 через reverse proxy.
Исходники и готовый сайт — не одно и то же
Ниже показана упрощённая структура собираемого проекта. Названия app и build условны: в реальном проекте их нужно взять из документации и конфигурации сборщика.
project/
├── app/ # редактируемые исходники
├── public/ # общедоступные ресурсы без обработки
├── package.json
├── package-lock.json
└── build/ # пример готового артефакта
В app находятся редактируемые исходники. Каталог public содержит только ресурсы, которые можно публиковать без обработки. package.json описывает команды и зависимости, а lock-файл фиксирует их дерево. build в этом примере создаётся заново и не редактируется вручную.
Nginx не превращает компоненты выбранного фреймворка в HTML. Он читает уже собранный index.html и связанные ресурсы. Поэтому копирование одних исходников без production build не публикует статическую версию сайта.
Определите тип проекта
Статический сайт
Все страницы подготавливаются заранее. В production нужны готовые файлы и веб-сервер. Постоянно работающий Node.js обычно не требуется. Такой вариант проще обслуживать и имеет меньшую поверхность атаки.
Серверное приложение
Страница или API формируются во время запроса. На сервере работает процесс приложения, например systemd-служба, а Nginx передаёт ему запросы. Здесь нужно публиковать код или собранное приложение, устанавливать production-зависимости, передавать окружение и контролировать запуск процесса.
Сайт с внешним API
Интерфейс может быть статическим, а данные получать из отдельного сервиса. Тогда публикация HTML не гарантирует работу продукта: smoke-тест должен проверить и доступ к API, и правила CORS, и обработку ошибок.
Не определяйте тип по наличию JavaScript в браузере. Статическая страница тоже может содержать интерактивный клиентский код.
Где собирать готовые файлы
Есть два практичных варианта:
- Локально или в системе автоматической проверки (CI). На сервер передаётся только проверенный артефакт. Рабочему серверу не нужны инструменты разработки, зато сборку следует уметь повторить с теми же версиями зависимостей.
- На отдельном каталоге VPS. Сервер получает репозиторий, выполняет
npm ciиnpm run build, затем публикует результат. Это проще для небольшого проекта, но зависимости и сборочные сценарии выполняются на production-узле.
В обоих случаях сборка не должна перезаписывать каталог, который прямо сейчас обслуживает Nginx. Сначала готовится новый релиз, затем после проверок атомарно меняется указатель current.
Не смешивайте рабочую копию и production
В рабочей копии находятся исходники, dev-зависимости и тестовые настройки. Сборочная среда получает чистую ревизию и lock-файл, выполняет проверки и создаёт один артефакт. Production получает этот артефакт и необходимые runtime-настройки, но не локальные заметки, кеш пакетного менеджера и ключи разработчика.
Такое разделение даёт конкретную проверку: контрольная сумма опубликованного каталога должна совпасть с проверенной сборкой. Если сайт собирается непосредственно на VPS, рабочая копия всё равно должна находиться вне каталога Nginx, а переключение выполняется только после успешного build.
Как запрос доходит до страницы
Последовательность для посетителя выглядит так:
- Браузер запрашивает адрес домена у DNS.
- Соединяется с IP на порту 443.
- Проверяет TLS-сертификат и имя сайта.
- Отправляет HTTP-запрос с нужным путём.
- Nginx выбирает
serverпо адресу иserver_name. - Статический файл читается с диска или запрос передаётся приложению.
- Ответ возвращается браузеру.
Поэтому «домен открывается» ещё не означает, что опубликована новая версия. DNS мог вести на старый сервер, браузер — использовать кеш, а Nginx — читать другой каталог.
Первый понятный порядок публикации
Откройте терминал в корне проекта на рабочем компьютере. Команды ниже устанавливают зависимости по lock-файлу, запускают штатную проверку проекта и создают готовый каталог сборки:
npm ci
npm run check
npm run build
После этого осмотрите каталог, указанный сборщиком, запустите локальный preview и только затем передавайте файлы на сервер. На VPS подготовьте новый каталог релиза, установите безопасные права, проверьте Nginx и откройте сайт по внешнему адресу.
Не копируйте .git, .env, приватные ключи, локальные заметки и кеши пакетного менеджера в публичный каталог. Если сборке нужны секреты, убедитесь, что они не встроились в клиентский JavaScript или HTML.
Как понять, где ошибка
Проверяйте слои снизу вверх:
| Симптом | Первый вопрос |
|---|---|
| build завершился ошибкой | проходит ли та же команда локально с lock-файлом |
| домен не находится | корректны ли DNS-записи |
| соединение отклонено | слушает ли порт и разрешён ли он firewall |
| 404 | какой root и существует ли файл |
| 403 | может ли пользователь Nginx пройти путь и прочитать файл |
| 502 | запущено ли приложение и доступен ли upstream |
| видна старая версия | переключён ли релиз и какие Cache-Control заголовки |
Сохраняйте commit и идентификатор релиза. Тогда проверка покажет не абстрактное «вроде обновилось», а конкретную версию.
Что считать успешной публикацией
Успех — это не только код ответа 200 у главной страницы. Должны пройти:
- локальная сборка без ошибок;
- проверка обязательных файлов в результате;
- чтение файлов веб-сервером без права записи;
- несколько ключевых URL по HTTPS;
- загрузка CSS, JavaScript и изображений;
- проверка маркера ожидаемого commit;
- возможность быстро вернуть предыдущий релиз.
Разделение исходников и артефакта закрепите в структуре репозитория. Готовый каталог сначала проверяют локально, затем передают на сервер по процедуре ручной публикации.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Нужно ли копировать на сервер весь каталог проекта?
Для статического сайта обычно публикуют только готовый каталог сборки. Исходники и зависимости нужны в сборочной среде, но не должны автоматически попадать в публичный каталог Nginx.
Чем домен отличается от сервера и хостинга?
Домен — удобное имя, DNS связывает его с адресом, сервер хранит или запускает сайт, а веб-сервер принимает HTTP-запросы. Это разные части одной цепочки, которые проверяются отдельно.
Когда приложению нужен запущенный Node.js на production?
Когда страницы формируются по запросу или работает серверный API. Полностью статический результат можно отдавать напрямую через Nginx без постоянно запущенного процесса Node.js.


