Самый быстрый путь к работающему приложению на новом сервере - не писать приложение с нуля, а начать с небольшого репозитория, который уже делает четыре вещи, которых требует хостинг: слушает 0.0.0.0 на выданном порту, имеет скрипт запуска или входной файл, который находит среда выполнения, фиксирует версию среды, доступную на сервере, и не пускает секреты в Git. Дальше вы превращаете его в своё приложение по одному коммиту. Создайте репозиторий из шаблона, укажите его серверу, нажмите deploy - и первый запуск покажет рабочую страницу, а не стек ошибки. Всё остальное - обычная разработка: вы делаете push, сервер забирает код и перезапускается.
В этой статье: что такое стартовый шаблон и чем он отличается от страницы-заглушки, которую показывает новый сервер; правила, которым следует каждый шаблон, и почему; пошаговый путь от пустого сервера до работающего приложения; что внутри каждого из шести шаблонов, которые мы поддерживаем (Next.js, Express, Discord-бот, Telegram-бот, FastAPI и статический сайт); как дорабатывать их, не ломая деплой; и как включить деплой при каждом push. Большая часть применима на любом хостинге, который деплоит из Git; части про RE:NODE помечены отдельно.
Шаблон, стартовая страница, приложение в один клик: три разные вещи#
Словом "стартовый" называют несколько разных вещей, и именно путаница между ними вызывает большую часть недоразумений в первый день.
Шаблонный репозиторий GitHub - обычный репозиторий, в настройках которого стоит одна галочка. Вместо форка вы нажимаете Use this template, и GitHub создаёт в вашем аккаунте совершенно новый репозиторий с теми же файлами и чистой историей. Связи с оригиналом нет, upstream синхронизировать не нужно, ваших коммитов никто не видит. Он ваш с первой секунды. Это правильная форма для стартового набора: вы не вносите вклад в шаблон, а берёте его как каркас.
Стартовая страница - то, что показывает новый пустой сервер со средой выполнения, пока вы ничего не задеплоили. На RE:NODE каждая линейка сред, кроме Node.js, запускается с небольшой рабочей страницей на своём адресе, пока вы не задеплоите код, и она никогда не затирает ваши файлы. Она нужна, чтобы первый запуск свежего сервера говорил "вот что делать дальше", а не падал с Cannot find module './index.js'. Это не приложение, на котором можно строить: деплой вашего репозитория её заменяет.
Приложение в один клик - готовый продукт, который устанавливают за вас: WordPress на линейке web, Ghost и Strapi на линейке app. Их настраивают, но не пишут. Если вам нужен блог, один из них - более короткий путь, и лучше сразу прочитать руководство по Ghost или руководство по Strapi.
Стартовый шаблон находится между ними: настоящий код, достаточно маленький, чтобы прочитать его за пять минут, и уже подготовленный под сервер, на который он попадёт.
Четыре правила, которым следует каждый шаблон#
Хостинговый сервер приложений - не ваш ноутбук. Он запускает один процесс в контейнере, даёт этому процессу ровно один публичный порт и каждый раз запускает процесс одинаково. Почти любой неудачный первый деплой нарушает одно из правил ниже, поэтому каждый шаблон построен вокруг них.
| Правило | Как это выглядит | Что ломается без него |
|---|---|---|
Слушать 0.0.0.0 на выданном порту | SERVER_PORT из окружения | Приложение работает, но никто не может достучаться |
| Запуск, который находит среда | скрипт start или app.py | Падение при старте, запускать нечего |
| Зафиксированная версия среды | .nvmrc, .python-version | Локально работает, на сервере нет |
| Секреты вне Git | .env в .gitignore | Токены утекают в репозиторий |
Порт. В панели на базе Pterodactyl порт вашего сервера передаётся процессу как переменная окружения SERVER_PORT. Наши шаблоны на Node.js и Python также используют запасной вариант PORT, который применяют многие платформы, а затем локальное значение по умолчанию, чтобы тот же файл запускался и на вашей машине. Адрес важен не меньше порта: приложение, которое слушает localhost или 127.0.0.1, отвечает только внутри своего контейнера. В консоли оно выглядит здоровым, но из интернета недоступно. 0.0.0.0 означает все интерфейсы, и только этот адрес работает.
Запуск. Среде нужно знать, что запускать. Для Node.js это скрипт start в package.json. Для Python это файл, указанный на вкладке Startup, по умолчанию app.py, который запускается после установки requirements.txt. Серверу веб-хостинга не нужно ни то ни другое: его собственный веб-сервер отдаёт index.html из корня сайта.
Версия. .nvmrc и .python-version указывают, под какую основную версию написан код. Сервер всё равно запускает ту версию, которая выбрана в поле Runtime version на вкладке GitHub, так что файл - это напоминание и проверка, а не переключатель. Но предстартовая проверка читает его и сообщает, если они расходятся, а это очень выручает, когда Next.js перестаёт поддерживать выбранную вами версию.
Секреты. Каждый шаблон содержит .env.example с названиями настроек и фиктивными значениями, а также .gitignore, который не пускает настоящий .env в репозиторий. Реальные значения вы вносите на сервере. Подробнее о том, почему и как, - в статье про переменные окружения и секреты.
Шесть шаблонов и что они запускают#
Мы поддерживаем шесть репозиториев-шаблонов, каждый из которых собран и проверен на собственной предстартовой проверке панели, так что репозиторий, созданный из шаблона, не выдаёт ни одного замечания. Они предлагаются только на серверах с подходящей средой.
| Шаблон | Для какого сервера | Что вы получаете |
|---|---|---|
| Next.js | Node.js, Node 22 | Сайт на App Router с маршрутом health |
| Express API | Node.js, Node 22 | JSON API: /, /health, /echo |
| Discord bot | Node.js, Node 22 | Бот на discord.js с командой /ping |
| Telegram bot | Python, 3.12 | Эхо-бот на long polling |
| FastAPI | Python, 3.12 | API с документацией на /docs |
| Static site | Веб-хостинг | HTML и CSS, собирать нечего |
Шаблонов для Bun, Deno, Go, Java, Rust, .NET и Laravel пока нет. Шаблоны на Node читают .env вызовом, который есть только в Node, и фиксируют версию Node, а для Bun нет гарантии, что она будет соблюдена; мы предпочитаем не предлагать ничего, чем шаблон, который не проверяли. Как запускать эти среды из пустого репозитория, описано в последнем разделе.
От пустого сервера до работающего приложения, шаг за шагом#
Это весь путь для шаблона Express на сервере Node.js. Остальные шаблоны отличаются только тем, какой сервер вы заказываете и какие настройки заполняете.
- Закажите сервер, который запускает ваш код, - для Express это тариф Node.js из раздела хостинг приложений. Он создаётся после подтверждения оплаты, обычно за минуту.
- Откройте вкладку GitHub сервера и нажмите Connect GitHub. Это установит GitHub App RE:NODE в ваш аккаунт и позволит выбрать, какие репозитории он будет видеть. App использует краткоживущие токены, поэтому приватные репозитории работают.
- В разделе Start from a template нажмите Use template у Express API. Откроется страница GitHub "создать репозиторий из шаблона" с предложенным именем. Выберите владельца, публичный или приватный репозиторий и создайте его. Сама панель ничего в вашем аккаунте не создаёт - это делает GitHub, где вы уже вошли.
- Вернитесь на вкладку панели. Список репозиториев обновляется, когда вкладка снова получает фокус. Если вы открыли App только выбранные репозитории, сначала добавьте новый в разделе Manage repository access.
- Выберите репозиторий, оставьте рабочую ветку
mainи выберите Runtime version - Node 22 для всех шаблонов на Node. - Нажмите Deploy. Панель запросит подтверждение, потому что это переустанавливает сервер из репозитория. На новом сервере терять нечего.
- Запустите сервер. В консоли появится установка зависимостей, затем
Listening on 0.0.0.0:и ваш порт. - Откройте адрес и порт сервера в браузере. Вы получите небольшой JSON-ответ с сообщением и именем приложения.
Вот и все пять минут. Дольше всего обычно длится шаг 3 - придумывание названия для репозитория.
Если вместо адреса с портом вы хотите использовать домен, это делает слот прокси на тарифах app: направьте A-запись на показанный адрес, и сертификат будет выпущен и продлеваться автоматически. Приложение по-прежнему слушает свой порт; прокси стоит перед ним, а настоящий IP клиента приходит в X-Forwarded-For.
Что внутри каждого шаблона#
Каждый шаблон намеренно мал. Смысл в том, чтобы вы могли прочитать его целиком, прежде чем что-то менять.
Express API
server.js читает необязательный .env, настраивает три маршрута и начинает слушать порт. Важна последняя часть:
const port = Number(process.env.SERVER_PORT || process.env.PORT || 3000);app.listen(port, '0.0.0.0', () => { console.log(`Listening on 0.0.0.0:${port}`);});.env читается встроенным в Node 22 вызовом process.loadEnvFile(), так что зависимости dotenv нет. npm run start запускает node server.js; собирать ничего не нужно. О том, что делать после шаблона - обработка ошибок, логирование, правильный запуск, - см. деплой Express API в продакшен.
Next.js
Шаблон Next.js - это сайт на App Router с главной страницей и маршрутом /api/health. Его скрипт запуска сначала собирает, а затем отдаёт:
{ "scripts": { "dev": "next dev", "build": "next build", "start": "next build && next start -H 0.0.0.0 -p $SERVER_PORT" }}Сборка при запуске означает, что каждый перезапуск пересобирает сайт. Это медленнее, чем отдавать закоммиченную сборку, но зато сервер всегда запускает именно тот коммит, который забрал, и в Git нет папки .next, которая могла бы устареть. Цена - память: next build - самое прожорливое, что маленький сайт на Next.js делает за день. Если в консоли сборка падает на самом маленьком тарифе, это лимит памяти, а не ошибка: на лимите контейнер останавливают и запускают заново, а не уводят в swap. Следите за графиком памяти во время сборки и берите тариф побольше, если он упирается в линию. Статья деплой Next.js на сервере Node подробнее разбирает standalone-вывод и кеш сборки.
FastAPI
app.py создаёт приложение и сам запускает uvicorn, не полагаясь на командную строку:
if __name__ == "__main__": port = int(os.environ.get("SERVER_PORT", os.environ.get("PORT", "8000"))) uvicorn.run(app, host="0.0.0.0", port=port)Адрес и порт хранятся в коде по причине: сервер Python запускает файл, а файл, который сам запускает свой сервер, нельзя по забывчивости запустить на неправильном адресе из-за пропущенного флага. requirements.txt фиксирует fastapi, uvicorn и python-dotenv на точных версиях и устанавливается перед каждым запуском. Интерактивная документация доступна на /docs с первого запуска. Руководство по деплою FastAPI и Flask рассказывает про воркеры и продакшен-настройки.
Discord bot
Бот на discord.js с одной глобальной слэш-командой /ping. Он читает DISCORD_TOKEN и завершается с понятным сообщением, если токена нет, а не падает где-то внутри библиотеки. Боту не нужен входящий порт, но если он у сервера есть, шаблон отвечает на нём небольшой JSON-проверкой состояния, чтобы монитору доступности было что опрашивать. Он запрашивает у Discord только intent Guilds; чтение содержимого сообщений требует привилегированного intent, который нужно включить на портале разработчиков Discord и добавить в коде. Остальное - в статье хостинг Discord-бота 24/7.
Telegram bot
Эхо-бот на python-telegram-bot, который отвечает на /start и повторяет любой текст. Он использует long polling: бот сам спрашивает у Telegram о новых сообщениях, поэтому до него ничего не должно доходить снаружи, и ему не нужны ни порт, ни домен. Это самая простая схема и правильный выбор по умолчанию; webhooks оправданы только при большом объёме, и у них свои сценарии отказов, описанные в статье диагностика webhook Telegram-бота.
Static site
index.html, 404.html и таблица стилей в корне - для сервера веб-хостинга. Здесь нет скрипта запуска и порта, который нужно занять: собственный веб-сервер отдаёт файлы как есть. Всё, что лежит в корне сайта, посетитель может скачать, поэтому в этом шаблоне нет никаких секретов. Если позже вы перейдёте на сборщик, либо закоммитьте готовый результат сборки, либо укажите в поле Where to put the code папку, где он лежит.
Доработка без поломки деплоя#
Шаблоны созданы для того, чтобы их менять. Одни изменения безопасны всегда, другие требуют внимания.
Можно менять свободно: маршруты, страницы, обработчики, имя приложения, стили, добавление файлов и папок, добавление зависимостей. Добавьте пакет через npm install <name> или строкой в requirements.txt, закоммитьте обновлённый lock-файл или requirements и сделайте push. Сервер установит то, что указано, при следующем запуске. Коммитьте package-lock.json: именно он делает установку на сервере такой же, как у вас на машине. Разница между двумя командами установки описана в статье npm ci или npm install.
Менять осторожно: вызов listen, скрипт start и имя входного файла. Это те самые четыре правила, и именно здесь рефакторинг незаметно ломает работающий сервер. Перенести сервер в src/index.js можно, если start последует за ним. Переименование app.py в main.py означает, что нужно поменять и файл, указанный на вкладке Startup. Если вы оборачиваете приложение во фреймворк, который слушает собственный порт по умолчанию (многие так делают, часто это 3000, 5000 или 8000), порт сервера нужно передать ему явно.
Никогда не коммитить: .env, токены, пароли баз данных, приватные ключи. Скопируйте .env.example в .env на сервере через файловый менеджер или SFTP и впишите туда настоящие значения:
APP_NAME=my-apiDISCORD_TOKEN=paste-the-real-token-hereDATABASE_URL=postgres://user:password@host:port/dbnameПерезапуск или push-деплой сбрасывает файлы, пришедшие из репозитория, и не трогает игнорируемый .env. Переустановка - другое дело: первый деплой или смена версии среды заменяет всё в каталоге. Загрузите .env после первого деплоя и храните копию в надёжном месте - это единственный файл, который свежий деплой воссоздать не может.
Добавление базы данных. Тарифы app включают слоты баз данных, которые создаются в панели с сгенерированными хостом, пользователем и паролем. Строку подключения кладите в .env, а не в код. Если вам нужны приложение, база данных и кеш одним заказом, набор со вкладки Bundles в магазине панели делает это за одну оплату со скидкой.
Перед каждым push, который затрагивает запуск, порт или среду, посмотрите на карточку Pre-flight check на вкладке GitHub. Она читает репозиторий на GitHub - один список дерева и несколько небольших файлов, никакого клонирования - и перечисляет то, что сломается, начиная с худшего, с готовым исправлением: отсутствующий скрипт запуска, приложение, привязанное к localhost или не к тому порту, отсутствующая сборка, несовпадение версии среды, закоммиченный .env (он указывается по имени и никогда не открывается). Шаблон проходит её с первого коммита; карточка показывает, что вы с тех пор ничего не сломали.
Деплой при каждом push#
На вкладке GitHub есть два переключателя, и вместе они определяют, когда новый код выходит в работу.
- Pull the latest commit every time the server starts. Перезапуск забирает ветку и запускает новый код. При push ничего не происходит; вы сами выбираете, когда перезапускать.
- Restart the server when someone pushes to this branch. Работающий сервер перезапускается через несколько секунд после push и возвращается уже на новом коммите. Остановленный сервер запускается, так что push в любом случае выходит в работу.
Для хобби-бота или личного API push-to-deploy - правильный вариант по умолчанию: коммит, push и наблюдение за консолью. Для всего, от чего зависят люди, деплойте из ветки, в которую вы пушите осознанно. Пусть main остаётся местом, куда приходит работа, а рабочей веткой сервера будет что-то вроде production или release, и вливайте в неё, когда действительно хотите выкатить. Каждый деплой записывается, по одной записи на деплой, поэтому на вопрос "что сейчас запущено" есть ответ.
Две вещи нужно знать, прежде чем на это полагаться. Во-первых, папка, указанная в Where to put the code, приводится к состоянию репозитория при каждом запуске: правка, которую вы внесли на живом сервере через файловый менеджер в файл, находящийся в Git, будет отменена при следующем деплое, а переустановка очищает папку целиком. Вносите исправление в Git, а загрузки и данные держите вне папки деплоя - в базе данных или объектном хранилище. Во-вторых, перезапуск остаётся перезапуском. Сайт на Next.js пересобирается, бот переподключается, а запросы, которые были в обработке, теряются. Деплой без простоя на маленьком сервере и корректное завершение работы - следующий шаг, когда это становится важным.
Токен деплоя, с которым панель забирает ваш код, создаётся заново при каждом запуске сервера. Долгоживущего ключа GitHub, который мог бы утечь, на сервере нет.
Когда первый запуск всё же не удался#
Шаблон убирает большинство сбоев первого деплоя, но не все. Вот те, что остаются.
- Страница не загружается, хотя консоль выглядит нормально. Скорее всего, вы открываете не тот порт, либо то, что вы добавили, слушает свой собственный порт. Найдите в консоли номер порта в строке "listening" и сравните его с портом на странице сервера.
- `DISCORD_TOKEN is not set` или `TELEGRAM_BOT_TOKEN is not set`. Шаблоны ботов намеренно останавливаются без токена. Загрузите
.envс этой переменной и перезапустите. - Бот входит в систему, но никто не отвечает. Для Discord бота нужно пригласить на сервер со scope
applications.commands, иначе слэш-команды не появятся. Для Telegram проверьте, что никакая другая копия бота - например, на вашем ноутбуке - не опрашивает Telegram с тем же токеном: два поллера конкурируют за одни и те же обновления. - Установка падает с ошибкой версии. Выбранная на вкладке Runtime version старше, чем нужно коду. Её смена пересоздаёт сервер на новом образе, заменяя файлы в его каталоге содержимым репозитория; базы данных и бэкапы не затрагиваются.
- Сборка Next.js обрывается на середине. Лимит памяти. Посмотрите график памяти во время сборки; решение - тариф побольше или более лёгкая сборка, а не повторная попытка.
- Сервер постоянно падает. Цикл падений замечается: наблюдатель считает сбои, которых вы не вызывали, и три за час добавляют предупреждение на страницу сервера и открывают тикет. Читайте первую ошибку в консоли, а не последнюю.
- Репозитория нет в списке. GitHub App видит только те репозитории, к которым вы дали ему доступ. Добавьте новый репозиторий в разделе Manage repository access.
Нет шаблона для вашего стека#
Для серверов Bun, Deno, Go, Java, Rust, .NET и Laravel шаблонов пока нет, но все они стартуют со страницы-заглушки, а те же четыре правила позволяют пустому репозиторию задеплоиться с первого раза.
Для Go сервер собирает код командой go build при каждом запуске, а неудачная сборка останавливает запуск, а не запускает старый код. Минимальный main.go:
package mainimport ( "fmt" "net/http" "os")func main() { port := os.Getenv("SERVER_PORT") http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "hello") }) http.ListenAndServe("0.0.0.0:"+port, nil)}Закоммитьте его вместе с go.mod, и предстартовая проверка сравнит версию Go в нём с версией на сервере. Более подробно - в статье деплой веб-сервиса на Go.
Для Bun скрипт start в package.json запускается после bun install. Для Deno задача start в deno.json запускается командой deno task start, и учтите, что Deno.serve по умолчанию использует порт 8000, поэтому передайте ему порт сервера. Статья Bun или Deno на маленьком сервере сравнивает их. Для Java подойдёт любой исполняемый jar: Spring Boot, Quarkus, Micronaut или Ktor на Java 17, 21 или 25, с портом из SERVER_PORT.
FAQ#
Нужно ли синхронизировать мой репозиторий с шаблоном?
Нет. Репозиторий, созданный из шаблона GitHub, не связан с ним и не имеет общей истории. Обновления шаблона до вас не доходят, а ваши коммиты не доходят ни до кого. Если в новой версии шаблона исправлено что-то важное для вас, перенесите изменение вручную, как любой другой код.
Может ли мой репозиторий быть приватным?
Да. Выберите private на странице создания в GitHub. Панель деплоит через GitHub App с краткоживущими токенами, поэтому приватные репозитории деплоятся так же, как публичные. Если вы позже включите pull request с контекстом для ИИ, публичный репозиторий получит только общие правила и никаких сведений о вашем сервере.
Удалит ли деплой шаблона то, что уже есть на моём сервере?
Да, деплой переустанавливает сервер из репозитория: файлы в его каталоге заменяются, а всё, что не закоммичено, теряется. Базы данных и бэкапы не затрагиваются. На совершенно новом сервере терять нечего; на сервере, с которым вы уже работали, сначала сделайте бэкап.
Почему мой сервер Node.js не показывает страницу-заглушку?
Страница-заглушка создаётся на каждой линейке сред, кроме Node.js. Новый сервер Node.js запускается пустым, поэтому до первого запуска задеплойте репозиторий - шаблон или свой собственный.
Можно ли использовать шаблон на другом хостинге?
Да. Ничто в них не привязано к одной панели, кроме того, что SERVER_PORT читается первым; затем они переходят на PORT, а потом на локальное значение по умолчанию. Этого хватает для большинства платформ, которые задают переменную порта, и для вашей собственной машины.
Как быстро push попадает в работу?
При включённом push-деплое работающий сервер перезапускается через несколько секунд после push. Общее время зависит от приложения: Express API возвращается почти сразу, а сайт на Next.js пересобирается при запуске и тратит столько, сколько next build занимает на этом тарифе.


