Установка ERPNext на свой сервер через Docker: схема для продакшена, а не для демо
Установка ERPNext для работы делается через официальный репозиторий frappe_docker: базовый compose.yaml, оверрайды для MariaDB, Redis и прокси, отдельный образ со своими приложениями и версии с фиксированным тегом. Ниже: из чего состоит стек, как создать сайт и чего не делать на боевой системе.
Из чего состоит продакшен-стек ERPNext в Docker и что подготовить до установки
Сначала различим два сценария. Файл pwd.yml в репозитории frappe_docker это одноразовое демо: в README прямо сказано, что оно для короткого знакомства, и в такой установке нельзя добавить свои приложения. Для работы используется compose.yaml плюс набор оверрайдов (папка overrides). Если вам нужен ERPNext «под ключ» без возни с контейнерами, посмотрите нашу страницу про внедрение ERPNext под ключ; если вы ставите сами, читайте дальше.
Базовый compose.yaml (проверен 01.10.2026 по ветке main) описывает такие сервисы: backend (Frappe на Gunicorn), frontend (Nginx, слушает порт 8080), websocket (Socket.IO), queue-short и queue-long (воркеры очередей), scheduler (планировщик) и configurator (одноразовый). Базу и кэш он не включает: MariaDB подключается оверрайдом compose.mariadb.yaml, Redis оверрайдом compose.redis.yaml. Это сделано специально, чтобы можно было подключить внешнюю базу.
Таблица ниже повторяет инфографику и пригодится как шпаргалка при диагностике. Имена сервисов я привожу по актуальному compose; в более старых материалах (в том числе в нашей базе знаний) воркеры называются иначе и есть отдельный контейнер create-site, поэтому свои имена всегда сверяйте с файлом выбранного релиза. | Контейнер | Что делает | Важная деталь | |---|---|---| | frontend | Nginx: вход, статика, прокси | Порт 8080 внутри контейнера | | backend | Приложение Frappe (Gunicorn) | GUNICORN_WORKERS и GUNICORN_THREADS, в example.env 2 и 4 | | websocket | Socket.IO для живых уведомлений | Порт 9000 внутри сети | | queue-short, queue-long | Фоновые задачи: письма, импорт, тяжёлые операции | Если упали, письма и импорт встают | | scheduler | Периодические задачи | Без него не идут регулярные операции | | db (оверрайд) | MariaDB | Healthcheck, том db-data | | redis-cache, redis-queue (оверрайд) | Кэш и очередь | Очередь хранит данные на томе | | configurator | Прописывает общий конфиг и завершается | Выход с кодом 0 нормален |
Нужны Linux-сервер (Ubuntu LTS подходит, документация frappe_docker исходит именно из него), Docker Engine, Docker Compose v2 и git. Если вы собираете свой образ, Docker Engine должен быть версии 23 или новее: сборка использует секреты BuildKit, а старые версии либо падают, либо молча откатываются на устаревший сборщик, где секреты не работают. Домен должен смотреть на публичный IP сервера, если вы хотите автоматический сертификат; для внутреннего доступа в ЛВС публичный домен не нужен.
Про железо. В обзорах сообщества минимум для запуска в Docker это 1 ГБ памяти, 1 ГБ swap и один процессор, но это порог «запустится», а не «будет работать для команды». Для компании на два десятка человек я закладываю от 4 до 8 ГБ памяти, и подробный расчёт вынесен в отдельный материал про требования к серверу. Диск считайте с запасом под файлы и резервные копии, а копии храните не только на том же сервере.
Windows и WSL для боевой работы не рекомендую. В обсуждениях сообщества Frappe их называют причиной сильной потери производительности, и в самой документации frappe_docker есть отдельная страница про ошибку точки входа Nginx в Windows. Если у вас парк на Windows, ставьте ERPNext на отдельную Linux-виртуальную машину; общие принципы про контейнеры, которые мы разбирали в статье про Docker Compose в продакшене, здесь тоже работают.
Как поднять сайт через frappe_docker и не испугаться остановленных контейнеров
Порядок такой. Клонируем репозиторий, копируем example.env в свой файл (например, custom.env), фиксируем версию образа в ERPNEXT_VERSION и меняем пароль базы DB_PASSWORD (значение по умолчанию в шаблоне слабое). Затем генерируем итоговый compose-файл из базового и нужных оверрайдов и запускаем его. Команды ниже взяты из документации репозитория и обезличены; пароли и имена замените на свои.
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
cp example.env custom.env
# в custom.env: ERPNEXT_VERSION=<конкретный тег>, DB_PASSWORD=<свой пароль>
docker compose --env-file custom.env \
-f compose.yaml \
-f overrides/compose.mariadb.yaml \
-f overrides/compose.redis.yaml \
-f overrides/compose.noproxy.yaml \
config > compose.custom.yaml
docker compose -p frappe -f compose.custom.yaml up -dСайт нужно создать отдельной командой, он сам не появляется. Подождите, пока запустится база и завершится configurator (обычно секунд десять), затем:
docker compose -p frappe exec backend bench new-site erp.example.com \
--mariadb-user-host-login-scope='%' \
--db-root-password '<пароль базы>' \
--admin-password '<пароль администратора>' \
--install-app erpnextКлюч --mariadb-user-host-login-scope нужен потому, что контейнеры получают динамические адреса: в документации frappe_docker показан вариант '172.%.%.%' для адресов Docker и '%' в примере со вторым пользователем. Для боевой системы выбирайте тот диапазон, который соответствует вашей сети контейнеров, а не «всем подряд» без причины.
Что вас испугает в docker ps -a: контейнер configurator находится в состоянии Exited. Это штатно, он только записывает общий конфиг (адреса базы и Redis, порт Socket.IO) и завершается; другие сервисы стартуют после его успешного завершения. В демо-файле pwd.yml есть ещё одноразовый create-site, в боевом compose.yaml его нет. Если сайт не создаётся, смотрите логи команды bench new-site и убедитесь, что база к этому моменту уже здорова (healthcheck).
Проверка результата: сайт открывается по домену, входит Administrator, тестовое письмо уходит, а в docker compose ps все постоянные сервисы в статусе running. Если сайт открывается по IP, но не по имени, сверьте переменную FRAPPE_SITE_NAME_HEADER: по умолчанию имя сайта берётся из заголовка Host, и оно должно совпадать с именем сайта.
Как добавить свои приложения: сборка образа вместо bench get-app
В готовом образе нет сборочных инструментов, поэтому bench get-app в боевом контейнере не работает, а ручная установка через docker exec исчезнет при пересоздании контейнера. Правильный путь: собственный образ. Вы пишете файл apps.json со списком репозиториев и веток и собираете образ из репозитория frappe_docker. Все приложения должны быть одной мажорной ветки, например version-16.
Важное уточнение к тому, что вы найдёте в старых руководствах. В них apps.json передавали как переменную APPS_JSON_BASE64. В актуальной документации (проверено 01.10.2026) файл передаётся как секрет BuildKit, чтобы токены частных репозиториев не попадали в слои образа, а --build-arg для этого файла прямо не рекомендуется.
cat > apps.json <<'EOF'
[
{"url": "https://github.com/frappe/erpnext", "branch": "version-16"},
{"url": "https://github.com/example/custom_app", "branch": "version-16"}
]
EOF
docker build \
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
--build-arg=FRAPPE_BRANCH=version-16 \
--secret=id=apps_json,src=apps.json \
--tag=custom:16 \
--file=images/layered/Containerfile .Дальше в env-файле указываются CUSTOM_IMAGE=custom, CUSTOM_TAG=16 и PULL_POLICY=missing: иначе Docker попытается скачать образ из реестра вместо локального (по умолчанию политика always). После сборки приложение устанавливают на сайт: bench --site erp.example.com install-app custom_app. Для регулярной сборки в CI используют тот же файл apps.json, а образ фиксируют версией, а не latest.
Мой совет по приложениям. Каждое лишнее приложение это расходы на обновление: перед обновлением версии нужно проверить совместимость каждого. Поэтому в образ кладите только необходимое, а доработки храните в собственном репозитории с тегами релизов.
Домен и SSL: прокси, Traefik и частые ошибки конфигурации
В репозитории есть несколько готовых оверрайдов для доступа. Самый простой, compose.noproxy.yaml, публикует порт 8080 наружу: подходит для проверки и для ситуации, когда перед ERPNext стоит ваш собственный обратный прокси. Для автоматических сертификатов Let's Encrypt есть оверрайд compose.https.yaml с Traefik: в него передаются почта для ACME (LETSENCRYPT_EMAIL) и правило сайта (SITES_RULE, например Host с вашим доменом), а порты 80 и 443 публикуются Traefik. Есть и варианты с nginx-proxy и Caddy, о выборе между ними в документации есть отдельные страницы.
Типичные ошибки по моим проектам такие. Первая: шаблон с Traefik рассчитан на публичное доменное имя, и по localhost он отдаёт 404. Вторая: хэш пароля для панели Traefik в env-файле нужно брать в одинарные кавычки, иначе символ доллара ломает разбор. Третья: домен ещё не смотрит на сервер, а порт 80 закрыт файрволом, и сертификат не выпускается. Четвёртая: Docker сам добавляет правила iptables и может открыть порт, который вы закрыли в ufw; про это у нас отдельный материал про порт, доступный вопреки UFW.
Если за ERPNext стоит ваш прокси, настройте доверенный адрес и заголовок реального IP: переменные UPSTREAM_REAL_IP_ADDRESS и UPSTREAM_REAL_IP_HEADER в env-файле. Ещё два параметра часто забывают до первой жалобы: PROXY_READ_TIMEOUT (по умолчанию 120 секунд, увеличивают для длинных печатных форм) и CLIENT_MAX_BODY_SIZE (по умолчанию 50m, нужен для крупных вложений). Если вы меняете лимит загрузки в самом Frappe, меняйте и этот.
Чего не делать на боевой системе: latest, down -v и бэкап только базы
Три запрета, которые я проговариваю на каждом проекте. Первый: тег latest в боевой системе. Образ при перезапуске может смениться на другую версию, и сайт после очередного pull получит миграцию, которой вы не ожидали; в compose-файле репозитория стоит политика always, так что версию надо фиксировать, а политику выбирать сознательно. Второй: docker compose down -v. Ключ -v удаляет тома, а в томах лежат сайты и база. Для остановки используйте docker compose down без этого ключа, а для удаления данных нужна ваша осознанная команда с резервной копией в руках.
Третий: резервная копия «только базы». Для восстановления нужны база и файлы сайта (публичные и приватные). В документации frappe_docker показан такой запуск по расписанию: docker compose -p <проект> exec backend bench --site all backup --with-files в cron, например каждые шесть часов. Копии складывайте вне хоста, а восстановление проверяйте на стенде, не на боевой системе. Сроки хранения и автоматическое удаление старых копий в bench backup проверьте в своей версии, не рассчитывайте на очистку по умолчанию.
Дополнительно: следите за томами и местом на диске. Том sites растёт вместе с файлами и копиями, и когда диск заканчивается, MariaDB падает первой. Простейший сторож: алерт на заполнение диска и на остановку контейнеров. Откат версии БД как отдельной операции в ERPNext не предусмотрен: вернуться на предыдущую версию можно только восстановлением из резервной копии, поэтому обновления делают сначала на копии. Подробно обновления разбираются в нашем материале про переход между версиями.
Как «Чертёж-Бюро Юг» на 23 рабочих места запускалась и что проверили перед пуском
Условный пример, цифры вымышленные. Проектная фирма «Чертёж-Бюро Юг», 23 рабочих места: архитекторы, конструкторы, два руководителя проектов, бухгалтерия. Задача: внутренняя система для проектов, закупок и часов на собственном сервере, без зависимости от внешнего облака. Выбрали виртуальную машину Ubuntu LTS на 8 ГБ памяти и 100 ГБ диска, внутри Docker, схема из compose.yaml с оверрайдами MariaDB, Redis и Traefik для сертификата. Для сайта выделили поддомен рабочей фирмы, а версию образа зафиксировали тегом.
До пуска прогнали пять проверок, и две из них нашли проблемы. Первая: остановили контейнер базы и запустили снова, смотря логи healthcheck; всё поднялось, но выяснилось, что сервис backend стартовал раньше, чем база была готова. Исправили зависимостью. Вторая: сделали резервную копию с файлами, удалили тестовый документ, восстановили; документ вернулся, но файл вложения не вернулся, потому что копию делали без ключа с файлами. Правильную команду закрепили в cron. Третья: вход под ролью руководителя проекта: создаёт и правит задачи, но не удаляет проекты. Четвёртая: установка PWA на телефон: табличная часть заявки показалась мелкой, расширили поля. Пятая: убедились, что в compose нет latest и теги закреплены.
Что сказали заказчику заранее. PWA не работает офлайн, без связи с сервером данные не внести, и это надо понимать до выезда на объект. Живой сервер ставит на себя ответственность за копии и обновления: за это и берётся сопровождение, условия которого описаны на странице продукта. Результат условного запуска: стенд собран за рабочий день, переход с тестовых данных на боевые занял ещё день, и главное, что инфраструктура описана в одном репозитории с env-файлом и compose-файлом, а не лежит «в голове» администратора.
Где такая схема не подходит
Docker-схема на одном сервере масштабируется вертикально: так описано и в документации frappe_docker для единого сервера. Если вам нужна отказоустойчивость на нескольких узлах, понадобится другая архитектура: внешняя база, общее хранилище файлов, оркестратор. Это уже проект сложнее типового, и оценивать его надо отдельно. Для команды в два десятка человек единая виртуальная машина с хорошими копиями обычно оправдана.
Вторая граница: самостоятельная установка требует навыков администрирования. Если некому следить за копиями, обновлениями и местом на диске, лучше взять сопровождение. Третья: сравнивая установку ERPNext с другими системами на Docker, не рассчитывайте на одинаковую процедуру: у EspoCRM и Odoo свои образы, свои тома и свои грабли. И четвёртая: общие советы из блога не заменяют проверку на вашей версии, поэтому выбранный релиз и compose-файл нужно перечитать перед запуском.
Частые вопросы
Какая установка ERPNext считается правильной для продакшена?
Сообщество Frappe считает основным способом контейнеры по официальному репозиторию frappe_docker: базовый compose.yaml, оверрайды для MariaDB, Redis и прокси, фиксированный тег образа. Файл pwd.yml предназначен для одноразового демо. Windows и WSL для боевой работы не рекомендуются из-за потери производительности, лучше отдельная Linux-машина.
Почему остановился контейнер configurator после запуска ERPNext?
Это штатное поведение. Configurator записывает общий конфиг: адреса базы и Redis, порт Socket.IO, и завершается, остальные сервисы ждут его успешного завершения. Статус Exited с кодом 0 нормален. Если сайт не появился, смотрите вывод команды bench new-site и состояние healthcheck базы, а не сам configurator.
Почему bench get-app не работает внутри контейнера ERPNext?
В готовых образах нет инструментов сборки, а установка вручную пропадёт при пересоздании контейнера. Свои приложения добавляют сборкой собственного образа: список репозиториев в apps.json передаётся как секрет BuildKit, все приложения одной мажорной ветки, например version-16. В старых руководствах встречается APPS_JSON_BASE64, сверяйтесь с актуальной документацией.
Хватит ли для ERPNext сервера на 1 ГБ памяти?
Для запуска демонстрации в Docker в обзорах называют минимум 1 ГБ памяти, 1 ГБ swap и один процессор. Для рабочей команды закладывайте 4–8 ГБ: фоновые воркеры, MariaDB и Redis требуют запаса, плюс место под файлы и копии. Точный расчёт зависит от числа пользователей и объёма данных.
Как обновлять ERPNext в Docker и не потерять данные?
Данные лежат в постоянных томах, поэтому docker compose down -v запрещён. Версии образов фиксируют тегом, не используют latest, перед обновлением делают полную копию с файлами и проверяют обновление на стенде. Отката версии базы нет: вернуться можно только восстановлением из резервной копии, сделанной до обновления.
Как делать резервные копии ERPNext в Docker?
В документации frappe_docker для одного хоста предложен запуск bench --site all backup --with-files по расписанию, например каждые шесть часов, и отправка копий во внешнее хранилище (в примере restic). Копия без ключа с файлами не вернёт вложения. Восстановление проверяйте на стенде, а не после аварии.
Источники
- frappe_docker: compose.yaml и example.env (ветка main) — Проверено 01.10.2026: сервисы backend, frontend, websocket, queue-short, queue-long, scheduler, configurator; переменные GUNICORN_*, PROXY_READ_TIMEOUT, CLIENT_MAX_BODY_SIZE; ERPNEXT_VERSION в шаблоне. https://github.com/frappe/frappe_docker/blob/main/compose.yaml
- frappe_docker: оверрайды MariaDB, Redis, https, noproxy — Проверено 01.10.2026: db с healthcheck и томом, redis-cache и redis-queue, Traefik с ACME и переменными LETSENCRYPT_EMAIL и SITES_RULE. https://github.com/frappe/frappe_docker/tree/main/overrides
- frappe_docker: сборка образа со своими приложениями — Проверено 01.10.2026: apps.json как секрет BuildKit, Docker Engine 23+, CUSTOM_IMAGE, CUSTOM_TAG, PULL_POLICY. https://github.com/frappe/frappe_docker/blob/main/docs/02-setup/02-build-setup.md
- frappe_docker: запуск и создание сайта — Проверено 01.10.2026: команды up -d, bench new-site, install-app, параметр --mariadb-user-host-login-scope. https://github.com/frappe/frappe_docker/blob/main/docs/02-setup/03-start-setup.md
- frappe_docker: стратегия резервного копирования — Проверено 01.10.2026: bench --site all backup --with-files по расписанию, пример restic. https://github.com/frappe/frappe_docker/blob/main/docs/03-production/02-backup-strategy.md
