Как установить и настроить Cal.com на VPS
Calendly прекрасно работает — ровно до момента, когда вы упираетесь в лимиты бесплатного тарифа или начинаете задумываться, где физически хранятся данные о встречах ваших клиентов. Cal.com — открытая альтернатива с тем же удобством, но развёрнутая на вашей инфраструктуре: вы решаете, кто видит календарь, какие интеграции включены и куда уходят письма с приглашениями. Ниже — рабочий способ поднять Cal.com на своём VPS через Docker Compose: с базой PostgreSQL, доменом, SSL-сертификатом и почтой для уведомлений, без «просто запустите скрипт» и недосказанностей.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что даёт self-hosted Cal.com и когда он оправдан
Cal.com — открытый планировщик встреч на Next.js с PostgreSQL в качестве хранилища. Логика та же, что у Calendly: публичная страница с доступными слотами, типы событий (30-минутный созвон, демо, консультация), автоматическая проверка занятости по подключённому календарю, письма-подтверждения и напоминания.
Разница появляется, когда вы переходите на self-hosted:
- Данные остаются у вас. Имена, email и содержимое встреч клиентов не уходят на серверы стороннего SaaS — актуально для юристов, медицины, финансовых консультаций и просто параноиков в хорошем смысле.
- Нет лимитов «на команду» или «на тип события». В облачном Cal.com и в Calendly бесплатные и средние тарифы режут количество активных типов событий, участников команды, интеграций. На своём сервере ограничение — только ресурсы VPS.
- Полный доступ к API и вебхукам. Можно завести вебхук на каждое бронирование и завести его в свою CRM без ограничений тарифного плана.
- Кастомизация UI и логики. Cal.com — open source, при желании можно патчить исходники под свои нужды (это уже не «пять минут», но возможность есть).
Честно про обратную сторону: обновления, бэкапы базы, мониторинг аптайма и решение проблем с почтовой доставкой теперь на вас. Если нужен SSO с корпоративным AD, SLA техподдержки или вы не хотите вообще думать о сервере — облачный тариф Cal.com или Calendly будет проще. Self-hosted имеет смысл, если у вас уже есть VPS под другие задачи или если контроль над данными для вас критичен.
Требования к серверу и подготовка
Cal.com — это Node.js/Next.js приложение плюс PostgreSQL рядом. Ориентировочно для комфортной работы небольшой команды (до пары десятков пользователей) хватает:
- 2 vCPU, 4 ГБ RAM — с запасом, чтобы Next.js и Postgres не толкались за память при пиковой нагрузке;
- 20–40 ГБ SSD — под систему, образы Docker и растущую базу бронирований;
- Ubuntu 24.04 LTS или Debian 12 — оба варианта штатно поддерживают Docker;
- домен (или поддомен вроде
cal.вашдомен.ру), A-запись которого указывает на IP сервера.
Если домен ещё не привязан к серверу, сначала настройте DNS — процесс с нуля описан в статье про настройку домена и DNS на Ubuntu 24.04. Дальше в этой статье предполагается, что cal.example.com уже резолвится на ваш сервер.
Из портов наружу должны смотреть только 80 и 443 — сам Cal.com и Postgres останутся за реверс-прокси и не будут торчать в интернет напрямую:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверDocker и Docker Compose: базовый стек
Если Docker и Compose ещё не установлены — поставьте их из официального репозитория Docker, а не из пакетов дистрибутива (там версии часто отстают):
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
docker compose version
Более подробно про структуру production-стека на Docker Compose — с профилями, healthcheck и порядком запуска сервисов — есть в статье про Docker Compose для продакшена. Здесь используем упрощённую, но рабочую схему: два сервиса — база и сам Cal.com — в одной пользовательской сети.
Создайте рабочую директорию:
sudo mkdir -p /opt/calcom
cd /opt/calcom
docker-compose.yml для Cal.com
Файл /opt/calcom/docker-compose.yml:
services:
database:
image: postgres:16
restart: unless-stopped
volumes:
- calcom_db:/var/lib/postgresql/data
environment:
POSTGRES_USER: calcom_user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: calendso
networks:
- calcom_net
calcom:
image: calcom/cal.com:latest
restart: unless-stopped
depends_on:
- database
env_file:
- .env
ports:
- "127.0.0.1:3000:3000"
networks:
- calcom_net
networks:
calcom_net:
volumes:
calcom_db:
Обратите внимание: порт приложения 3000 пробрасывается только на 127.0.0.1 — снаружи он недоступен, наружу его откроет Nginx через reverse proxy с SSL. Пароль базы вынесен в переменную окружения .env, чтобы не хранить секрет прямо в compose-файле.
Официальный образ calcom/cal.com довольно тяжёлый и требователен к переменным окружения — если что-то из обязательных полей не задано, контейнер может падать при старте с понятной ошибкой в логах. Проверяйте docker compose logs calcom после первого запуска, прежде чем разбираться дальше.
Переменные окружения: ключи и почта
Создайте файл /opt/calcom/.env — в него уйдут и настройки Postgres, и секреты самого Cal.com:
# Пароль базы (тот же, что в docker-compose.yml)
POSTGRES_PASSWORD=замените_на_длинный_случайный_пароль
# Подключение к БД
DATABASE_URL=postgresql://calcom_user:замените_на_длинный_случайный_пароль@database:5432/calendso
DATABASE_DIRECT_URL=postgresql://calcom_user:замените_на_длинный_случайный_пароль@database:5432/calendso
# Адрес, по которому доступен сервис
NEXTAUTH_URL=https://cal.example.com
NEXT_PUBLIC_WEBAPP_URL=https://cal.example.com
# Секреты приложения — сгенерируйте свои, не используйте примеры ниже
NEXTAUTH_SECRET=сюда_вывод_openssl
CALENDSO_ENCRYPTION_KEY=сюда_вывод_openssl
# Почта для писем-подтверждений и напоминаний
EMAIL_FROM=noreply@example.com
EMAIL_SERVER_HOST=smtp.example.com
EMAIL_SERVER_PORT=587
EMAIL_SERVER_USER=smtp_user
EMAIL_SERVER_PASSWORD=smtp_password
# Отключить отправку телеметрии разработчикам Cal.com
CALCOM_TELEMETRY_DISABLED=1
Секреты сгенерируйте на самом сервере, а не берите из примеров в интернете:
openssl rand -base64 32 # для NEXTAUTH_SECRET
openssl rand -base64 24 # для CALENDSO_ENCRYPTION_KEY
Про SMTP — Cal.com сам почту не рассылает, ему нужен внешний сервер (Postfix на этом же VPS, Yandex 360, Mailgun, Postmark и т.д.). Если письма с подтверждением бронирования не доходят, проблема почти всегда либо в неверных EMAIL_SERVER_*, либо в блокировке 587/465 у хостера, либо в SPF/DKIM домена отправителя — типовые причины и способы диагностики разобраны в статье «не отправляется почта с сервера».
Список переменных окружения у Cal.com со временем меняется (добавляются интеграции, флаги фич) — перед деплоем сверьтесь с .env.example в официальном репозитории проекта, чтобы не упустить что-то новое.
Nginx как reverse proxy и SSL-сертификат
Cal.com слушает 127.0.0.1:3000 — снаружи его открывает Nginx с TLS-терминацией. Если Nginx как reverse proxy ещё не настроен на сервере, пошаговая установка есть в статье про Nginx как reverse proxy на VPS. Конфиг для Cal.com — /etc/nginx/sites-available/calcom:
server {
listen 80;
server_name cal.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Заголовки Upgrade/Connection "upgrade" нужны для WebSocket-соединений, которые использует Next.js в режиме разработки логики бронирования в реальном времени. Активируйте конфиг и получите сертификат Let's Encrypt:
sudo ln -s /etc/nginx/sites-available/calcom /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d cal.example.com
Подробности выпуска и автопродления сертификата, а также типовые ошибки certbot — в статье про установку Let's Encrypt SSL на VPS. После certbot Nginx сам допишет блок listen 443 ssl и редирект с 80 на 443 — проверьте итоговый конфиг перед перезапуском.
Первый запуск, миграции и подключение календаря
Когда .env заполнен и Nginx настроен, поднимайте стек:
cd /opt/calcom
docker compose up -d
docker compose logs -f calcom
При первом старте контейнер накатывает миграции Prisma поверх пустой базы — в логах это видно по строкам о применении миграций. Если через минуту-другую логи показывают, что сервис слушает порт 3000 без ошибок подключения к БД, откройте https://cal.example.com в браузере.
Дальше:
- Пройдите мастер первичной настройки (
/auth/setup) — там создаётся первый аккаунт администратора. Используйте сложный пароль, это фактически root-доступ ко всей системе бронирований. - Задайте базовый тип события (например, «30-минутный созвон») и часовой пояс по умолчанию для команды.
- Подключите календарь для проверки занятости — Google Calendar, Office 365 или CalDAV. Для Google Calendar понадобится создать OAuth-приложение в Google Cloud Console и прописать client ID/secret в переменные окружения (
GOOGLE_API_CREDENTIALSили аналог, в зависимости от текущей версии образа) — это отдельная, не самая тривиальная настройка, дайте на неё время. - Проверьте, что письмо-подтверждение при тестовом бронировании реально приходит — если нет, возвращайтесь к разделу про SMTP.
Не забудьте про бэкапы: база — единственное, что жалко потерять. Простой вариант — ежедневный pg_dump из контейнера базы в cron:
docker compose exec -T database pg_dump -U calcom_user calendso | gzip > /opt/calcom/backups/calendso-$(date +%F).sql.gz
Храните архивы не только на самом VPS, но и вне сервера — на случай, если с сервером что-то случится целиком.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужен ли отдельный сервер только под Cal.com?
Нет, если у вас уже есть VPS с Docker и свободными 2+ ГБ RAM — Cal.com спокойно уживается рядом с другими контейнерными сервисами на общем хосте.
Можно ли запустить без Docker, напрямую из исходников?
Технически да — Cal.com собирается через Yarn/pnpm как обычное Next.js-приложение, но тогда вы вручную отвечаете за Node.js, процесс-менеджер и обновления зависимостей. Docker Compose проще поддерживать в долгую.
Что будет с данными при обновлении образа calcom/cal.com:latest?
Миграции Prisma применяются автоматически при старте нового контейнера, но перед любым major-обновлением сделайте pg_dump — не все миграции обратимы, а откат версии образа откат схемы БД не делает.
Почему письма с приглашениями не приходят, хотя SMTP настроен верно?
Часто дело не в самом Cal.com, а в SPF/DKIM домена отправителя или в том, что почтовый провайдер помечает письма как спам — проверьте домен через инструменты вроде mail-tester и посмотрите статью про недоставленную почту с сервера.
Заменяет ли self-hosted Cal.com команду поддержки облачного тарифа?
Нет — вы получаете контроль над данными и отсутствие лимитов, но диагностика падений, апдейтов и совместимости версий теперь на вас или на вашем администраторе.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →