Svelte-приложение после сборки — это набор статических файлов, а SvelteKit умеет и статику, и серверный рендеринг. От этого зависит всё остальное в деплое: что собирает платформа и как проект отвечает на запросы. Одна ловушка при этом попадается чаще прочих — адаптер: без правильного значения в svelte.config.js сборка останавливается с сообщением «could not detect a supported production environment». Ниже — путь от папки с кодом до рабочей HTTPS-ссылки на Dockbox и то, что стоит поправить в конфигурации заранее.
Почему деплой Svelte упирается в сборку и адаптер
Привычный сценарий начинается с аренды сервера: поставить Node.js нужной версии, собрать проект, отдать готовые файлы через nginx или держать процесс в фоне, настроить прокси, выпустить сертификат и проследить, чтобы всё поднялось после перезагрузки. Для одного сайта это несколько вечеров, потраченных на всё, кроме самого приложения.
Сборка перед каждой загрузкой. Браузер не исполняет .svelte-файлы, ему нужны готовые JS и CSS, поэтому без шага сборки деплой не начинается.
Адаптер. У SvelteKit в конфигурации стоит adapter-auto, который угадывает хостинг по окружению и на незнакомой площадке останавливает сборку.
SSR или статика. SvelteKit собирает либо пачку prerendered-страниц, либо Node-приложение, которое отвечает на запросы. Это два разных режима запуска.
Секреты в бандле. Всё, что попадает во фронтенд-сборку, видно любому посетителю в исходнике страницы, и ключи оказываются там быстрее, чем кажется.
Порт и адрес. Приложение должно слушать порт из переменной окружения и адрес 0.0.0.0, а не localhost.
Платформа деплоя берёт эту часть на себя: вы отдаёте исходники, она видит по package.json, что это Node.js-проект, ставит зависимости, собирает и отдаёт публичную HTTPS-ссылку. Ни nginx, ни ручного сертификата.
Шаг 1. Определите, что у вас: Svelte или SvelteKit
Откройте package.json. Если в зависимостях только svelte и vite, а сборка кладёт результат в папку dist, это обычное Svelte-приложение, и результат его сборки — статический сайт: страницы, скрипты, стили. Если в зависимостях есть @sveltejs/kit, у вас SvelteKit, и ему нужно явно сказать, во что собираться. Отличается ровно один шаг, всё остальное одинаково.
Шаг 2. Выберите адаптер: статика или Node
Адаптер — строка конфигурации в svelte.config.js, которая говорит сборке, что производить на выходе.
Нет серверной части — ни данных, загружаемых на сервере, ни форм, обрабатываемых на сервере: берите adapter-static и включите пререндеринг в корневом layout-файле.
import adapter from '@sveltejs/adapter-static';
export default { kit: { adapter: adapter() } };
export const prerender = true;
Серверная часть есть — серверные маршруты, form actions, данные, которые браузер видеть не должен: нужен adapter-node. Он пишет готовый сервер в папку сборки, запускается командой node build, поэтому добавьте её скриптом запуска.
import adapter from '@sveltejs/adapter-node';
export default { kit: { adapter: adapter() } };
"scripts": {
"build": "vite build",
"start": "node build"
}
Шаг 3. Уберите «чужие» адаптеры
Свежий проект SvelteKit идёт с adapter-auto. Он определяет хостинг по окружению и на незнакомой площадке останавливает сборку сообщением о неподдерживаемом production-окружении. Адаптеры под конкретный сервис — vercel, netlify, cloudflare — не соберутся по той же причине: они готовят результат под чужую платформу, а не под обычный сервер.
Замените их на node или static: это штатные адаптеры SvelteKit, и они работают на любом обычном сервере, в том числе у нас. Плохой вариант:
import adapter from '@sveltejs/adapter-auto';
Правильный:
import adapter from '@sveltejs/adapter-node';
Шаг 4. Порт приложение берёт из переменной PORT
Приложение должно слушать порт, который платформа передаёт в переменной окружения PORT, и адрес 0.0.0.0, а не localhost. Адаптер для Node уже делает это сам, поэтому в коде порт не задаётся — следите только, чтобы в команде запуска не оказалось зашитого числа. Жёстко прописанный порт — причина номер один, по которой сборка проходит, а ссылка открывается пустой страницей. Со статическим адаптером порт вообще не важен: отдаются обычные файлы.
Шаг 5. Секреты — в переменные окружения, публичное — с префиксом PUBLIC_
Токены, ключи сторонних API и строку подключения к базе не держите в коде и в .env внутри архива. Платформа запрашивает эти значения при настройке проекта и подставляет их переменными окружения, храня в зашифрованном виде. В серверном коде SvelteKit значения читаются из окружения обычным способом, а всё, что нужно браузеру, обязано иметь префикс PUBLIC_ — без него переменная до клиента просто не доедет.
DATABASE_URL=postgres://app:***@db:5432/app
PUBLIC_API_URL=https://api.example.com
Помните, что значения с префиксом PUBLIC_ запекаются в готовые файлы: адрес API там уместен, настоящий ключ — нет.
Шаг 6. Загрузите код и получите ссылку
Проект попадает на платформу архивом или импортом репозитория GitHub, включая приватный. node_modules, dist, build и .svelte-kit в архив не кладите: зависимости платформа ставит сама, а сборку выполняет на своей стороне, так что загрузка остаётся лёгкой. Логи и статус сборки видны в панели в реальном времени, а после успешного запуска вы получаете публичную HTTPS-ссылку.
Сколько это стоит и как работают контейнеры
Принципиальная разница с VPS: администрировать сервер не нужно. Контейнеры работают постоянно, без ограничения по часам и без «засыпания». Упавший контейнер платформа перезапускает сама, и приложение возвращается в строй без вашего участия.
Starter — 990 ₽/мес. 1 vCPU, 2 GB RAM, 20 GB SSD, один проект. Первый месяц бесплатный. Для одного SvelteKit-приложения этого достаточно, и лимита по времени работы у тарифа нет.
Pro — 2 490 ₽/мес. 2 vCPU, 4 GB RAM, до пяти проектов.
Team — 4 990 ₽/мес — для команд, которым нужен запас ресурсов и SLA.
Свой Dockerfile поддерживается, но не обязателен: стек платформа определяет по коду сама. Нужна база рядом с приложением — поднимите её отдельным сервисом в своём docker-compose с именованным томом, чтобы данные пережили обновление кода.
Частые вопросы
Чем деплой SvelteKit отличается от обычного Svelte?
Обычное Svelte-приложение собирается в папку файлов, которую достаточно отдать как статический сайт. SvelteKit умеет и так: он собирает либо prerendered-страницы, либо Node-приложение с серверной частью. Что именно получится, решает адаптер в конфигурации.
Какой адаптер SvelteKit выбрать?
Если весь сайт можно отрисовать заранее и ничего не считается под конкретный запрос — adapter-static, такие страницы загружаются быстрее всего. Если есть серверные маршруты, обработка форм на сервере или данные, которые не должен видеть браузер, — adapter-node. Оба работают на обычном сервере и на нашей платформе.
Почему сборка падает на adapter-auto?
Этот адаптер определяет хостинг по окружению и знает лишь несколько конкретных сервисов. На любом другом сервере он не находит знакомых признаков и останавливает сборку сообщением о том, что не смог определить поддерживаемое production-окружение. Лечится заменой на adapter-node или adapter-static.
Почему внутренние страницы дают 404 при обновлении?
Статическая сборка записывает только те страницы, которые SvelteKit сумел отрисовать заранее. Если часть маршрутов рисуется в браузере, включите fallback в настройках статического адаптера: тогда по любому адресу отдаётся эта страница, а маршрут разрешает само приложение. Второй вариант — пререндерить все страницы.
Нужно ли ставить Node.js самому и можно ли подключить базу?
Ставить и настраивать Node.js не нужно: платформа узнаёт проект по package.json и поднимает всё сама. С базой тоже нет проблем: можно взять внешнюю и передать строку подключения секретом либо поднять базу рядом сервисом в своём docker-compose — данные в именованном томе переживут обновление кода.