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

Первый облачный счёт, который я оплатил как хост, был $73. Прокликал AWS-консоль, выбрал «разумные на вид» настройки и в итоге получил t3.medium, идущий вхолостую круглосуточно, плюс managed Postgres, в который я ни разу не залез. После отмены этого я перенёс всё на дроплет DigitalOcean за $4 в месяц и SQLite. Крутится больше года. Обслуживает небольшую, но реальную базу пользователей. Не загорелся.
Этот пост — про то, как это сделать, что ломается на маленьком конце и какой честный компромисс между $4-боксом и managed-сервисом.
За self-host (и против)
Self-host PMS — не для всех. Честно решите, на какой вы стороне, прежде чем читать дальше.
Self-host имеет смысл, если:
- У вас уже есть Linux-машина под что-то ещё (личный сайт, домашняя лаба, VPN). Маржинальные усилия добавить ещё одно приложение — небольшие.
- У вас 1–50 объектов и хочется не платить $25–200 в месяц за PMS.
- Хочется владеть своими данными — сканам паспортов гостя не место в общей SaaS-БД компании, которую через три года могут купить.
- Вам в кайф чинить что-то в 23:00, потому что радость перевешивает потерю сна.
Self-host НЕ имеет смысла, если:
- У вас 100+ объектов. Реальные channel-manager API (Hostaway, Lodgify) на этом масштабе стоят своих денег; iCal-only мир слишком терян.
- У вас работа, не позволяющая отвечать на алерт в 3 ночи. Self-host означает, что вы команда дежурных из одного человека.
- Вам нужно пять девяток. Один дроплет — одна точка отказа. Перезагрузка, мигнула сеть, забился диск — восстановление за вами.
- «Смотреть в логи» вы считаете наказанием. Self-host — это в основном смотреть в логи.
Честный средний путь: сначала попробуйте бесплатный hosted-инстанс (RentTools — один из вариантов; есть и другие). Подходит — оставайтесь там. Хотите больше контроля — следующий шаг $4-дроплет. Переросли его — managed PMS.
Размер дроплета
Самые дешёвые дроплеты DigitalOcean — $4–6 в месяц в зависимости от региона и текущих цен. 512 МБ — 1 ГБ, 1 vCPU, 10–25 ГБ SSD. Прайс-страница — авторитетный источник; цифры двигаются раз в несколько кварталов.
Для одного приложения Next.js плюс SQLite docs Next.js по продакшен-деплою описывают стандартный node сервер, который вы и будете крутить. Реалистичное потребление ресурсов на моём боксе, наблюдаемое месяцами:
- RAM в рантайме: 250–400 МБ резидентной памяти на Node-процесс при штатном трафике (1–5 одновременных запросов).
- CPU в рантайме: меньше 5% одного vCPU в среднем. Пики до 30% во время iCal-синхронизации каждые 10 минут.
- Диск под SQLite: меньше 100 МБ для БД на 50 объектов, 8 000 бронирований, 12 000 гостей. SQLite плотный.
- Диск под Node + node_modules: 600 МБ — 1 ГБ. Это та часть, которая просит дроплет побольше.
Тариф 1 ГБ всё это держит спокойно. Тариф 512 МБ держит рантайм, но во время операций вроде массовых миграций или восстановления бэкапа вы поймаете OOM. Если бюджет позволяет — берите 1 ГБ. Если нет — структурируйте операции так, чтобы тяжёлая работа шла в другом месте (CI, ваш ноутбук), а на маленький бокс приезжал результат.
Чего точно НЕ нужно делать — это собирать на дроплете. Об этом ниже.
Собирать в одном месте, запускать на боксе
Это самый полезный приём на дешёвом конце.
Сборка Next.js на маленьком боксе идёт плохо. Процесс сборки порождает несколько воркеров, держит весь граф зависимостей в памяти, прогоняет TypeScript, оптимизирует бандлы, генерирует пред-рендереные страницы и выдаёт .next/, который в 10 раз больше исходников. На дроплете 1 ГБ эта связка:
- За 30–60 секунд съест всю доступную RAM.
- Триггерит OOM-killer, который обычно убивает сборку, но иногда — работающее приложение.
- Оставит вас с полу-собранным деплоем и кратковременным простоем.
Лечение — собирать артефакт на машине помощнее и довозить результат. Два рабочих варианта:
- GitHub Actions runner. У ранеров 16 ГБ RAM. Сборка укладывается в 2–4 минуты. Ранер делает tarball из
.next/, копирует на дроплет черезscp, дроплет распаковывает и перезапускает systemd-юнит. Стоимость: $0 на free tier GitHub Actions для публичных и большинства небольших приватных репозиториев. - Ваш ноутбук. Та же идея, руками.
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. Несколько вещей, которые работают вопреки ожиданиям:
- Параллельные чтения: WAL-режим даёт многим читателям читать одновременно. Даже 100-объектный дашборд, тянущий десятки бронирований, читает чисто.
- Пропускная способность записи: записи одного хоста — единицы в секунду в худшем случае. Сильно ниже потолка SQLite в тысячи записей в секунду на обычном диске.
- Бэкапы: БД SQLite — один файл. Ежедневный бэкап —
cp data/prod.db data/backups/$(date +%F).db, быстрый даже на гигабайтных размерах, потому что page cache ОС делает чтение последовательным. - Миграции: стандартные миграции 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. Выгоды большие при нулевой цене:
- Бесплатный TLS-сертификат. Выдаётся автоматом. Никакого Let's Encrypt-крона, никакого certbot.
- Защита от DDoS. Маленького хоста вряд ли будут DDoS-ить целенаправленно, но шумный бот один-два раза прибил CPU моего сервера. Cloudflare его съел.
- Кеш статики. Картинки, шрифты и пути
_next/static/Next.js кешируются на edge. Это снимает с дроплета пропускную и CPU-нагрузку настолько, что 1 ГБ-тариф ощущается просторнее. - 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-боксе, по убыванию частоты:
- Кончился диск. Логи накапливаются. Старые бэкапы накапливаются. Не докатившийся
npm installоставляет хлам в~/.npm. Поднимитеlogrotate, поставьте политику ретеншна бэкапов (последние 14 ежедневных + последние 12 месячных), раз в месяц прогоняйтеdu -sh /var/log /home/app/.npm /tmp. Дважды за год я ловил ENOSPC, и заметил только потому, что упал деплой. - Давление по памяти при ручной операции. Разовый SQL-дамп, push схемы Prisma, скрипт, который грузит все бронирования в память. CI-сборка лечит штатный сценарий; ручные требуют дисциплины (стримить, а не грузить; пайпать, а не накапливать). На разовые
tsxдобавляйте--max-old-space-size=512как страховку. - Дрейф конфига доменов. Cloudflare поменял дефолт, или DNS-кеш TTL держится дольше ожидаемого. 24 часа на исправление — норма. На время активных изменений ставьте TTL 60 секунд; после — возвращайте дефолт.
- Минорная версия 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, а не дроплет.
Читать дальше
Comments
Sign in to comment.
- No comments yet.