Frappe CRM в Docker: установка на свой сервер, прокси, настройка
АйТи Фреш
Linux, Docker и DevOps

Frappe CRM в Docker: разворачиваем на своём сервере рядом с ERPNext

Автор: , директор ООО «АйТи-Фреш» · · ~17 мин чтения
Ряд контейнеров на причале, в одном виден стол агента недвижимости, человек проверяет замок: Frappe CRM в Docker
Каждое приложение в своём контейнере, а ключи и копии под вашим контролем.

Frappe CRM в Docker ставится двумя путями: для работы скриптом easy-install с образом ghcr.io/frappe/crm, для проверки тестовым docker-compose из репозитория. Ниже требования к серверу и домену, команды, соседство с ERPNext, HTTPS, бэкап и типичные поломки после установки.

Что нужно перед установкой: сервер, домен и версия

Перед любыми командами определите три вещи: на каком сервере будет жить система, под каким доменом её откроют сотрудники и какая версия Frappe CRM вам нужна. Frappe CRM — приложение на платформе Frappe, того же семейства, что и ERPNext, поэтому нужно ещё решить, будет ли оно стоять отдельным стендом или в одной установке с ERPNext. Если вы выбираете между системами учёта в целом, посмотрите на ERPNext под ключ: там же описано, как мы ведём такие проекты. В этой статье я разбираю именно установку CRM, и я проверял каждую команду по README репозитория frappe/crm и по исходникам скрипта easy-install.

Требования к серверу сводятся к простому набору. Нужен Linux-сервер с Docker и плагином Docker Compose v2: скрипт easy-install вызывает команду docker compose, а не старый docker-compose. Нужен домен, например crm.example.com, с A-записью на IP сервера, потому что для HTTPS прокси получает сертификат Let's Encrypt методом проверки по HTTP (httpChallenge), и порты 80 и 443 сервера должны быть доступны из интернета. Про основы Docker полезно прочитать руководство для начинающих по Docker, если вы работаете с контейнерами впервые.

Про ресурсы я не назову точных цифр, потому что не нашёл их в документации Frappe CRM и не хочу выдумывать. Мой практический порядок такой: для проверки хватит небольшого виртуального сервера, а для пилота на 10–30 пользователей закладывайте запас по памяти, потому что в стеке работают MariaDB, Redis и несколько воркеров. Точную нагрузку нужно измерять на ваших данных во время пилота.

Теперь про версию. По таблице совместимости в README ветка main (версия 1.x) считается стабильной и поддерживает Frappe и ERPNext 15 и 16, а ветка develop (будущая 2.x) помечена как нестабильная и рассчитана на develop-ветку Frappe. Это сведения из README на момент написания, проверьте таблицу в репозитории в день установки. Практический вывод: для рабочего стенда берите стабильную версию, а develop оставляйте разработчикам.

Быстрый путь: easy-install.py и образ ghcr.io/frappe/crm

Для рабочей установки README предлагает скрипт easy-install. Он скачивается с официального адреса и запускается командой deploy. Вот команды из README с моими поясняющими подписями:

wget https://frappe.io/easy-install.py

python3 ./easy-install.py deploy \
    --project=crm_prod_setup \
    --email=admin@example.com \
    --image=ghcr.io/frappe/crm \
    --version=stable \
    --app=crm \
    --sitename crm.example.com

Параметр --project задаёт имя проекта Compose, --email нужен для сертификата, --image указывает образ Frappe CRM, --version=stable берёт стабильный тег, --app=crm говорит, какое приложение ставить на сайт, а --sitename задаёт домен. По заявлению README, скрипт разворачивает рабочий экземпляр за пять минут. У меня на чистой машине скорость определяется скачиванием образов, и пять минут — реальная цифра для быстрого канала, но не гарантия.

Что именно делает скрипт, я разобрал по его исходникам. Он создаёт в домашнем каталоге файл ~/crm_prod_setup-compose.yml (имя собирается из названия проекта), генерирует пароли и записывает их в файл ~/crm_prod_setup-passwords.txt в виде двух строк: ADMINISTRATOR_PASSWORD и MARIADB_ROOT_PASSWORD. Итоговый compose собирается из готовых дополнений frappe_docker: MariaDB, Redis, HTTPS через Traefik и контейнер с расписанием резервных копий. Параметры --no-ssl и --http-port отключают HTTPS и открывают сайт по обычному порту, если сертификат вам не нужен.

Сразу после установки сделайте три вещи. Откройте файл с паролями, войдите на сайт под Administrator и смените пароль на свой, а файл с исходными паролями перенесите в менеджер паролей и удалите с сервера. Проверьте, что сайт открывается по HTTPS без предупреждений. Убедитесь, что контейнеры запущены командой docker compose -p crm_prod_setup ps. Если сайт не открывается, первым делом проверьте DNS и доступность порта 80 снаружи: сертификат не выпустится, пока проверка Let's Encrypt не дойдёт до сервера.

Одно предупреждение про версию образа. Тег stable удобен на старте, но дальше версию нужно фиксировать и обновлять по плану, а не позволять образу обновиться при перезапуске. В примере окружения frappe_docker версию ERPNext задают явным номером именно для этого. Обновление скрипт тоже умеет: у него есть команда upgrade, но запускать её я рекомендую только после свежей полной копии.

Docker Compose для проверки: что поднимется и что сменить сразу

В README есть и второй способ: скачать тестовый файл docker-compose.yml и скрипт init.sh из репозитория и поднять стенд командой docker compose up -d. Важная деталь: в README этот способ описан в разделе для разработки, и это видно по содержимому файлов. Я прочитал оба. Compose использует образ frappe/bench:latest, базу mariadb:10.8 с корневым паролем 123 и запускает скрипт init.sh, который создаёт новый bench версии 15, ставит приложения whatsapp и crm, создаёт сайт crm.localhost с паролем администратора admin и включает режим разработчика, отключает отправку писем и разрешает Server Script.

Команды, которые описаны в README для такого стенда, такие:

mkdir frappe-crm
cd frappe-crm
wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/crm/develop/docker/docker-compose.yml
wget -O init.sh https://raw.githubusercontent.com/frappe/crm/develop/docker/init.sh
docker compose up -d

После запуска сайт доступен по адресу http://crm.localhost:8000/crm, логин Administrator, пароль admin. Первый запуск идёт долго, потому что bench создаётся с нуля, и следить за ним удобно командой docker compose logs -f frappe. Подождите, пока в логе появится запуск bench start.

Что здесь нужно понимать. Это стенд для знакомства: слабые пароли, режим разработчика, заглушённая почта, плавающий тег образа. Выставлять его в интернет нельзя. Если вы всё же держите его на сервере, смените пароль Administrator сразу, а наружу публикуйте только через прокси с HTTPS. Для знакомства с интерфейсом и пробного заведения лидов и сделок он подходит хорошо, а переносить данные с него в рабочую систему я не советую: проще заново поднять рабочую установку и загрузить данные туда.

Если нужно просто посмотреть, как выглядит и ведёт себя CRM, быстрее открыть демо на сайте Frappe, ссылка на которое есть в README. Тестовый стенд на своём сервере нужен, когда вы хотите проверить свои сценарии: свои этапы воронки, свои поля, интеграции с телефонией. В остальных случаях лучше сразу ставить через easy-install и не копить два разных окружения.

Рядом с ERPNext: приложение в готовом образе и мастер настройки

Frappe CRM умеет работать вместе с ERPNext: в README указано, что интеграция расширяет CRM выставлением счетов и бухгалтерией. Но поставить CRM в уже работающий контейнер ERPNext командой bench get-app нельзя. В документации frappe_docker сказано прямо: установка приложений в запущенный контейнер не поддерживается, потому что приложения и ассеты входят в образ, а изменения внутри контейнера пропадают при его пересоздании. Правильный путь: добавить приложение в сборку образа, пересобрать образ и заново развернуть стек.

Для общей установки вы описываете приложения в файле apps.json: каждое приложение со ссылкой на репозиторий и веткой. Все приложения должны быть одной мажорной версии Frappe, а таблица совместимости CRM говорит, что ветка main работает с версиями 15 и 16. Современная документация сборки frappe_docker передаёт этот файл как секрет BuildKit (параметр --secret=id=apps_json,src=apps.json), а не как аргумент сборки, потому что аргументы остаются видны в истории образа. Для этого нужен Docker Engine версии 23 и новее. Затем в запущенном стеке выполняется установка приложения на сайт командой bench --site имя install-app crm внутри контейнера backend.

Если вы ставили приложение интерактивно через docker exec, перезапустите все контейнеры стека целиком. В сообществе описан симптом: без перезапуска сайт отвечает ошибкой Internal Server Error, потому что процессы не подхватили новое приложение. Пробуйте на стенде и фиксируйте на нём, что именно потребовалось.

Отдельное предупреждение про версии. В сообществе описан случай, когда установка ветки develop приложения CRM ломала мастер первоначальной настройки ERPNext 15, и выходом было удалить приложение командой bench uninstall-app crm, выполнить миграцию и повторить мастер. Я не воспроизводил это сам, поэтому подаю как сообщение сообщества, а не как гарантию. Мой порядок для новой установки с обоими приложениями проще: сначала проходит мастер настройки ERPNext, затем ставится CRM стабильной ветки. И пока вы не уверены, держите CRM отдельным стендом: если не получится, вы не заденете рабочую систему учёта.

Чтобы понимать, что именно вы пересобираете и перезапускаете, держите в голове состав стека. В compose-файлах frappe_docker это frontend (nginx: маршрутизация и статика), backend (бизнес-логика), websocket (обновления в реальном времени), воркеры queue-short и queue-long, планировщик scheduler, redis-cache и redis-queue, база db (MariaDB с проверкой состояния) и одноразовые контейнеры configurator и create-site. Последние два после старта завершаются штатно, и статус exited у них не поломка. При сбое начинайте с docker compose ps: смотрите, какой контейнер не в состоянии running или healthy, и читайте логи именно его.

Прокси и HTTPS: что ломается при публикации

В easy-install за HTTPS отвечает Traefik, который читает метки контейнеров. По исходнику дополнения compose.https.yaml он слушает порты 80 и 443, перенаправляет HTTP на HTTPS и получает сертификат Let's Encrypt методом httpChallenge. Правило маршрутизации берётся из переменной SITES_RULE, а адрес для сертификата из переменной LETSENCRYPT_EMAIL. Если вы вручную правите файл окружения, помните, что старая переменная SITES помечена в скрипте устаревшей и заменяется на SITES_RULE.

Типичные поломки при публикации укладываются в четыре пункта. Первый: DNS не указывает на сервер, сертификат не выпускается. Второй: порт 80 закрыт файрволом, проверка Let's Encrypt не проходит. Третий: шаблон Traefik рассчитан на публичный домен, и на localhost он отдаёт 404, это нормально и не лечится настройкой: для локальной проверки используйте --no-ssl. Четвёртый: пароль в файле .env содержит спецсимволы, и хэш нужно экранировать и брать в кавычки, иначе файл разбирается неверно. Последнее я привожу по сообщениям сообщества, а у пароля из скрипта easy-install спецсимволов быть не должно.

Если у вас уже есть общий обратный прокси на сервере, например nginx или Caddy, скрипт можно запустить без HTTPS и опубликовать сайт через свой прокси. Сравнение подходов есть в материале про Caddy и nginx, а про автоматизацию сертификатов — в статье про автоматизацию SSL-сертификатов. Главное правило публикации: наружу смотрит только прокси, а база данных и Redis порты на внешний интерфейс не открывают.

СимптомВероятная причинаЧто проверить
Сертификат не выпускаетсяDNS или порт 80A-запись, файрвол, docker compose logs proxy
404 на localhost при TraefikШаблон ждёт публичный доменЗадать домен или --no-ssl
Ошибка разбора .envСпецсимволы в хэше пароляЭкранировать и взять в кавычки
Internal Server Error после install-appКонтейнеры не перезапущеныПерезапустить стек целиком

«Адрес-Плюс Север»: стенд для агентства недвижимости на 25 рабочих мест

Условный пример: агентство недвижимости «Адрес-Плюс Север», 25 рабочих мест, менеджеры и агенты. Заказчик хотел попробовать собственную CRM без платы за каждого пользователя и без передачи клиентской базы стороннему сервису. Числа в разборе условные и показывают ход работ, а не результат реального клиента. Цель стенда — за неделю проверить, ложатся ли на систему их этапы воронки: заявка, показ, задаток, сделка.

Порядок был такой. Взяли отдельный сервер под CRM, не трогая учётную систему. Завели поддомен и A-запись, поставили Docker, запустили easy-install с проектом и стабильной версией. Открыли файл с паролями, сменили пароль Administrator, перенесли пароли в менеджер паролей. Проверили HTTPS, завели трёх тестовых пользователей и прогнали десяток тестовых лидов от заявки до сделки. Решили, что ERPNext к CRM пока не подключаем: сначала пилот на стабильной версии, потом отдельная задача по интеграции.

Две вещи вскрылись при первой проверке. Во-первых, расписание резервных копий, которое подключил скрипт, копировало только базу, без вложений (договоры и сканы агенты прикрепляют к карточкам). Во-вторых, у агентства был свой домен с настроенной почтой, и без отправки писем тестовые рассылки не работали, пока не настроили почтовый аккаунт. Оба вопроса закрыли до пилота, а не после. Если вам нужна такая же проверка на вашем сервере, мы делаем её в рамках внедрения open source.

Бэкап и проверка перед пилотом

Про бэкап в easy-install нужно знать точно. Скрипт подключает контейнер планировщика ofelia, который по расписанию из переменной BACKUP_CRONSTRING (по умолчанию каждые шесть часов) выполняет команду bench --site all backup. У этой команды нет флага --with-files, поэтому копируются база и конфигурация сайта, а вложения нет. Документация frappe_docker в примере для cron использует другую строку: docker compose -p erpnext exec backend bench --site all backup --with-files. Выбирайте вторую.

Править собранный скриптом compose-файл вручную я не советую: скрипт собирает его заново при повторном запуске, и ваши правки пропадут. Надёжнее добавить задачу в cron хоста:

# crontab -e на сервере CRM
0 2 * * * docker compose -p crm_prod_setup exec -T backend bench --site all backup --with-files >> /var/log/crm-backup.log 2>&1

Флаг -T отключает интерактивный терминал, без него cron-задача с exec может падать. Копии лежат в томе sites внутри контейнера, в каталоге сайта private/backups, и их нужно регулярно переносить на другой сервер. Подробно про стратегию копирования серверов есть материал про резервное копирование Linux-сервера.

Перед пилотом я прохожу короткую проверку. Первое: сменён ли пароль Administrator и убраны ли исходные пароли с диска. Второе: открывается ли сайт по HTTPS и закрыты ли внешние порты базы и Redis. Третье: лежит ли в каталоге копий комплект с вложениями и восстанавливается ли он на отдельном тестовом стенде командой bench --site имя restore. Четвёртое: зафиксирована ли версия образа и есть ли план обновления. Не используйте на рабочем стенде команду docker compose down -v: ключ -v удаляет тома вместе с данными.

Об ограничениях честно. Frappe CRM молодая система, и стабильная ветка меняется быстрее, чем типичная коробочная CRM, поэтому обновления нужно проверять на тестовом стенде. Я бы пилотировал на небольшой группе, а решение о переходе всей команды принимал после месяца работы. Для задач с глубокой телефонией, маркетинговыми рассылками или сложной аналитикой сначала сверьте возможности с вашим списком требований, а при необходимости сравните с другими решениями, например с EspoCRM, которую мы тоже ставим на отдельный VPS.

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

Как установить Frappe CRM через Docker?

Для рабочей установки скачайте easy-install.py и запустите deploy с образом ghcr.io/frappe/crm, версией stable, приложением crm, доменом и почтой для сертификата. По README это занимает около пяти минут. Для проверки есть тестовый docker-compose.yml и init.sh из репозитория frappe/crm: docker compose up -d. Команды сверяйте с README на дату установки.

Какой логин и пароль у Frappe CRM после установки?

В тестовом compose из README по умолчанию Administrator и admin, сайт открывается на crm.localhost:8000/crm. Пароль нужно сменить сразу, такие учётные данные нельзя оставлять. Скрипт easy-install генерирует случайные пароли и пишет их в файл проекта в домашнем каталоге, откуда их переносят в менеджер паролей.

Можно ли поставить Frappe CRM в тот же сервер, где ERPNext?

Можно, но не командой bench get-app в рабочем контейнере: в готовом образе приложения не добавляют. Нужен свой образ со всеми приложениями в apps.json и одной мажорной версией Frappe, затем install-app на сайте. По сообщениям сообщества, ветка develop ломала мастер настройки ERPNext 15, поэтому берите стабильную main.

Сколько ресурсов нужно Frappe CRM?

Точных цифр в документации я не нашёл. Для проверки хватит небольшого VPS, а для 10–30 пользователей закладывайте запас по памяти, потому что работают MariaDB, Redis и несколько воркеров. Реальную нагрузку измеряют на ваших данных на пилоте, а потом расширяют сервер при необходимости.

Почему после установки приложения сайт выдаёт Internal Server Error?

Если приложение ставили интерактивно через docker exec, нужно полностью перезапустить все контейнеры compose-проекта. Без перезапуска Frappe не подхватывает новое приложение, а в готовом образе приложения вообще добавляют пересборкой образа. Проверьте логи контейнера backend командой docker compose logs backend: в них будет видна причина ошибки, а не только общий код ответа сервера.

Как настроить HTTPS для Frappe CRM?

В easy-install за HTTPS отвечает Traefik, он получает сертификат Let's Encrypt проверкой по протоколу HTTP. Нужны публичный домен с A-записью на сервер, открытые порты 80 и 443 и почта в LETSENCRYPT_EMAIL. На localhost Traefik вернёт 404, для локальных проверок используют параметр --no-ssl. Свой прокси тоже подойдёт.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи