Nuxt 3 — не просто фреймворк для страниц: внутри него живёт серверный движок Nitro, который решает, что отдать сразу готовым HTML, а что дорисовать на сервере при каждом запросе. Из-за этого деплой Nuxt выглядит сложнее, чем публикация статики: нужно выбрать режим, правильно отдать порт и не вынести секреты в браузер. Ниже — путь от папки с кодом до рабочей HTTPS-ссылки на Dockbox без аренды сервера, nginx и ручных сертификатов.
Два режима Nuxt: что вы публикуете на самом деле
Nuxt 3 собирается в двух принципиально разных режимах, и от выбора зависит всё остальное.
Статика (SSG). Команда nuxt generate заранее превращает страницы в готовые HTML-файлы и складывает их в .output/public. Это обычный набор файлов: он открывается мгновенно, ничего не держит процесс и не может упасть.
Сервер (SSR). Обычный nuxt build оставляет серверную часть: приложение становится Node-приложением на движке Nitro, которое слушает порт и отвечает на каждый запрос. Только в этом режиме работают папка server/api, запросы к базе, обработка форм и контент, вычисляемый под конкретного посетителя.
Как выбрать. Если проект только показывает контент — лендинг, блог, портфолио, документация — хватит статики. Если есть серверные маршруты, авторизация, база или персонализация, нужен серверный режим.
Шаг 1. Соберите статику локально или отдайте сборку платформе
Для статического варианта запустите на своей машине:
npm run generate
Nuxt положит готовые страницы в .output/public, и содержимое этой папки — ваш сайт. Его можно загрузить архивом, и платформа отдаст файлы по публичной HTTPS-ссылке. Это единственный случай, когда сборка идёт на вашей машине: в серверном режиме сборку выполняет платформа, а вы загружаете исходники. Чтобы обновить статический сайт, сгенерируйте страницы заново и залейте новую версию — ссылка останется прежней.
Шаг 2. Оставьте порт и адрес платформе
В серверном режиме сайт откроется только если приложение слушает там, где его ждут: порт берётся из переменной окружения PORT, а адрес должен быть 0.0.0.0, а не localhost. Nitro делает это правильно по умолчанию, поэтому ваша задача — убрать то, что вы дописали сами.
Проверьте nuxt.config и .env на жёстко вписанный порт 3000 и хост localhost:
nitro: {
devServer: { port: 3000 }
}
Захардкоженный порт — причина номер один, по которой ссылка после публикации не открывается: контейнеру порт выдаёт платформа, а приложение упрямо стучится в свой. Локальные настройки разработки в конфиге стоит закомментировать или перенести в отдельный файл.
Шаг 3. Пропишите пресет и start-скрипт
Сборка Nuxt кладёт приложение в папку .output, и запускается оно из файла .output/server/index.mjs. Убедитесь, что в nuxt.config не переопределён пресет Nitro — по умолчанию нужен node-server:
nitro: {
preset: 'node-server'
}
Затем добавьте в package.json явный start, чтобы платформа точно знала, чем поднимать проект:
"scripts": {
"build": "nuxt build",
"start": "node .output/server/index.mjs"
}
Скрипт build обычно уже есть, и платформа выполнит его сама при публикации — собирать проект у себя в серверном режиме не нужно.
Шаг 4. Разделите runtimeConfig на серверную и публичную части
В Nuxt значения из runtimeConfig делятся на две группы, и разница здесь принципиальная.
Внутри public — всё, что уезжает в браузер вместе со страницей. Эти значения видит любой посетитель, поэтому там место только безобидным вещам: адрес внешнего API, имя проекта.
runtimeConfig: {
apiSecret: '',
public: {
apiBase: '/api'
}
}
Снаружи public — ключи, токены и строки подключения к базе. Они остаются на сервере и в браузер не попадают. Сами значения в код не вписывайте: их задают при настройке проекта, они передаются как переменные окружения и хранятся зашифрованно. Nuxt подхватывает их по своим правилам: серверное значение apiSecret читается из NUXT_API_SECRET, публичное apiBase — из NUXT_PUBLIC_API_BASE.
NUXT_API_SECRET=super-secret
NUXT_PUBLIC_API_BASE=https://api.example.com
Файл .env при этом ни в архив, ни в репозиторий не кладите: всё, что в нём лежит, переносится в раздел переменных окружения панели.
Шаг 5. Загрузите код и получите ссылку
Проект можно отправить ZIP-архивом или подключить GitHub-репозиторий, включая приватный. Если загружаете исходники, не включайте в архив node_modules, .nuxt и .output — зависимости платформа поставит сама, а лишние папки только раздувают загрузку.
Дальше платформа собирает проект, запускает его и отдаёт публичную HTTPS-ссылку. Логи и статус публикации видны в панели в реальном времени, поэтому ошибка сборки проявляется сразу, а не пустой страницей. Обновление уезжает тем же путём, адрес остаётся прежним.
Сколько это стоит и как работают контейнеры
Своим сервером и nginx заниматься не нужно: контейнеры работают постоянно, без «засыпания» и без ограничений по часам. Упавший контейнер платформа перезапускает сама, а логи остаются в панели.
Starter — 990 ₽/мес. 1 vCPU, 2 GB RAM, 20 GB SSD. Первый месяц бесплатный. Одного Nuxt-проекта с серверным рендерингом это покрывает с запасом.
Pro — 2 490 ₽/мес. 2 vCPU, 4 GB RAM, до пяти проектов — если проектов несколько или нужен запас ресурсов.
Team — 4 990 ₽/мес — для команд, которым нужен запас и SLA.
Свой Dockerfile поддерживается, но не обязателен: Nuxt платформа распознаёт по package.json. Тарифы — на dockbox.host.
Частые вопросы
Чем отличается nuxt generate от обычной сборки?
nuxt generate вычисляет страницы заранее и записывает их готовыми файлами — получается статический сайт, которому не нужен запущенный процесс. Обычный nuxt build оставляет серверную часть, и сайт становится Node-приложением, которое слушает порт и отвечает на каждый запрос. Серверные маршруты из server/api, доступ к базе и контент под конкретного посетителя существуют только во втором варианте.
Можно ли обойтись без Vercel?
Да. Nuxt не привязан к одной платформе: в серверном режиме это обычное Node-приложение, а после nuxt generate — обычная папка готовых страниц. Dockbox принимает оба варианта: загружаете код архивом или из GitHub и получаете публичную HTTPS-ссылку.
Сборка проходит, а ссылка не открывается — почему?
Чаще всего порт или адрес заданы вручную: приложение слушает 3000 или localhost, тогда как платформа ждёт ответа на своём порту из PORT и на 0.0.0.0. Уберите эти значения из nuxt.config и .env. Вторая причина — приложение вообще не стартовало, и это прямым текстом написано в логах панели.
Куда девать .env?
Файл не кладите ни в архив, ни в репозиторий. Значения вводите при настройке проекта: они передаются как переменные окружения и хранятся зашифрованно. Nuxt подхватывает их в runtimeConfig по своим правилам именования — серверное apiSecret из NUXT_API_SECRET, публичное apiBase из NUXT_PUBLIC_API_BASE.
Попадают ли ключи из runtimeConfig в браузер?
Всё, что лежит под public, уезжает в браузер вместе со страницей, и любой посетитель может эти значения прочитать. Остальной runtimeConfig остаётся на сервере и наружу не отправляется. В статическом режиме сервера нет вообще, поэтому всё, что вшито в сгенерированные страницы, становится публичным — секретные ключи в статическую сборку попадать не должны.