|
|
||
|---|---|---|
| frappe_docker@6e78467603 | ||
| .gitignore | ||
| .gitmodules | ||
| .woodpecker.yml | ||
| apps.json | ||
| compose.site-creator.yaml | ||
| compose.traefik.yaml | ||
| Makefile | ||
| README.md | ||
ERPNext with Custom Apps (frappe_docker)
This guide shows how to build a custom ERPNext image from apps.json in the project root
and then start the stack using the official frappe_docker/compose.yaml — no push to a registry.
The .env file is placed in the project root and is used by both the build commands and Compose.
Project layout
.
├── .env # Configuration (image/tag, pull policy, build args)
├── apps.json # Your app list (ERPNext, Payments, custom repos) — in project root
├── frappe_docker/ # Cloned frappe_docker repo
│ ├── compose.yaml # Official compose by frappe_docker
│ └── images/
│ ├── custom/Containerfile
│ └── layered/Containerfile
└── README.md
1) Configure .env (in project root)
Create a .env in the project root (./.env). Example:
# ---- Image & Tag (local, no push) ----
CUSTOM_IMAGE=codeyard.3dt.digital/3dt/frappe
CUSTOM_TAG=local-1.0.0
# Compose: prevent pulls when the image exists locally
PULL_POLICY=never
# Default ERPNext version (only used as fallback in compose.yaml)
ERPNEXT_VERSION=version-15
# Optional build args
FRAPPE_PATH=https://github.com/frappe/frappe
FRAPPE_BRANCH=version-15
PYTHON_VERSION=3.11.9
NODE_VERSION=20.19.2
IMPORTANT: Docker image names must not contain
@. Usecodeyard.3dt.digital/3dt/frappeinstead ofcodeyard.3dt.digital/@3dt/frappe.
2) Create apps.json (in project root)
Create ./apps.json like this:
[
{
"url": "https://github.com/frappe/erpnext",
"branch": "version-15"
},
{
"url": "https://github.com/frappe/payments",
"branch": "version-15"
},
{
"url": "https://<PAT>@git.example.com/project/repository.git",
"branch": "main"
}
]
- For private repositories use a PAT inside the
url(e.g.https://<PAT>@...). - Validate the JSON:
jq empty apps.json
3) Optional: Base64 round-trip check
You do not need to export any variable. The build targets base64‑encode apps.json inline.
If you want a quick integrity check:
make encode # validates and writes apps-test-output.json (round-trip)
4) Build the image (from project root)
You have two build options:
A) Custom build (flexible, configurable Python/Node versions)
make build-custom
This runs:
docker build \
--build-arg FRAPPE_PATH="${FRAPPE_PATH}" \
--build-arg FRAPPE_BRANCH="${FRAPPE_BRANCH}" \
--build-arg PYTHON_VERSION="${PYTHON_VERSION}" \
--build-arg NODE_VERSION="${NODE_VERSION}" \
--build-arg APPS_JSON_BASE64="${APPS_JSON_BASE64}" \
--tag "${CUSTOM_IMAGE}:${CUSTOM_TAG}" \
--file frappe_docker/images/custom/Containerfile \
frappe_docker
B) Layered build (faster, uses prebuilt base layers)
make build-layered
This runs:
docker build \
--build-arg FRAPPE_PATH="${FRAPPE_PATH}" \
--build-arg FRAPPE_BRANCH="${FRAPPE_BRANCH}" \
--build-arg APPS_JSON_BASE64="${APPS_JSON_BASE64}" \
--tag "${CUSTOM_IMAGE}:${CUSTOM_TAG}" \
--file frappe_docker/images/layered/Containerfile \
frappe_docker
Result: A local image
CUSTOM_IMAGE:CUSTOM_TAG(no registry involved).
5) Start the stack (no push)
From the project root:
make up
# or
docker compose -f frappe_docker/compose.yaml up -d
- The compose file uses your
.env(CUSTOM_IMAGE,CUSTOM_TAG,PULL_POLICY). - With
PULL_POLICY=never, Compose does not pull from a registry if the image exists locally.
Open ERPNext at: http://localhost:8080 (depending on your chosen overrides).
6) Useful commands
make logs # follow logs
make down # stop and remove containers
make images # list the built image(s)
make config # print the resolved compose config
Troubleshooting
-
Invalid image reference: remove
@fromCUSTOM_IMAGE(use slashes/). -
Compose tries to pull the image: ensure
.envis in the project root and containsPULL_POLICY=never. Also confirm that the built image exists locally:docker images | grep $(basename "${CUSTOM_IMAGE}") | grep "${CUSTOM_TAG}" -
apps.jsonerrors: runjq empty apps.jsonto validate, and re-runmake encodeto refreshAPPS_JSON_BASE64. -
Switching tags for local experiments:
CUSTOM_TAG=feature-x make build-custom make up
Makefile shortcuts
This repo ships with a Makefile containing the targets used above. See make help
for a quick summary.
From-scratch run (DB, Redis, Traefik labels, Site creation)
The steps below get you from zero to a running site using your custom image and the official frappe_docker compose. No files are added to the frappe_docker submodule.
- Prepare
.env(root)
Add these keys in addition to your existing ones:
# Site
SITE_NAME=erp.corp.3dt.digital
ADMIN_PASSWORD=change-me
DB_PASSWORD=change-me
# Traefik (labels only; Traefik runs elsewhere)
DOMAIN=erp.corp.3dt.digital
TRAEFIK_CERTRESOLVER=letsencrypt
TRAEFIK_ENTRYPOINT_WEB=web
TRAEFIK_ENTRYPOINT_WEBSECURE=websecure
# Optional: external DB/Redis instead of overrides
# DB_HOST=my-postgres
# DB_PORT=5432
# REDIS_CACHE=my-redis:6379
# REDIS_QUEUE=my-redis:6379
- Define apps in
apps.json(root)
List all apps you want baked into the image. Example is in section 2 above.
- Build the image
make build-custom
- Ensure Traefik network exists (if you use
compose.traefik.yaml)
Your Traefik runs separately but must share the external Docker network used by the frontend service labels. Create it on the host if needed:
docker network create dokploy-network || true
- Start services incl. MariaDB, Redis, and Traefik labels
make up-full
This composes:
frappe_docker/compose.yaml(core services)frappe_docker/overrides/compose.mariadb.yaml(MariaDB)frappe_docker/overrides/compose.redis.yaml(Redis)compose.traefik.yaml(attachfrontendto your external Traefik via labels/network)
- Create the site (one-time)
Use the one-shot site creator. It reads the app list from sites/apps.txt (generated by the configurator) and installs all apps whose code is already inside your custom image.
make site
What it does (MariaDB):
- Waits for DB, sets MariaDB connection in bench config (db_type=db_host=db_port)
- Creates site:
bench new-site --mariadb-user-host-login-scope=% --db-root-password ${DB_PASSWORD} --admin-password ${ADMIN_PASSWORD} ${SITE_NAME} - Installs all apps found in
sites/apps.txt(skipsfrappe) - Sets the site as default
- Verify
make logs
Open your domain via Traefik (e.g. https://erp.corp.3dt.digital).
Troubleshooting tips:
- If the site was not created, re-run
make siteand inspect logs for DB connectivity - If assets look broken, run:
docker compose -f frappe_docker/compose.yaml exec backend bench build - If you use external DB/Redis, set
DB_HOST/DB_PORT/REDIS_CACHE/REDIS_QUEUEin.envand usemake up-traefik(skip Postgres/Redis overrides)
Notes:
- This flow uses MariaDB (recommended for ERPNext). If you must use Postgres, swap to
overrides/compose.postgres.yamland use the previous site-creator variant. - This flow does not modify the
frappe_dockersubmodule; the additional files live at the project root (e.g.compose.traefik.yaml,compose.site-creator.yaml).