Self-host PMS на дроплете за $4

Как поднять PMS для краткосрочной аренды на дешёвом дроплете DigitalOcean. Реальные цифры по RAM, реальные ограничения сборки, реальный ежемесячный счёт.

GGribadan7 мин чтения
Self-host PMS на дроплете за $4

Первый облачный счёт, который я оплатил как хост, был $73. Прокликал AWS-консоль, выбрал «разумные на вид» настройки и в итоге получил t3.medium, идущий вхолостую круглосуточно, плюс managed Postgres, в который я ни разу не залез. После отмены этого я перенёс всё на дроплет DigitalOcean за $4 в месяц и SQLite. Крутится больше года. Обслуживает небольшую, но реальную базу пользователей. Не загорелся.

Этот пост — про то, как это сделать, что ломается на маленьком конце и какой честный компромисс между $4-боксом и managed-сервисом.

За self-host (и против)

Self-host PMS — не для всех. Честно решите, на какой вы стороне, прежде чем читать дальше.

Self-host имеет смысл, если:

  1. У вас уже есть Linux-машина под что-то ещё (личный сайт, домашняя лаба, VPN). Маржинальные усилия добавить ещё одно приложение — небольшие.
  2. У вас 1–50 объектов и хочется не платить $25–200 в месяц за PMS.
  3. Хочется владеть своими данными — сканам паспортов гостя не место в общей SaaS-БД компании, которую через три года могут купить.
  4. Вам в кайф чинить что-то в 23:00, потому что радость перевешивает потерю сна.

Self-host НЕ имеет смысла, если:

  1. У вас 100+ объектов. Реальные channel-manager API (Hostaway, Lodgify) на этом масштабе стоят своих денег; iCal-only мир слишком терян.
  2. У вас работа, не позволяющая отвечать на алерт в 3 ночи. Self-host означает, что вы команда дежурных из одного человека.
  3. Вам нужно пять девяток. Один дроплет — одна точка отказа. Перезагрузка, мигнула сеть, забился диск — восстановление за вами.
  4. «Смотреть в логи» вы считаете наказанием. Self-host — это в основном смотреть в логи.

Честный средний путь: сначала попробуйте бесплатный hosted-инстанс (RentTools — один из вариантов; есть и другие). Подходит — оставайтесь там. Хотите больше контроля — следующий шаг $4-дроплет. Переросли его — managed PMS.

Размер дроплета

Самые дешёвые дроплеты DigitalOcean — $4–6 в месяц в зависимости от региона и текущих цен. 512 МБ — 1 ГБ, 1 vCPU, 10–25 ГБ SSD. Прайс-страница — авторитетный источник; цифры двигаются раз в несколько кварталов.

Для одного приложения Next.js плюс SQLite docs Next.js по продакшен-деплою описывают стандартный node сервер, который вы и будете крутить. Реалистичное потребление ресурсов на моём боксе, наблюдаемое месяцами:

  1. RAM в рантайме: 250–400 МБ резидентной памяти на Node-процесс при штатном трафике (1–5 одновременных запросов).
  2. CPU в рантайме: меньше 5% одного vCPU в среднем. Пики до 30% во время iCal-синхронизации каждые 10 минут.
  3. Диск под SQLite: меньше 100 МБ для БД на 50 объектов, 8 000 бронирований, 12 000 гостей. SQLite плотный.
  4. Диск под Node + node_modules: 600 МБ — 1 ГБ. Это та часть, которая просит дроплет побольше.

Тариф 1 ГБ всё это держит спокойно. Тариф 512 МБ держит рантайм, но во время операций вроде массовых миграций или восстановления бэкапа вы поймаете OOM. Если бюджет позволяет — берите 1 ГБ. Если нет — структурируйте операции так, чтобы тяжёлая работа шла в другом месте (CI, ваш ноутбук), а на маленький бокс приезжал результат.

Чего точно НЕ нужно делать — это собирать на дроплете. Об этом ниже.

Собирать в одном месте, запускать на боксе

Это самый полезный приём на дешёвом конце.

Сборка Next.js на маленьком боксе идёт плохо. Процесс сборки порождает несколько воркеров, держит весь граф зависимостей в памяти, прогоняет TypeScript, оптимизирует бандлы, генерирует пред-рендереные страницы и выдаёт .next/, который в 10 раз больше исходников. На дроплете 1 ГБ эта связка:

  1. За 30–60 секунд съест всю доступную RAM.
  2. Триггерит OOM-killer, который обычно убивает сборку, но иногда — работающее приложение.
  3. Оставит вас с полу-собранным деплоем и кратковременным простоем.

Лечение — собирать артефакт на машине помощнее и довозить результат. Два рабочих варианта:

  1. GitHub Actions runner. У ранеров 16 ГБ RAM. Сборка укладывается в 2–4 минуты. Ранер делает tarball из .next/, копирует на дроплет через scp, дроплет распаковывает и перезапускает systemd-юнит. Стоимость: $0 на free tier GitHub Actions для публичных и большинства небольших приватных репозиториев.
  2. Ваш ноутбук. Та же идея, руками. npm run build локально, rsync на дроплет, рестарт. Менее повторяемо, чем CI, но норм для one-person-операции с одним деплоем в неделю.

Шаблон работает, потому что требования к рантайму (node server.js поверх готового .next/) драматически легче требований к сборке (компиляция, бандл, оптимизация). Дроплет делает только лёгкую половину.

Если идёте по CI-маршруту, docs GitHub Actions описывают workflow YAML; туториал DigitalOcean по systemd для Node — стандартный референс на стороне дроплета. Заведите Node-процесс под systemd, чтобы перезагрузки и краши восстанавливались автоматически.

SQLite вытягивает

Второй сюрприз — насколько далеко вас тащит SQLite.

Для single-tenant или single-host PMS SQLite держит нагрузки, под которые обычно советуют Postgres. Несколько вещей, которые работают вопреки ожиданиям:

  1. Параллельные чтения: WAL-режим даёт многим читателям читать одновременно. Даже 100-объектный дашборд, тянущий десятки бронирований, читает чисто.
  2. Пропускная способность записи: записи одного хоста — единицы в секунду в худшем случае. Сильно ниже потолка SQLite в тысячи записей в секунду на обычном диске.
  3. Бэкапы: БД SQLite — один файл. Ежедневный бэкап — cp data/prod.db data/backups/$(date +%F).db, быстрый даже на гигабайтных размерах, потому что page cache ОС делает чтение последовательным.
  4. Миграции: стандартные миграции Prisma работают. Ограничение «один писатель» бьёт во время изменения схемы, но 30-секундная пауза приемлема для инструмента одного хоста, который не критичен по времени на 100%.

Сценарии, где SQLite ломается: мульти-регион (без репликации), тяжёлый мульти-tenant с веером записей (лучше Postgres или sharded write), full-text search на миллионах строк (FTS5 справляется, но Postgres идиоматичнее). Ничего из этого к небольшому PMS не относится.

Путь миграции, если перерастёте, — нормальный. Шаблон database adapter в Prisma (мы используем @prisma/adapter-libsql) позволяет поменять SQLite на Turso, реплицированный libSQL или полноценный Postgres почти переменной окружения. Стройте под SQLite, меняйте позже, если понадобится.

Подробнее, почему мы выбрали SQLite-подход, — в посте про автоматизацию расписания уборки, который живёт на той же БД и показывает, как реально выглядят данные.

Cloudflare, TLS и скучная инфра

Перед дроплетом я держу Cloudflare. Free tier. Full (strict) TLS. Выгоды большие при нулевой цене:

  1. Бесплатный TLS-сертификат. Выдаётся автоматом. Никакого Let's Encrypt-крона, никакого certbot.
  2. Защита от DDoS. Маленького хоста вряд ли будут DDoS-ить целенаправленно, но шумный бот один-два раза прибил CPU моего сервера. Cloudflare его съел.
  3. Кеш статики. Картинки, шрифты и пути _next/static/ Next.js кешируются на edge. Это снимает с дроплета пропускную и CPU-нагрузку настолько, что 1 ГБ-тариф ощущается просторнее.
  4. DNS в одном месте с прокси. Один дашборд на всё.

Полная схема: регистратор домена указывает NS-записи на Cloudflare, Cloudflare проксирует apex и www на IP дроплета, на дроплете крутится nginx, терминирующий трафик Cloudflare со strict TLS, nginx форвардит в локальный Next.js процесс. Вся цепочка от DNS до приложения собирается за час, если делали раньше; за два-три часа в первый раз.

Не очень эффектный шаг — systemd. Заведите Next.js как systemd-юнит (rent-tool.service в нашем случае), и перестанете беспокоиться про автозапуск, рестарт после краша, ротацию логов и лимиты ресурсов. systemd — это операционка говорит вам: «оставь бокс в покое, я разберусь».

Рисунок 1: Деплой-пайплайн. Push в master → GitHub Actions собирает → scp tarball на дроплет → systemd reload. Скриншот появится по адресу /blog/self-hosting-property-manager-droplet/figure-1.png.

Что ломается на дешёвом конце

Что реально ломалось на моём $6-боксе, по убыванию частоты:

  1. Кончился диск. Логи накапливаются. Старые бэкапы накапливаются. Не докатившийся npm install оставляет хлам в ~/.npm. Поднимите logrotate, поставьте политику ретеншна бэкапов (последние 14 ежедневных + последние 12 месячных), раз в месяц прогоняйте du -sh /var/log /home/app/.npm /tmp. Дважды за год я ловил ENOSPC, и заметил только потому, что упал деплой.
  2. Давление по памяти при ручной операции. Разовый SQL-дамп, push схемы Prisma, скрипт, который грузит все бронирования в память. CI-сборка лечит штатный сценарий; ручные требуют дисциплины (стримить, а не грузить; пайпать, а не накапливать). На разовые tsx добавляйте --max-old-space-size=512 как страховку.
  3. Дрейф конфига доменов. Cloudflare поменял дефолт, или DNS-кеш TTL держится дольше ожидаемого. 24 часа на исправление — норма. На время активных изменений ставьте TTL 60 секунд; после — возвращайте дефолт.
  4. Минорная версия Next.js, сломавшая зависимость. Дважды за 18 месяцев. Лечится быстро (откатить пакет, запушить фикс); урок — пусть CI прогоняет сборку до того, как деплой ляжет на дроплет, тогда сломанная версия туда не доезжает.

Что НЕ ломалось: коррозия SQLite, дрожь systemd, сам дроплет неожиданно перезагружался. Маленькие дроплеты DigitalOcean удивительно стабильны. Скучная инфраструктура остаётся скучной.

Одно мнение, не нейтральное

Единственное, что подход «маленький дроплет» реально покупает, — это отсутствие вендора. Не экономия (managed-сервис — $25–200 в месяц за похожие фичи; экономия настоящая, но вторична). Именно отсутствие.

Когда регистратор домена меняет UI, когда у DigitalOcean 30-минутный сетевой провал в моём регионе, когда Cloudflare депрекейтит настройку — это вещи, которые я замечаю и подкручиваю. Ни одна из них меня не выключает, потому что ни одна не владеет моими данными или моим кодом. Если завтра DO обанкротится, я в выходные scp-ю SQLite-файл на Hetzner и в понедельник снова работаю.

Сравните с managed PMS. Вендор меняет цены, его покупает PMS покрупнее, который хочет «консолидировать», закрывают free tier или ловят многодневный outage. Вы ждёте. Данные на бумаге ваши, а на практике — их. $4-дроплет — это цена выхода из этих отношений.

Это и есть мнение. Экономия — бонус.

Частые вопросы

  • SQLite реально безопасен в продакшене?

    Да для single-writer нагрузок на масштабе одного хоста-PMS. Нет для мульти-регион или write-heavy мульти-tenant SaaS. Appropriate Uses от команды SQLite — канонический референс; мы попадаем в шаблон «БД для приложения».

  • Почему DigitalOcean, а не AWS / GCP / Hetzner?

    Личное предпочтение. UI у DO самый простой, цены на маленькие дроплеты честные, документация хорошая. Hetzner дешевле при том же RAM-тарифе и тоже хорош. AWS — overkill для амбиций уровня $4. GCP норм, но правила free tier мутные.

  • А Raspberry Pi дома?

    Работает. Добавляет два новых режима отказа: домашний интернет (динамические IP, заблокированный 443 порт) и отключения электричества дома. Если оба перекрываете — Pi дешевле любого облака. Сервис, на котором держится мой доход, я бы так не запускал, но как хобби-сетап нормально.

  • Как мониторить uptime?

    Бесплатный uptime-монитор (BetterStack, UptimeRobot, free-tier Pingdom) бьёт по /api/health раз в минуту и алертит на падение. Эндпоинт должен быть дешёвым (без запросов в БД), чтобы сам монитор не нагружал бокс.

  • А бэкапы?

    Ежедневный cp файла SQLite в директорию бэкапов плюс оффсайт (S3-совместимое хранилище — Backblaze B2 по $6/ТБ) раз в неделю. Раз в квартал тестируйте восстановление — бэкапы, из которых вы ни разу не восстанавливались, не настоящие.

  • Дроплет потянет 1000 объектов?

    Скорее всего да, но не на самом дешёвом тарифе. Поднимите до 2 ГБ RAM и 2 vCPU (~$12 в месяц), и боксу станет просторнее. Дальше узкое место обычно цикл опроса iCal, а не дроплет.

ПоделитьсяX / TwitterLinkedInFacebookRedditПочта

Comments

Sign in to comment.

  • No comments yet.