Серия статей про настройку мини платформы для маленьких бэкенд приложений:

В чем сложность

Время от времени я всё-таки дорываюсь до сайд-проектов. Как мобильному разработчику, мне нужен самый скромный бэкенд: отдать JSON, записать пару строк в базу или выполнить простую логику — ничего героического. Но стоит открыть первую ссылку из Google и попробовать сделать «как все советуют», как базовый бэкенд превращается в квест.

Популярные варианты

Есть Cloudflare Workers — мне они правда нравятся, но их SDK сразу диктует edge-архитектуру. Минимальные контейнеры на DigitalOcean быстро превращаются в ощутимый чек, а Fly.io и похожие платформы снова навязывают свои ограничения. Есть ещё Coolify: оно превращает личный сервер в мини-облако и закрывает много угловых случаев, но за это платишь сложностью самого решения. Сервер под него должен быть бодрым, поэтому счёт за инфраструктуру снова улетает вверх и больше подходит для малого бизнеса, чем для воскресных экспериментов.

Нужен минимализм

Хочется варианта настолько дешёвого, что про него можно забыть на год: без особых ограничений, чтобы любой quick start из интернета заводился без танцев и можно было быстро завернуть бэкенд, не думая о технологиях — сегодня на Python, завтра на JavaScript или Swift. При этом добавление ещё одного полумёртвого проекта не должно увеличивать чек и ломать конфигурацию: сервисы просто живут рядом и работают.

Заветный вариант: Hetzner + Dokku + Dockerfile

  • Hetzner/VPS: дешёвый и достаточно надёжный сервер, который всегда работает.
  • Контейнеры: Dockerfile абстрагирует стек — Python, JavaScript и Swift запускаются одинаково.
  • Dokku: лёгкий «менеджер» для контейнеров на сервере — один раз настраиваешь, а потом добавляешь и обновляешь маленькие проекты парой простых команд, не залезая в настройки.
  • Бюджет: около 5 € в месяц + домен (≈1.5 € в год), чтобы выдавать удобные адреса и включить HTTPS.

Инструкция

Дальше покажу, как я настраиваю и использую связку Hetzner + Dokku + Dockerfile. На всё уходит около часа, и в итоге появляется своё мини-облако.

Аренда сервера (VPS)

Провайдер для сервера не так критичен — нам просто нужен маленький Linux-сервер, к которому можно зайти по SSH. Я покажу на примере Hetzner: там адекватное соотношение цены и производительности.

К концу шага у вас должно быть:

  • запущенный Linux-сервер;
  • внешний IP-адрес;
  • пароль или SSH-ключ, чтобы зайти командой ssh root@<ip>.

Сервер в Hetzner Cloud

  1. Захожу в cloud консоль и создаю проект, если его ещё нет.
  2. В проекте нажимаю Create server и выбираю тариф. Я беру CX23 на x86. Есть ещё CAX11 на ARM — он заметно быстрее за те же деньги, но не весь софт дружит с ARM, поэтому для «no stress» варианта останемся на x86.
  3. Локация: выбираю Германию, датацентр Falkenstein. Можно взять ближайший к вам регион (latency тест).
  4. OS: ставлю Ubuntu LTS — под неё больше всего простых гайдов. Если хочется минимализма и есть силы гуглить, можно взять Debian, будет чуть производительнее.
  5. Networking: добавляю внешний IPv4 (для меня это +0.61 € в месяц), потому что домашний провайдер пока не умеет в IPv6. У вас может получиться сэкономить.
  6. SSH: загружаю свой публичный ключ или создаю новый, чтобы логиниться без пароля — это сильно упрощает настройку Dokku.
  7. Остальные галочки (backup, дополнительные диски) пропускаю — к ним можно вернуться позже, отдельная тема.
  8. Жму Create & Buy now, жду, пока сервер поднимется, и проверяю доступ командой ssh root@<ip> -i ~/.ssh/hetzner (-i ~/.ssh/hetzner - ssh ключ, если что-то не так с аттрибутами, попробуйте chmod 600 ~/.ssh/hetzner)

Для таких конфигураций цена получается в районе 3.5–4.5 € в месяц.

Настройка домена

Беру самый бюджетный домен — в зонах вроде .xyz они стоят 1–2 € в год — и настраиваю DNS прямо у регистратора. Если панели нет, подключаю бесплатный Cloudflare DNS.

  1. Открываю управление доменом.
  2. Создаю wildcard-запись *.chenchik.me (A/AAAA) и указываю IP своего сервера.

Теперь любой поддомен вроде helloworld.chenchik.me резолвится в мой VPS.

Установка Dokku

Дальше все команды выполняю уже на сервере: ssh root@<ip> -i ~/.ssh/hetzner.

  1. Опционально: обновляю систему.
    # Ubuntu update all
    sudo -s -- <<'EOF'
    apt-get update
    apt-get upgrade -y
    apt-get full-upgrade -y
    apt-get autoremove -y
    apt-get autoclean -y
    EOF
    
    Также рекомендую после обновлений перезагрузить сервер полностью sudo reboot и переподключиться.
  2. Ставлю Dokku. На момент написания свежая версия — 0.36.10, поэтому скачиваю официальный скрипт и явно указываю тег:
    wget -NP . https://dokku.com/install/v0.36.10/bootstrap.sh
    sudo DOKKU_TAG=v0.36.10 bash bootstrap.sh
    
  3. Добавляю ключ для публикации приложений. Чтобы не создавать новый, забираю публичный ключ, которым уже захожу на сервер, и передаю Dokku:
    cat ~/.ssh/authorized_keys | dokku ssh-keys:add admin
    
    Важно: лучше всё-таки сгенерировать отдельную пару ключей для деплоя, а не переиспользовать root-доступ. Можно вручную передать любой публичный ключ:
    echo '<your-public-key>' | dokku ssh-keys:add admin
    
  4. Привязываю домен по умолчанию:
    dokku domains:set-global <your-domain>
    
  5. Ставлю плагин для HTTPS и настраиваю автоматическое продление сертификатов, для создания сертификатов нужно будет указать email:
    sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
    dokku letsencrypt:set --global email <your-email>
    sudo dokku letsencrypt:cron-job --add
    

На этом настройка Dokku завершена, теперь можно переходить к деплою своего первого бэкенда!

Первый бэкенд

Пора собрать первый бэкенд. Первые две команды выполняю на сервере, остальные — локально.

  1. Создаю новое приложение helloworld
    dokku apps:create helloworld
    
  2. Активирую HTTPS
    dokku letsencrypt:enable helloworld
    
  3. На локальной машине создаю пустой git-репозиторий и настраиваю его на Dokku:
    git init helloworld
    cd helloworld
    git remote add dokku dokku@<ip>:helloworld
    
  4. Проверяю, что соединение работает (ssh -T dokku@<ip> должен вывести список команд). Если нет, добавляю блок в ~/.ssh/config, чтобы указать ключ:
    Host <ip>
     IdentityFile ~/.ssh/hetzner
     AddKeysToAgent yes
     UseKeychain yes
    
    После создания файла не забудьте chmod 600 ~/.ssh/config, чтобы поправить права доступа.
  5. Создаю минимальное бэкенд-приложение (копирую несколько строчек в файл):
    cat <<'EOF' > server.js
    const http = require('http');
    http.createServer((_, res) => {
       res.writeHead(200, {'Content-Type':'application/json'});
       res.end('{"message":"hello world"}');
    }).listen(80);
    EOF
    
  6. Создаю минимальный Dockerfile:
    cat <<'EOF' > Dockerfile
    FROM node:24-alpine
    COPY server.js .
    EXPOSE 80
    CMD ["node", "server.js"]
    EOF
    
  7. Коммичу изменения и деплою. Как только git push доезжает до сервера, Dokku собирает образ и перезапускает приложение:
    git add -A && git commit -m "first backend"
    git push --set-upstream dokku main
    

Готово! Теперь приложение доступно по адресу https://helloworld.chenchik.me

Источники