Frappe CRM в Docker: разворачиваем на своём сервере рядом с ERPNext
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 оставляйте разработчикам.
- Linux-сервер с Docker и плагином Docker Compose v2.
- Домен или поддомен с A-записью на IP сервера, например crm.example.com.
- Открытые порты 80 и 443 для выпуска сертификата и работы по HTTPS.
- Решение: отдельный стенд CRM или общая установка с ERPNext.
- Стабильная версия (main, 1.x), а не 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 или порт 80 | A-запись, файрвол, 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. Свой прокси тоже подойдёт.
Источники
- README репозитория frappe/crm — Проверены команды easy-install deploy с параметрами, образ ghcr.io/frappe/crm, тестовый docker-compose и init.sh, адрес crm.localhost:8000/crm, логин Administrator и пароль admin, таблица совместимости с Frappe и ERPNext. https://github.com/frappe/crm/blob/develop/README.md
- Файлы docker/docker-compose.yml и docker/init.sh в frappe/crm — Проверено содержимое тестового стенда: frappe/bench:latest, mariadb:10.8, пароль 123, bench init version-15, режим разработчика. https://github.com/frappe/crm/tree/develop/docker
- Скрипт easy-install.py — Проверены параметры deploy, расписание резервных копий @every 6h, генерация паролей и файла проекта, ключи --no-ssl и --http-port. https://frappe.io/easy-install.py
- frappe_docker: compose.https.yaml и compose.backup-cron.yaml — Проверено: Traefik, httpChallenge, переменные SITES_RULE и LETSENCRYPT_EMAIL; ofelia с командой bench --site all backup без --with-files. https://github.com/frappe/frappe_docker/tree/main/overrides
- frappe_docker: docs, неизменяемость образов и сборка — Проверено: установка приложений в запущенный контейнер не поддерживается, apps.json передаётся как секрет BuildKit, пример cron с --with-files. https://github.com/frappe/frappe_docker/blob/main/docs/01-getting-started/02-docker-immutability.md
- frappe_docker: compose.yaml и pwd.yml — Проверено 01.10.2026: сервисы configurator, backend, frontend, websocket, queue-short (short,default), queue-long (long,default,short), scheduler, db с healthcheck, redis-cache, redis-queue, create-site; ofelia в compose.backup-cron.yaml выполняет «bench --site all backup» по BACKUP_CRONSTRING, по умолчанию @every 6h. https://github.com/frappe/frappe_docker/blob/main/pwd.yml
