SSD Nodes Learn 🎉 VPS от $4.99/мес
Руководства Matt ConnorАвтор: Matt Connor

Self-hosted аналоги Calendly: сравнение систем

Сравнение Cal.com, Easy!Appointments, Rallly и DayOtter для установки на VPS. Узнайте, как настроить двустороннюю синхронизацию календарей и отправку уведомлений по почте.

Краткий ответ

Self-hosted альтернатива Calendly должна выполнять одну задачу, которую никогда не решают внутренние инструменты на вашем VPS: отвечать на внешние запросы. Страница бронирования и есть сам продукт. Ей необходимы реальное доменное имя и TLS (transport layer security) с первого дня, а также возможность доставлять почту людям, которые никогда не слышали о вашем сервере.

Четыре проекта охватывают реалистичный спектр решений. Cal.com наиболее близок к Calendly и является стандартным выбором для индивидуального консультанта. Easy!Appointments — легкое решение на PHP и MySQL, которое стабильно работает на VPS с 1 GB оперативной памяти. Rallly — инструмент для групповых опросов, в котором отсутствует страница бронирования. DayOtter — новичок, платформа для планирования под лицензией AGPLv3 с ассистентом, который запрашивает подтверждение перед записью.

Два вопроса определяют, что именно вы сможете запустить. Синхронизируется ли решение в обе стороны с календарем, которым вы уже пользуетесь? И может ли оно отправлять почту? Второй вопрос — это то, на чем тихо проваливается большинство self-hosted систем бронирования, поэтому с него и стоит начать.

Проблемы с исходящей почтой

Подтверждение бронирования отправляется на почтовый ящик клиента. Это транзакционное письмо, которое попадает в Gmail или Microsoft 365, и эти почтовые службы оценивают вас на основе IP-адреса отправителя и ваших DNS-записей.

Отправка почты напрямую с VPS почти никогда не работает. Большинство провайдеров блокируют исходящий TCP-порт 25 на новых аккаунтах, поэтому соединение зависает и завершается по таймауту. Даже если порт 25 открыт, у нового IP-адреса VPS нет истории отправки, и крупные почтовые службы считают адреса из диапазонов хостинг-провайдеров подозрительными. Бронирование записывается в базу данных, страница сообщает об успехе, но письмо никто не получает. Со стороны сервера всё выглядит исправно, поэтому проблему обычно обнаруживают спустя недели, когда клиент не приходит на встречу.

Используйте релей. Подойдет любой провайдер транзакционной почты; приложению нужны только имя хоста, порт, имя пользователя и пароль. Перед настройкой приложения проверьте доступность порта:

nc -vz -w 5 "$SMTP_HOST" 587

Строка succeeded означает, что путь открыт. Зависание или Connection refused означают, что порт заблокирован на сетевом уровне, и никакое редактирование .env это не исправит. Релеи слушают порты 587 или 465 именно потому, что 25-й порт часто заблокирован.

Каждый проект работает с релеем по-своему. Cal.com считывает EMAIL_FROM, EMAIL_SERVER_HOST, EMAIL_SERVER_PORT, EMAIL_SERVER_USER и EMAIL_SERVER_PASSWORD, а также принимает RESEND_API_KEY. Будьте внимательны: в стандартном файле .env.example указан EMAIL_SERVER_HOST на localhost через порт 1025, что является локальным почтовым ящиком для разработки. Если оставить настройки по умолчанию, приложение будет отправлять письма в никуда без ошибок. Rallly использует SMTP_HOST, SMTP_PORT, SMTP_USER и SMTP_PWD. DayOtter принимает SMTP-настройки или ключ Resend. Easy!Appointments отправляет уведомления из самого приложения, поэтому укажите настройки релея на странице конфигурации перед тем, как принимать реальные бронирования.

Затем опубликуйте DNS-записи, которые предоставит ваш релей. Запись SPF (sender policy framework) указывает, какие серверы имеют право отправлять почту от имени вашего домена, а ключ DKIM (domainkeys identified mail) подписывает каждое сообщение, чтобы получатель мог убедиться в отсутствии изменений. Добавьте политику DMARC (domain-based message authentication, reporting and conformance) после того, как настроите первые две. Отправьте тестовое бронирование на реальный адрес у крупного провайдера, откройте заголовки сообщения и убедитесь, что строки аутентификации содержат pass. Страница бронирования, которая не может отправить письмо, хуже, чем её отсутствие, так как она отказывает незаметно.

Какие бэкенды календарей действительно поддерживают двустороннюю синхронизацию

Синхронизация работает в двух направлениях, и сбои в них происходят независимо. Направление чтения отвечает за доступность: приложение должно видеть ваши существующие занятые интервалы, иначе оно предложит слот, в котором вы уже заняты. Направление записи отвечает за само бронирование: подтвержденное событие должно появиться в календаре, который вы используете, а не только внутри инструмента бронирования.

Google Calendar и Microsoft 365 поддерживают оба направления, но с одним условием для self-hosted установки. Вы должны создать OAuth (open authorization) клиент самостоятельно, так как client ID хостируемого продукта отсутствует в исходном коде. Для Cal.com это GOOGLE_API_CREDENTIALS в .env, где хранится JSON-файл, который вы скачиваете из консоли Google Cloud. DayOtter принимает учетные данные Google и Microsoft OAuth таким же образом.

Здесь могут возникнуть две проблемы, о которых стоит знать до начала работы. Во-первых, redirect URI, который вы регистрируете, должен в точности совпадать с вашим публичным URL, включая схему и любой завершающий путь, иначе Google прервет соединение с ошибкой redirect_uri_mismatch на экране согласия. Во-вторых, проект Google, оставленный в статусе публикации Testing, выдает refresh tokens, которые истекают через семь дней. Синхронизация работает всю неделю, а затем останавливается, и логи приложения показывают invalid_grant при следующей попытке обновления. Переведите экран согласия в статус In production или будьте готовы переподключаться вручную каждый понедельник.

CalDAV (расширение протокола WebDAV для календарей) — это открытый вариант, но его поддержка реализована слабее. Cal.com поставляет приложение CalDAV, которое до сих пор помечено как beta, проверенное на совместимость с серверами, включая Baikal, Radicale, Nextcloud и Kerio Connect. Apple iCloud работает через то же приложение, но требует пароль приложения (app-specific password), а не основной пароль от вашего Apple ID. DayOtter указывает Apple через CalDAV наряду с Google и Microsoft 365.

ICS-лента — это не синхронизация. Подписка по URL .ics по своей сути доступна только для чтения, поэтому она может блокировать время на вашей странице бронирования, но никогда не сможет принять само бронирование. Если инструмент предлагает для вашего календаря только ICS, у вас есть лишь половина необходимого функционала, и вам все равно придется копировать события вручную.

Easy!Appointments синхронизирует только Google Calendar и ничего больше. Rallly вообще не считывает доступность: он собирает голоса по набору предложенных дат. Это подходящий инструмент для задачи «когда мы шестеро можем встретиться» и неподходящий для задачи «забронировать 30 минут со мной».

Страница бронирования публична, поэтому TLS — в приоритете

Большинство сервисов для self-hosting являются приватными. Вики-системы, форумы, дашборды — всё это можно скрыть за VPN или SSO-авторизацией, не открывая доступ из Интернета. С booking-ссылкой так поступить нельзя. Любой человек, которому вы её отправите, должен иметь возможность открыть её, что меняет конфигурацию в трёх аспектах.

Вам необходимо иметь доменное имя с A-записью, указывающей на VPS, ещё до начала установки. Сертификат нужен с первого дня, так как браузеры помечают обычные HTTP-формы как небезопасные, а ваш клиент вводит в них свои имя и email. Также необходимо правильно указать публичный URL приложения в конфигурации, поскольку это значение вшивается в ссылки в исходящих письмах и в OAuth redirect URI. Установите NEXT_PUBLIC_WEBAPP_URL в Cal.com, DOMAIN в Rallly, BASE_URL в Easy!Appointments или DAYOTTER_DOMAIN во время установки, указав именно тот https:// адрес, который вы будете использовать.

Rallly и DayOtter решают вопрос с TLS за вас. В комплект Rallly входит Traefik, который выпускает сертификаты Let's Encrypt, используя адрес из ACME_EMAIL. Установщик DayOtter разворачивает Caddy с автоматическим HTTPS. Cal.com и Easy!Appointments этого не делают, поэтому вам нужно поставить перед ними nginx и выпустить сертификат самостоятельно, так же, как вы бы сделали это для сертификата Let's Encrypt на nginx с помощью Certbot. Привяжите контейнер приложения к 127.0.0.1, чтобы единственный путь к нему пролегал через контролируемый вами прокси. Если на этом же сервере уже работает self-hosted альтернатива Trello для ваших внутренних задач, оставьте её за существующей аутентификацией, а публичный server block настройте только для хоста системы бронирования.

Cal.com на вашем VPS

Конфигурация Docker находится в собственном репозитории, а образы уже собраны на Docker Hub, поэтому вы загружаете их, а не собираете самостоятельно.

git clone --recursive https://github.com/calcom/cal.diy.git
cd cal.diy
cp .env.example .env
openssl rand -base64 32
openssl rand -base64 24
docker compose pull
docker compose up -d

Первое случайное значение вставляется в NEXTAUTH_SECRET, а второе — в CALENDSO_ENCRYPTION_KEY. Оба значения обязательны. Установите DATABASE_URL и укажите NEXT_PUBLIC_WEBAPP_URL на ваш публичный адрес. В комплект поставки входят веб-приложение, PostgreSQL и Prisma Studio; в документации приводится docker compose up -d calcom для запуска приложения отдельно от базы данных, которую вы размещаете в другом месте, что и рекомендуется сделать после завершения установки.

Загружайте образ, не собирайте его на VPS. Инструкции проекта требуют экспортировать NODE_OPTIONS="--max-old-space-size=16384" при сборке из исходного кода, что составляет 16 GB кучи только для Node. На оборудовании ARM добавьте суффикс -arm к тегу образа. Проект не публикует минимальные требования для запуска готового образа, поэтому ориентируйтесь на 2 GB для приложения вместе с PostgreSQL как на рабочую цифру, а не на задокументированную, и следите за потреблением памяти в течение первой недели.

Проверьте, что сервис запустился:

docker compose ps
docker compose logs -f calcom
curl -sI https://cal.example.com | head -n 1

Команда curl должна вывести HTTP/2 200. Ошибка 502 Bad Gateway от Nginx при работающем контейнере обычно означает, что при первом запуске ещё применяются миграции базы данных. Подождите несколько минут и изучите логи, прежде чем делать вывод о неисправности. Вебхуки Cal.com срабатывают при каждом подтвержденном бронировании, поэтому бронирование может запускать любую автоматизацию, которая у вас уже настроена, например экземпляр n8n, доступный по HTTPS на вашем VPS.

Ядро системы распространяется по лицензии AGPLv3, некоторые функции содержатся в корпоративном каталоге под отдельной коммерческой лицензией. Ознакомьтесь с этой лицензией, прежде чем строить платные бизнес-процессы на основе функций для команд.

Easy!Appointments на сервере с 1 ГБ ОЗУ

Требуются Apache или Nginx, PHP 8.2 или новее, а также MySQL. Официальный образ доступен по адресу alextselegidis/easyappointments.

Сначала важное предупреждение. Файл docker-compose.yml в репозитории предназначен для среды разработки. Он предполагает, что вы откроете оболочку внутри контейнера и выполните npm install && composer install && npm start. Это не готовое решение для развертывания. Используйте опубликованный образ:

services:
  easyappointments:
    image: alextselegidis/easyappointments  # pin the current tag from Docker Hub
    environment:
      - BASE_URL=https://book.example.com
      - DB_HOST=mysql
      - DB_NAME=easyappointments
      - DB_USERNAME=easyapp
      - DB_PASSWORD=change-me
    ports:
      - '127.0.0.1:8080:80'
    depends_on:
      - mysql
  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=change-me-too
      - MYSQL_DATABASE=easyappointments
      - MYSQL_USER=easyapp
      - MYSQL_PASSWORD=change-me
    volumes:
      - ./mysql:/var/lib/mysql

Параметр BASE_URL должен содержать публичный HTTPS-адрес. Если указать его неверно, ссылки на бронирование в письмах с подтверждением будут вести на хост, недоступный для клиента. Образ работает по обычному HTTP на 80 порту и не имеет собственных сертификатов, поэтому порт привязан к 127.0.0.1, а Nginx выполняет TLS termination перед ним. Если синтаксис compose вам в новинку, начните с Основы Docker Compose на VPS и вернитесь сюда.

Это самый легковесный вариант из всех представленных. Два контейнера, PHP-приложение и MySQL, свободно размещаются на VPS с 1 ГБ ОЗУ. Плата за это — ограниченные возможности: Google Calendar является единственным бэкендом для календаря, а интерфейс представляет собой классическую панель администратора, а не современный процесс бронирования. Если ваш календарь находится в Microsoft 365, Fastmail или Nextcloud, этот вариант вам не подойдет.

Rallly для групповых опросов

Rallly решает другую задачу. Он не публикует вашу доступность. Он предлагает группе набор вариантов времени и собирает голоса, что полезно для собрания совета директоров, но бесполезно для ссылки на запись клиента.

curl -fsSL https://get.rallly.co | bash

Прочитайте любой скрипт перед тем, как передать его в оболочку через pipe. Замените bash на less, ознакомьтесь с его действиями, а затем запустите. Ручной способ выполняет ту же работу пошагово, позволяя вам контролировать процесс:

git clone https://github.com/lukevella/rallly-selfhosted.git
cd rallly-selfhosted
./rallly.sh setup
./rallly.sh start

Документированные требования: минимум 2 GB оперативной памяти, Docker 19.03 или новее с Compose v2, свободные порты 80 и 443, а также домен, указывающий на сервер. В комплект поставки входят Traefik для HTTPS, веб-приложение, PostgreSQL и Garage для S3-совместимого объектного хранилища. Установите DOMAIN, SECRET_PASSWORD длиной не менее 32 символов, SUPPORT_EMAIL и INITIAL_ADMIN_EMAIL. Если вы уже используете reverse proxy, настройте PROXY_MODE=external и WEB_PORT, чтобы Traefik не конфликтовал с ним. Если вы уже используете самостоятельно развернутое S3-совместимое объектное хранилище с MinIO, укажите на него в переменных S3_* и удалите контейнер Garage.

SMTP здесь обязателен, так как вход в систему осуществляется через magic link. Без работающего реле никто не сможет войти, включая только что созданную учетную запись администратора. Это лучший вариант сбоя электронной почты: он останавливает вас на входе, а не приводит к потере записи клиента через три недели.

DayOtter — новый участник рынка

DayOtter — это платформа для планирования с лицензией AGPLv3, дополненная встроенным помощником. Установка в production выполняется одной командой:

curl -fsSL https://raw.githubusercontent.com/Dayotter/dayotter/main/deploy/install.sh \
  | sudo DAYOTTER_DOMAIN=cal.example.com bash

Перед запуском обязательно ознакомьтесь с содержимым скрипта, как указано выше. Установщик настраивает Docker, генерирует секретные ключи и разворачивает полный стек: веб-приложение на Next.js, фоновый процесс для обработки напоминаний, синхронизации календарей и вебхуков, PostgreSQL, Redis, а также Caddy с автоматическим HTTPS.

Поддержка календарей здесь самая широкая из всех четырех решений. Доступны Google, Microsoft 365, Apple через CalDAV и ленты ICS (с учетом указанного выше ограничения для ICS). Все остальные интеграции подключаются через переменные окружения, включая SMTP или Resend для почты, ANTHROPIC_API_KEY для помощника, Twilio для SMS и Stripe для платежей. Помощник работает по принципу подтверждения: он предлагает действие, вы одобряете его, и ни одна запись не попадет в календарь без вашего явного согласия. Если оставить API-ключ пустым, соответствующая часть функционала просто не будет запущена.

Лицензирование прозрачно для тех, кто размещает систему самостоятельно. Ядро распространяется под AGPLv3, а каталог ee/ содержит компоненты с коммерческой лицензией для облачных решений, которые остаются неактивными, если не установлена переменная DAYOTTER_CLOUD=1. Это означает, что функции для команд, которые в облачном тарифе стоят 9 долларов за пользователя в месяц (по состоянию на август 2026 года), доступны для использования на вашем собственном сервере.

Это самый тяжелый стек в данном обзоре и самый молодой проект. Запустите его параллельно с текущим сервисом бронирования на две недели, принимайте реальные заявки через обе системы и изучите логи фонового процесса, прежде чем переводить на него своих клиентов.

Во что на самом деле обходится каждый стек

Количество контейнеров — это честный показатель того, сколько ресурсов стек потребует от небольшого VPS, так как каждый сервис имеет свой минимальный порог потребления оперативной памяти. Ниже приведены показатели из опубликованных Docker-стеков каждого проекта по состоянию на август 2026 года.

ChartServices in each project's documented Docker stack
The data behind this chart
[
  {
    "tool": "Easy!Appointments",
    "containers": 2,
    "database": "MySQL"
  },
  {
    "tool": "Cal.com",
    "containers": 3,
    "database": "PostgreSQL"
  },
  {
    "tool": "Rallly",
    "containers": 4,
    "database": "PostgreSQL"
  },
  {
    "tool": "DayOtter",
    "containers": 5,
    "database": "PostgreSQL and Redis"
  }
]

Easy!Appointments требует 2 контейнеров и помещается в 1 ГБ. Входящий в комплект стек Rallly состоит из 4, а документация к нему рекомендует 2 ГБ. Установщик DayOtter разворачивает 5 контейнеров, поэтому он требует самый мощный сервер из 4 представленных здесь. Cal.com и DayOtter не публикуют минимальные требования к оперативной памяти, поэтому 2 ГБ — это моя начальная точка для обоих, а не официально поддерживаемое значение.

Два из этих показателей можно снизить, если у вас уже развернута инфраструктура. Контейнеры Traefik и Garage в Rallly можно исключить, если использовать собственный прокси-сервер и объектное хранилище. Prisma Studio в Cal.com — это инструмент разработки, который не следует оставлять запущенным на публичном сервере.

Какую альтернативу Calendly для self-hosting выбрать

Индивидуальному консультанту стоит использовать Cal.com. Это единственный проект в списке, который сочетает в себе узнаваемую страницу бронирования, готовые образы, избавляющие ваш VPS от сборки Node, и поддержку CalDAV для тех, кто не пользуется календарями Google или Microsoft. Одна база данных PostgreSQL и один контейнер с приложением — это нагрузка по обслуживанию, которую можно поддерживать годами. Заложите полдня на настройку OAuth-клиента и почтового реле. Учтите, что приложение CalDAV всё ещё находится в стадии бета-тестирования, поэтому перед публикацией ссылки протестируйте одно реальное бронирование от начала до конца.

Небольшой команде стоит присмотреться к DayOtter. Взвешенный алгоритм round robin и коллективное бронирование входят в ядро AGPLv3, поэтому self-hosting предоставляет функции, за которые в облачных версиях пришлось бы платить за каждое рабочее место. Воркер-процесс оптимизирован для работы с напоминаниями и вебхуками, на которые опирается команда. Плата за это — зрелость продукта: это самый новый проект в списке, поэтому сначала запустите его параллельно с текущим решением и сохраняйте старую ссылку, пока не отследите полный месяц бронирований.

Два более узких случая. Если вам нужно только голосование для выбора времени встречи группы, установите Rallly и на этом остановитесь. Если у вас VPS с 1 GB оперативной памяти, вы пользуетесь Google Calendar и вам нужно максимально легковесное решение для приёма бронирований, Easy!Appointments прослужит дольше любого более сложного варианта, который вы могли бы разместить на этом сервере. По более широкому вопросу о том, что ещё стоит разместить на том же сервере, см. что стоит хостить самостоятельно в 2026.

FAQ

Можно ли запустить сервис бронирования без доменного имени?

Нет. Каждое из этих приложений вставляет свой публичный URL в ссылки внутри писем с подтверждением. Кроме того, Google и Microsoft сверяют OAuth redirect URI с этим же значением, поэтому при использовании IP-адреса вы получите redirect_uri_mismatch на экране согласия. Let's Encrypt также не выдает сертификаты для IP-адресов, из-за чего страница будет открываться по обычному HTTP, а браузер пометит форму как небезопасную. Сначала купите домен, направьте A-запись на ваш VPS, и только потом приступайте к установке.

Почему письма с подтверждением бронирования не приходят?

Почти всегда это происходит потому, что сервер пытается отправить почту самостоятельно. Большинство хостинг-провайдеров блокируют исходящий 25 порт на новых аккаунтах, поэтому соединение зависает. Даже если порт открыт, у нового IP-адреса нет репутации отправителя, и крупные почтовые сервисы отклоняют такие письма. Настройте приложение на работу через транзакционный почтовый релей по порту 587, убедитесь, что порт доступен с помощью nc -vz -w 5 "$SMTP_HOST" 587, а затем опубликуйте SPF и DKIM записи, предоставленные релеем. Если вы используете Cal.com, проверьте, заменили ли вы стандартные значения EMAIL_SERVER_HOST=localhost и EMAIL_SERVER_PORT=1025, которые указывают на локальный почтовый ящик для разработки.

Синхронизируется ли self-hosted Cal.com с CalDAV или только с Google?

С обоими, но с разной степенью готовности. Приложение CalDAV помечено как бета-версия и протестировано с такими серверами, как Baikal, Radicale, Nextcloud и Kerio Connect. Apple iCloud также работает через него при использовании пароля приложения. Google Calendar и Microsoft 365 поддерживают двустороннюю синхронизацию, но при self-hosted установке вы должны создать собственного OAuth-клиента и указать его через GOOGLE_API_CREDENTIALS, так как учетные данные облачного сервиса отсутствуют в исходном коде.

Почему синхронизация с Google Calendar перестает работать через неделю?

Потому что проект в Google Cloud Console все еще находится в статусе Testing. Google выдает refresh tokens для приложений в этом состоянии, которые истекают через семь дней. Поэтому соединение работает, а затем обрывается при попытке обновления токена, и в логах приложения появляется ошибка invalid_grant. Переведите экран согласия OAuth в статус In production и один раз переподключите календарь. Повторное подключение без изменения статуса даст вам еще семь дней, не более.

Что из этого будет работать на VPS с 1 ГБ оперативной памяти?

Easy!Appointments будет, так как это PHP-приложение и MySQL. Rallly требует минимум 2 ГБ, так как его стек состоит из четырех сервисов. Cal.com и DayOtter не указывают минимальные требования, но приложение на Next.js с PostgreSQL (а в случае с DayOtter — еще и Redis с воркером) подразумевает, что вам стоит рассчитывать на 2 ГБ или больше. Никогда не собирайте Cal.com из исходного кода на слабом сервере: инструкции проекта требуют 16 ГБ для Node heap, поэтому используйте готовый образ.

#scheduling#calendly#cal-com#self-hosted#booking