mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-17 13:55:08 +00:00
Compare commits
82 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
825536a998 | ||
|
|
91fc59a134 | ||
|
|
f5eae9dffc | ||
|
|
7ef1d3e664 | ||
|
|
55cbf8e31f | ||
|
|
a1d4499fae | ||
|
|
1e3d40fa65 | ||
|
|
f60da9b964 | ||
|
|
25477c9e08 | ||
|
|
b7a0badaf0 | ||
|
|
3fccc2f9e7 | ||
|
|
6fccccf6d1 | ||
|
|
6526ab8cd4 | ||
|
|
c7da80ea3f | ||
|
|
4e5a578801 | ||
|
|
6695bb7b03 | ||
|
|
8c47ee9eb5 | ||
|
|
6377a34c61 | ||
|
|
e64251a86a | ||
|
|
cb0eda5214 | ||
|
|
0cb8df1631 | ||
|
|
930d44603a | ||
|
|
08d765c413 | ||
|
|
c710eef89e | ||
|
|
33f24b2645 | ||
|
|
640b761a3d | ||
|
|
73b029945b | ||
|
|
38ca8d2316 | ||
|
|
48764b21c1 | ||
|
|
19259e9d02 | ||
|
|
6e1117bbbc | ||
|
|
2c44349a0f | ||
|
|
5097115d08 | ||
|
|
cfd280eff3 | ||
|
|
aafc25bc76 | ||
|
|
e31bcceac1 | ||
|
|
eeb487e5e6 | ||
|
|
cec5b93546 | ||
|
|
d07d805436 | ||
|
|
5abd3c0f95 | ||
|
|
004b27a5a7 | ||
|
|
37e91a2db2 | ||
|
|
c363f459a4 | ||
|
|
09fcd3e83b | ||
|
|
8f4130b5d3 | ||
|
|
93ade44c6b | ||
|
|
f2d96ab8eb | ||
|
|
c7ac6b7666 | ||
|
|
0a04e5ecd2 | ||
|
|
c302af9dd5 | ||
|
|
d24093469d | ||
|
|
2af7b06f8d | ||
|
|
5d9f2e41a0 | ||
|
|
373e6c1e20 | ||
|
|
edfd8f0755 | ||
|
|
d8393e0402 | ||
|
|
9432daaaaf | ||
|
|
092a3769b1 | ||
|
|
ae221ebf7a | ||
|
|
815946194c | ||
|
|
5cdd428a66 | ||
|
|
64e6536592 | ||
|
|
c48aa7f39b | ||
|
|
12e6e821bc | ||
|
|
473f08a7f9 | ||
|
|
db21f966ef | ||
|
|
0b835b0819 | ||
|
|
8428dfe9ba | ||
|
|
a260d9a431 | ||
|
|
84e0608209 | ||
|
|
007ae42d2f | ||
|
|
4b8d6a94cd | ||
|
|
71399ec0f3 | ||
|
|
c7a437ad63 | ||
|
|
d2308438d0 | ||
|
|
50e0ad5d3f | ||
|
|
6633e61bfb | ||
|
|
f8cfe4cb82 | ||
|
|
a41764b9cc | ||
|
|
3b3873cad5 | ||
|
|
0d11308944 | ||
|
|
a0bef9c2db |
30 changed files with 754 additions and 124 deletions
4
.github/workflows/app-build-image.yml
vendored
4
.github/workflows/app-build-image.yml
vendored
|
|
@ -130,7 +130,7 @@ jobs:
|
||||||
PY
|
PY
|
||||||
|
|
||||||
- name: Build smoke-test image
|
- name: Build smoke-test image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: ${{ env.BUILDER_DIR }}
|
context: ${{ env.BUILDER_DIR }}
|
||||||
file: ${{ env.BUILDER_DIR }}/images/layered/Containerfile
|
file: ${{ env.BUILDER_DIR }}/images/layered/Containerfile
|
||||||
|
|
@ -172,7 +172,7 @@ jobs:
|
||||||
|
|
||||||
- name: Push multi-arch image
|
- name: Push multi-arch image
|
||||||
if: ${{ inputs.push }}
|
if: ${{ inputs.push }}
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: ${{ env.BUILDER_DIR }}
|
context: ${{ env.BUILDER_DIR }}
|
||||||
file: ${{ env.BUILDER_DIR }}/images/layered/Containerfile
|
file: ${{ env.BUILDER_DIR }}/images/layered/Containerfile
|
||||||
|
|
|
||||||
2
.github/workflows/build_stable.yml
vendored
2
.github/workflows/build_stable.yml
vendored
|
|
@ -7,6 +7,6 @@ jobs:
|
||||||
delegate:
|
delegate:
|
||||||
uses: ./.github/workflows/core-build-stable.yml
|
uses: ./.github/workflows/core-build-stable.yml
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
|
||||||
4
.github/workflows/core-build-bench.yml
vendored
4
.github/workflows/core-build-bench.yml
vendored
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
run: echo "LATEST_BENCH_RELEASE=$(curl -s 'https://api.github.com/repos/frappe/bench/releases/latest' | jq -r '.tag_name')" >> "$GITHUB_ENV"
|
run: echo "LATEST_BENCH_RELEASE=$(curl -s 'https://api.github.com/repos/frappe/bench/releases/latest' | jq -r '.tag_name')" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Build and test
|
- name: Build and test
|
||||||
uses: docker/bake-action@v7.1.0
|
uses: docker/bake-action@v7.2.0
|
||||||
with:
|
with:
|
||||||
source: .
|
source: .
|
||||||
targets: bench-test
|
targets: bench-test
|
||||||
|
|
@ -52,7 +52,7 @@ jobs:
|
||||||
|
|
||||||
- name: Push
|
- name: Push
|
||||||
if: ${{ github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' }}
|
if: ${{ github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' }}
|
||||||
uses: docker/bake-action@v7.1.0
|
uses: docker/bake-action@v7.2.0
|
||||||
with:
|
with:
|
||||||
targets: bench
|
targets: bench
|
||||||
push: true
|
push: true
|
||||||
|
|
|
||||||
2
.github/workflows/core-build-develop.yml
vendored
2
.github/workflows/core-build-develop.yml
vendored
|
|
@ -5,6 +5,8 @@ permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
|
||||||
4
.github/workflows/core-build-stable.yml
vendored
4
.github/workflows/core-build-stable.yml
vendored
|
|
@ -5,6 +5,8 @@ permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
@ -87,6 +89,8 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' }}
|
if: ${{ github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' }}
|
||||||
needs: v16_publish
|
needs: v16_publish
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
|
||||||
2
.github/workflows/core-build-test-images.yml
vendored
2
.github/workflows/core-build-test-images.yml
vendored
|
|
@ -87,7 +87,7 @@ jobs:
|
||||||
echo "NODE_VERSION=${{ inputs.node_version }}" >> "$GITHUB_ENV"
|
echo "NODE_VERSION=${{ inputs.node_version }}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: docker/bake-action@v7.1.0
|
uses: docker/bake-action@v7.2.0
|
||||||
with:
|
with:
|
||||||
source: .
|
source: .
|
||||||
push: true
|
push: true
|
||||||
|
|
|
||||||
4
.github/workflows/core-publish-images.yml
vendored
4
.github/workflows/core-publish-images.yml
vendored
|
|
@ -70,7 +70,7 @@ jobs:
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Push Docker Hub images
|
- name: Push Docker Hub images
|
||||||
uses: docker/bake-action@v7.1.0
|
uses: docker/bake-action@v7.2.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
set: "*.platform=linux/amd64,linux/arm64"
|
set: "*.platform=linux/amd64,linux/arm64"
|
||||||
|
|
@ -83,7 +83,7 @@ jobs:
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Push GHCR base images
|
- name: Push GHCR base images
|
||||||
uses: docker/bake-action@v7.1.0
|
uses: docker/bake-action@v7.2.0
|
||||||
with:
|
with:
|
||||||
targets: base-images
|
targets: base-images
|
||||||
push: true
|
push: true
|
||||||
|
|
|
||||||
1
.github/workflows/stale.yml
vendored
1
.github/workflows/stale.yml
vendored
|
|
@ -16,3 +16,4 @@ jobs:
|
||||||
stale-pr-message: This PR has been automatically marked as stale. You have a week to explain why you believe this is an error.
|
stale-pr-message: This PR has been automatically marked as stale. You have a week to explain why you believe this is an error.
|
||||||
stale-issue-label: no-issue-activity
|
stale-issue-label: no-issue-activity
|
||||||
stale-pr-label: no-pr-activity
|
stale-pr-label: no-pr-activity
|
||||||
|
exempt-issue-labels: keep-open
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@ services:
|
||||||
backend:
|
backend:
|
||||||
<<: *backend_defaults
|
<<: *backend_defaults
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
|
environment:
|
||||||
|
GUNICORN_THREADS: ${GUNICORN_THREADS:-4}
|
||||||
|
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-2}
|
||||||
|
GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT:-120}
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
<<: *customizable_image
|
<<: *customizable_image
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@
|
||||||
"grapecity.gc-excelviewer",
|
"grapecity.gc-excelviewer",
|
||||||
"mtxr.sqltools",
|
"mtxr.sqltools",
|
||||||
"mtxr.sqltools-driver-mysql",
|
"mtxr.sqltools-driver-mysql",
|
||||||
"visualstudioexptteam.vscodeintellicode"
|
"vue.volar",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"charliermarsh.ruff"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"terminal.integrated.profiles.linux": {
|
"terminal.integrated.profiles.linux": {
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,11 @@ This allows you to:
|
||||||
|
|
||||||
Installing apps into a running container is **not supported**.
|
Installing apps into a running container is **not supported**.
|
||||||
|
|
||||||
`bench get-app` is an examples of an common but unsupported action.
|
`bench get-app` and `bench build` are examples of an common but unsupported actions.
|
||||||
|
|
||||||
### Why?
|
### Why?
|
||||||
|
|
||||||
- Apps are part of the **Docker image**
|
- Apps and assets are part of the **Docker image**
|
||||||
- Runtime changes are lost on container recreation
|
- Runtime changes are lost on container recreation
|
||||||
- This ensures reproducibility and stability
|
- This ensures reproducibility and stability
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ here is the example pwd.yml file:
|
||||||
```yml
|
```yml
|
||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
@ -39,8 +39,8 @@ services:
|
||||||
- logs:/home/frappe/frappe-bench/logs
|
- logs:/home/frappe/frappe-bench/logs
|
||||||
|
|
||||||
configurator:
|
configurator:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: none
|
condition: none
|
||||||
|
|
@ -68,8 +68,8 @@ services:
|
||||||
- logs:/home/frappe/frappe-bench/logs
|
- logs:/home/frappe/frappe-bench/logs
|
||||||
|
|
||||||
create-site:
|
create-site:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: none
|
condition: none
|
||||||
|
|
@ -101,7 +101,7 @@ services:
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: mariadb:11.8
|
image: mariadb:11.8
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: mysqladmin ping -h localhost --password=admin
|
test: mysqladmin ping -h localhost --password=admin
|
||||||
interval: 1s
|
interval: 1s
|
||||||
|
|
@ -119,8 +119,8 @@ services:
|
||||||
- db-data:/var/lib/mysql
|
- db-data:/var/lib/mysql
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
depends_on:
|
depends_on:
|
||||||
- websocket
|
- websocket
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -144,8 +144,8 @@ services:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
|
|
||||||
queue-long:
|
queue-long:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
@ -159,8 +159,8 @@ services:
|
||||||
- logs:/home/frappe/frappe-bench/logs
|
- logs:/home/frappe/frappe-bench/logs
|
||||||
|
|
||||||
queue-short:
|
queue-short:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
@ -175,7 +175,7 @@ services:
|
||||||
|
|
||||||
redis-queue:
|
redis-queue:
|
||||||
image: redis:6.2-alpine
|
image: redis:6.2-alpine
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
@ -184,14 +184,14 @@ services:
|
||||||
|
|
||||||
redis-cache:
|
redis-cache:
|
||||||
image: redis:6.2-alpine
|
image: redis:6.2-alpine
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
@ -203,8 +203,8 @@ services:
|
||||||
- logs:/home/frappe/frappe-bench/logs
|
- logs:/home/frappe/frappe-bench/logs
|
||||||
|
|
||||||
websocket:
|
websocket:
|
||||||
image: frappe/erpnext:v15
|
image: frappe/erpnext:v16.19.1
|
||||||
platform: linux/amd64
|
platform: linux/arm64
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ This guide walks you through building Frappe images from the repository resource
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
|
|
||||||
- git
|
- git
|
||||||
- docker (Engine **v23.0+**) or podman
|
- docker (Engine **v23.0+** with buildx) or podman
|
||||||
- docker compose v2 or podman compose
|
- docker compose v2 or podman compose
|
||||||
|
|
||||||
> Install containerization software according to the official maintainer documentation. Avoid package managers when not recommended, as they frequently cause compatibility issues.
|
> Install containerization software according to the official maintainer documentation. Avoid package managers when not recommended, as they frequently cause compatibility issues.
|
||||||
|
|
@ -23,7 +23,7 @@ cd frappe_docker
|
||||||
|
|
||||||
# Define custom apps
|
# Define custom apps
|
||||||
|
|
||||||
If you dont want to install specific apps to the image skip this section.
|
If you don't want to include custom apps in the image, skip this section.
|
||||||
|
|
||||||
To include custom apps in your image, create an `apps.json` file in the repository root:
|
To include custom apps in your image, create an `apps.json` file in the repository root:
|
||||||
|
|
||||||
|
|
@ -31,11 +31,11 @@ To include custom apps in your image, create an `apps.json` file in the reposito
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"url": "https://github.com/frappe/erpnext",
|
"url": "https://github.com/frappe/erpnext",
|
||||||
"branch": "version-15"
|
"branch": "version-16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://github.com/frappe/hrms",
|
"url": "https://github.com/frappe/hrms",
|
||||||
"branch": "version-15"
|
"branch": "version-16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://github.com/frappe/helpdesk",
|
"url": "https://github.com/frappe/helpdesk",
|
||||||
|
|
@ -44,7 +44,9 @@ To include custom apps in your image, create an `apps.json` file in the reposito
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
# Build the image
|
# Build custom images
|
||||||
|
|
||||||
|
## Manually
|
||||||
|
|
||||||
Choose the appropriate build command based on your container runtime and desired image type. This example builds the `layered` image with the custom `apps.json` you created.
|
Choose the appropriate build command based on your container runtime and desired image type. This example builds the `layered` image with the custom `apps.json` you created.
|
||||||
|
|
||||||
|
|
@ -54,10 +56,11 @@ Choose the appropriate build command based on your container runtime and desired
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build \
|
docker build \
|
||||||
|
--no-cache \
|
||||||
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
||||||
--build-arg=FRAPPE_BRANCH=version-15 \
|
--build-arg=FRAPPE_BRANCH=version-16 \
|
||||||
--secret=id=apps_json,src=apps.json \
|
--secret=id=apps_json,src=apps.json \
|
||||||
--tag=custom:15 \
|
--tag=custom:16 \
|
||||||
--file=images/layered/Containerfile .
|
--file=images/layered/Containerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -65,31 +68,42 @@ docker build \
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
podman build \
|
podman build \
|
||||||
|
--no-cache \
|
||||||
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
||||||
--build-arg=FRAPPE_BRANCH=version-15 \
|
--build-arg=FRAPPE_BRANCH=version-16 \
|
||||||
--secret=id=apps_json,src=apps.json \
|
--secret=id=apps_json,src=apps.json \
|
||||||
--tag=custom:15 \
|
--tag=custom:16 \
|
||||||
--file=images/layered/Containerfile .
|
--file=images/layered/Containerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build args
|
## Automated
|
||||||
|
|
||||||
| Arg | Purpose |
|
This repository is fully suited for automated builds, i.e. using CI/CD pipelines.
|
||||||
| -------------------- | ----------------------------------------------------------------------------------------------- |
|
|
||||||
| **Frappe Framework** | |
|
|
||||||
| FRAPPE_PATH | Repository URL for Frappe framework source code. Defaults to <https://github.com/frappe/frappe> |
|
|
||||||
| FRAPPE_BRANCH | Branch to use for Frappe framework. Defaults to version-15 |
|
|
||||||
| **Custom Apps** | |
|
|
||||||
| (secret) apps_json | Passed via `--secret=id=apps_json,src=apps.json`. Never use `--build-arg` for this file. |
|
|
||||||
| **Dependencies** | |
|
|
||||||
| PYTHON_VERSION | Python version for the base image |
|
|
||||||
| NODE_VERSION | Node.js version |
|
|
||||||
| WKHTMLTOPDF_VERSION | wkhtmltopdf version |
|
|
||||||
| **bench only** | |
|
|
||||||
| DEBIAN_BASE | Debian base version for the bench image, defaults to `bookworm` |
|
|
||||||
| WKHTMLTOPDF_DISTRO | use the specified distro for debian package. Default is `bookworm` |
|
|
||||||
|
|
||||||
# env file
|
See [Automated Builds and Deployment](../03-production/06-automated-builds-and-deployment.md) for more information.
|
||||||
|
|
||||||
|
## Build args, secrets and flags
|
||||||
|
|
||||||
|
| Variable | Purpose |
|
||||||
|
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| **Frappe Framework** | |
|
||||||
|
| FRAPPE_PATH | Repository URL for Frappe framework source code. Defaults to <https://github.com/frappe/frappe> |
|
||||||
|
| FRAPPE_BRANCH | Branch to use for Frappe framework. Defaults to version-16 |
|
||||||
|
| **Custom Apps** | |
|
||||||
|
| CACHE_BUST | Can be used to invalidate the cached layer. See [Build Cache](../03-production/06-automated-builds-and-deployment.md#build-cache) |
|
||||||
|
| (secret) apps_json | Passed via `--secret=id=apps_json,src=apps.json`. Never use `--build-arg` for this file. |
|
||||||
|
| **Dependencies** | |
|
||||||
|
| PYTHON_VERSION | Python version for the base image |
|
||||||
|
| NODE_VERSION | Node.js version |
|
||||||
|
| WKHTMLTOPDF_VERSION | wkhtmltopdf version |
|
||||||
|
| INSTALL_CHROMIUM | Configure chromium installation, defaults to `true` - needed for Frappe Workbench version >15 |
|
||||||
|
| **bench only** | |
|
||||||
|
| DEBIAN_BASE | Debian base version for the bench image, defaults to `bookworm` |
|
||||||
|
| WKHTMLTOPDF_DISTRO | use the specified distro for debian package. Default is `bookworm` |
|
||||||
|
|
||||||
|
# Deploy the stack
|
||||||
|
|
||||||
|
## env file
|
||||||
|
|
||||||
The compose file requires several environment variables. You can either export them on your system or create a `.env` file.
|
The compose file requires several environment variables. You can either export them on your system or create a `.env` file.
|
||||||
|
|
||||||
|
|
@ -103,7 +117,7 @@ For this setup, make sure **at least** the following values are added to `custom
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
CUSTOM_IMAGE=custom
|
CUSTOM_IMAGE=custom
|
||||||
CUSTOM_TAG=15
|
CUSTOM_TAG=16
|
||||||
PULL_POLICY=missing
|
PULL_POLICY=missing
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -113,7 +127,7 @@ PULL_POLICY=missing
|
||||||
**⚠️ This is not meant to be a complete `.env` configuration guide. These are only the minimal additions required for this example.
|
**⚠️ This is not meant to be a complete `.env` configuration guide. These are only the minimal additions required for this example.
|
||||||
Please have a look at [env-variables.md](04-env-variables.md) for a full description of all available variables and adjust them according to your needs.**
|
Please have a look at [env-variables.md](04-env-variables.md) for a full description of all available variables and adjust them according to your needs.**
|
||||||
|
|
||||||
# Creating the final compose file
|
## Creating the final compose file
|
||||||
|
|
||||||
Combine the base compose file with appropriate overrides for your use case. This example adds MariaDB, Redis, and exposes ports on `:8080`:
|
Combine the base compose file with appropriate overrides for your use case. This example adds MariaDB, Redis, and exposes ports on `:8080`:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,16 @@ If your site is named `example.com` and you access it via that domain, no need t
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Backend (Gunicorn) Configuration
|
||||||
|
|
||||||
|
| Variable | Purpose | Default | When to Set / Allowed Values |
|
||||||
|
| :----------------- | :------------------------------------------------------------- | :------ | :------------------------------------------------------------------------------- |
|
||||||
|
| `GUNICORN_WORKERS` | Number of worker processes handling web requests | `2` | Scale up for multi-core CPUs. Formula: `(2 x Cores) + 1` |
|
||||||
|
| `GUNICORN_THREADS` | Number of concurrent threads per worker process | `4` | Increase to handle more simultaneous I/O-bound requests without high memory cost |
|
||||||
|
| `GUNICORN_TIMEOUT` | Max time a worker can spend on a single request before restart | `120` | Increase if long-running reports or data imports time out |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Frontend Nginx Configuration (inside the frontend container)
|
## Frontend Nginx Configuration (inside the frontend container)
|
||||||
|
|
||||||
| Variable | Purpose | Default | Allowed Values |
|
| Variable | Purpose | Default | Allowed Values |
|
||||||
|
|
@ -140,3 +150,11 @@ Use these variables when running behind a reverse proxy or load balancer:
|
||||||
| `UPSTREAM_REAL_IP_ADDRESS` | Trusted upstream IP address for real IP detection | `127.0.0.1` |
|
| `UPSTREAM_REAL_IP_ADDRESS` | Trusted upstream IP address for real IP detection | `127.0.0.1` |
|
||||||
| `UPSTREAM_REAL_IP_HEADER` | Request header containing client IP | `X-Forwarded-For` |
|
| `UPSTREAM_REAL_IP_HEADER` | Request header containing client IP | `X-Forwarded-For` |
|
||||||
| `UPSTREAM_REAL_IP_RECURSIVE` | Enable recursive IP search | `off` |
|
| `UPSTREAM_REAL_IP_RECURSIVE` | Enable recursive IP search | `off` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Service
|
||||||
|
|
||||||
|
| Variable | Purpose | Default | Allowed Values |
|
||||||
|
| --------------- | ------------------------------- | -------------------------- | ---------------- |
|
||||||
|
| `MIGRATE_SITES` | Switch auto migration on or off | `true` - auto migration on | `true` , `false` |
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ docker compose -f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/co
|
||||||
| compose.nginxproxy.yaml | Uses nginx-proxy as HTTP reverse proxy on port `:80` | Set `NGINX_PROXY_HOSTS`. Use with `compose.nginxproxy-ssl.yaml` for HTTPS. You can change the published port by setting `HTTP_PUBLISH_PORT` |
|
| compose.nginxproxy.yaml | Uses nginx-proxy as HTTP reverse proxy on port `:80` | Set `NGINX_PROXY_HOSTS`. Use with `compose.nginxproxy-ssl.yaml` for HTTPS. You can change the published port by setting `HTTP_PUBLISH_PORT` |
|
||||||
| compose.nginxproxy-ssl.yaml | Adds acme-companion for HTTPS on port `:443` with automatic certificates | Requires `compose.nginxproxy.yaml`. Set `NGINX_PROXY_HOSTS` and `LETSENCRYPT_EMAIL`. `HTTP_PUBLISH_PORT` and `HTTPS_PUBLISH_PORT` can be set. |
|
| compose.nginxproxy-ssl.yaml | Adds acme-companion for HTTPS on port `:443` with automatic certificates | Requires `compose.nginxproxy.yaml`. Set `NGINX_PROXY_HOSTS` and `LETSENCRYPT_EMAIL`. `HTTP_PUBLISH_PORT` and `HTTPS_PUBLISH_PORT` can be set. |
|
||||||
| **Redis** | | |
|
| **Redis** | | |
|
||||||
| compose.redis.yaml | Adds Redis service for caching and background job queuing |
|
| compose.redis.yaml | Adds Redis service for caching and background job queuing | |
|
||||||
| **TBD** | **The following overrides are available but lack documentation. If you use them and understand their purpose, please consider contributing to this documentation.** |
|
| **Services** | | |
|
||||||
|
| compose.migrator.yaml | Runs a dedicated migration container performing `bench --site all migrate` on all sites at every start | Control migration intent with `MIGRATE_SITES` - defaults to true |
|
||||||
|
| **TBD** | **The following overrides are available but lack documentation. If you use them and understand their purpose, please consider contributing to this documentation.** | |
|
||||||
| compose.backup-cron.yaml | | |
|
| compose.backup-cron.yaml | | |
|
||||||
| compose.custom-domain-ssl.yaml | | |
|
| compose.custom-domain-ssl.yaml | | |
|
||||||
| compose.custom-domain.yaml | | |
|
| compose.custom-domain.yaml | | |
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ docker compose --project-name erpnext exec backend \
|
||||||
|
|
||||||
# crm.your-domain.com
|
# crm.your-domain.com
|
||||||
docker compose --project-name erpnext exec backend \
|
docker compose --project-name erpnext exec backend \
|
||||||
bench new-site --mariadb-user-host-login-scope=% --db-root-password changeit --install-app erpnext --admin-password changeit crm.your-domain.com
|
bench new-site --mariadb-user-host-login-scope=% --db-root-password changeit --install-app crm --admin-password changeit crm.your-domain.com
|
||||||
```
|
```
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
|
||||||
147
docs/03-production/06-automated-builds-and-deployment.md
Normal file
147
docs/03-production/06-automated-builds-and-deployment.md
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
---
|
||||||
|
title: Automated Builds and Deployment
|
||||||
|
---
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
This is a brief guide to automated builds and deployment for custom Frappe images.
|
||||||
|
Depending on your specific setup, environment and security rules, the information below may need to be adapted to your needs.
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
|
||||||
|
## Knowledge
|
||||||
|
|
||||||
|
Basic knowledge of Docker and build pipelines is expected.
|
||||||
|
|
||||||
|
Please refer to the Setup chapter first, especially [Build Setup](../02-setup/02-build-setup.md), for basic understanding.
|
||||||
|
|
||||||
|
## Additional Files
|
||||||
|
|
||||||
|
### Apps
|
||||||
|
|
||||||
|
At build time an `apps.json` file can be provided. This specifies additional Frappe framework compatible apps to include in custom images.
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
A workflow file for your CI platform and environment is required.
|
||||||
|
|
||||||
|
## Build Cache
|
||||||
|
|
||||||
|
Unlike manual builds, automated build commands should generally not use `--no-cache`.
|
||||||
|
|
||||||
|
Reusing cached layers can greatly reduce build times, disk usage, and bandwidth usage when pushing to image registries.
|
||||||
|
|
||||||
|
Instead, `CACHE_BUST` can be used to control cache invalidation of the Frappe layer when rebuilding is desired.
|
||||||
|
|
||||||
|
This is especially relevant because `apps.json` is provided as a secret. Secret contents are not part of Docker layer cache keys and therefore cannot trigger cache invalidation automatically.
|
||||||
|
|
||||||
|
As a result, Docker may reuse an older cached layer even when the custom app definition has changed.
|
||||||
|
|
||||||
|
Exception: Newer releases of the Frappe framework may still trigger rebuilding the layer.
|
||||||
|
|
||||||
|
### Possible techniques for cache invalidation using `CACHE_BUST`:
|
||||||
|
|
||||||
|
1. No override: normal Docker layer caching is used - not recommended in this use case
|
||||||
|
2. Timestamp: force a rebuild on every pipeline run - since the value will change every run
|
||||||
|
3. Pipeline run ID: rebuild once per CI run
|
||||||
|
4. Commit SHA: rebuild once per commit
|
||||||
|
5. apps.json hash: rebuild only when the custom app definition changes - additional requirements, see below example
|
||||||
|
|
||||||
|
### Examples:
|
||||||
|
|
||||||
|
#### 1. No override - not recommended
|
||||||
|
|
||||||
|
This will reuse a previously build layer and won't check for app updates except Frappe framework
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
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 .
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Timestamp
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
||||||
|
--build-arg=FRAPPE_BRANCH=version-16 \
|
||||||
|
--build-arg=CACHE_BUST="$(date +%s)" \
|
||||||
|
--secret=id=apps_json,src=apps.json \
|
||||||
|
--tag=custom:16 \
|
||||||
|
--file=images/layered/Containerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Pipeline run ID from GitHub
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
||||||
|
--build-arg=FRAPPE_BRANCH=version-16 \
|
||||||
|
--build-arg=CACHE_BUST="$GITHUB_RUN_ID" \
|
||||||
|
--secret=id=apps_json,src=apps.json \
|
||||||
|
--tag=custom:16 \
|
||||||
|
--file=images/layered/Containerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. Commit SHA from GitHub
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
||||||
|
--build-arg=FRAPPE_BRANCH=version-16 \
|
||||||
|
--build-arg=CACHE_BUST="$GITHUB_SHA" \
|
||||||
|
--secret=id=apps_json,src=apps.json \
|
||||||
|
--tag=custom:16 \
|
||||||
|
--file=images/layered/Containerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. apps.json hash
|
||||||
|
|
||||||
|
Note: When using branch references in `apps.json`, the hash only changes when the file content changes, not when an upstream app branch receives updates. This method works best when pinning specific commits or releases.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
|
||||||
|
--build-arg=FRAPPE_BRANCH=version-16 \
|
||||||
|
--build-arg=CACHE_BUST="$(sha256sum apps.json | awk '{print $1}')" \
|
||||||
|
--secret=id=apps_json,src=apps.json \
|
||||||
|
--tag=custom:16 \
|
||||||
|
--file=images/layered/Containerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automated deployment
|
||||||
|
|
||||||
|
### Automate site migration
|
||||||
|
|
||||||
|
After updating a custom image or deploying new app versions, a database migration
|
||||||
|
must be executed using `bench migrate`.
|
||||||
|
|
||||||
|
Without running migrations, the site may become inconsistent or fail to start properly.
|
||||||
|
|
||||||
|
For automated deployments, this step should not be performed manually.
|
||||||
|
|
||||||
|
Consider using the dedicated `migrator` service provided as a Compose override.
|
||||||
|
It ensures that migrations are executed automatically when the stack starts.
|
||||||
|
|
||||||
|
This approach is especially useful in CI/CD pipelines where no interactive access
|
||||||
|
to the backend container is available.
|
||||||
|
|
||||||
|
See [Compose override](../../overrides/compose.migrator.yaml)
|
||||||
254
docs/05-development/04-alternate-setup.md
Normal file
254
docs/05-development/04-alternate-setup.md
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
---
|
||||||
|
title: Docker Development Setup
|
||||||
|
---
|
||||||
|
|
||||||
|
# Docker Development Setup
|
||||||
|
|
||||||
|
A complete guide for setting up a Frappe development environment on x86 and ARM based computers running UNIX based OSes by running containers directly and working inside them via the terminal. No VS Code Dev Containers extension needed.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Devcontainers are the intended development setup for Frappe Framework but in case you don't want to use that method follow these instructions to use the CLI directly instead
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Docker Desktop** (Applicable only for MacOS) — [download here](https://www.docker.com/products/docker-desktop/)
|
||||||
|
- **Git**
|
||||||
|
- A terminal (iTerm2, or the built-in Terminal.app)
|
||||||
|
|
||||||
|
### Docker Desktop Resource Allocation (Critical)
|
||||||
|
|
||||||
|
1. Open Docker Desktop → **Settings** → **Resources**
|
||||||
|
2. **Memory**: at least **6 GB** (8 GB recommended)
|
||||||
|
3. **CPUs**: at least **4**
|
||||||
|
4. **Disk image size**: at least **60 GB**
|
||||||
|
5. Click **Apply & Restart**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1 — Set ARM64 as Default Platform (ONLY FOR ARM BASED SYSTEMS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DOCKER_DEFAULT_PLATFORM=linux/arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
Make it permanent:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo 'export DOCKER_DEFAULT_PLATFORM=linux/arm64' >> ~/.zshrc
|
||||||
|
source ~/.zshrc
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2 — Clone the Repo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/frappe/frappe_docker.git
|
||||||
|
cd frappe_docker
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3 — Set Up the Dev Container Config
|
||||||
|
|
||||||
|
The `devcontainer-example/` folder contains a ready-made `docker-compose.yml` for development. Copy it into place:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -R devcontainer-example .devcontainer
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives you `.devcontainer/docker-compose.yml` which defines all the services you need:
|
||||||
|
|
||||||
|
- `frappe` — the main development container (Debian, Python, Node, bench)
|
||||||
|
- `mariadb` — the database
|
||||||
|
- `redis-cache` — cache layer
|
||||||
|
- `redis-queue` — background job queue
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4 — Add ARM64 Platform to All Services
|
||||||
|
|
||||||
|
Open `.devcontainer/docker-compose.yml` in any editor and add `platform: linux/arm64` to every service block. It should look like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
frappe:
|
||||||
|
image: frappe/bench:latest
|
||||||
|
platform: linux/arm64
|
||||||
|
# ... rest of config
|
||||||
|
|
||||||
|
mariadb:
|
||||||
|
image: mariadb:10.8
|
||||||
|
platform: linux/arm64
|
||||||
|
# ...
|
||||||
|
|
||||||
|
redis-cache:
|
||||||
|
image: redis:6.2-alpine
|
||||||
|
platform: linux/arm64
|
||||||
|
# ...
|
||||||
|
|
||||||
|
redis-queue:
|
||||||
|
image: redis:6.2-alpine
|
||||||
|
platform: linux/arm64
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
> Without this, Docker may pull amd64 images and emulate them via Rosetta — things will work but be noticeably slower.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5 — Start the Containers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f .devcontainer/docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify everything is running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f .devcontainer/docker-compose.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see all services with status `Up`.
|
||||||
|
|
||||||
|
In case you get any errors along the lines of,
|
||||||
|
|
||||||
|
```log
|
||||||
|
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint devcontainer-frappe-1 (44b337b68d100e914fab0ce446ed08d791cc73aaffb05cf47c347c00ff88f567): Bind for 0.0.0.0:9001 failed: port is already allocated
|
||||||
|
```
|
||||||
|
|
||||||
|
- Check if the port is being used by another service with `lsof -i :PORT`
|
||||||
|
> Usually on MacOS ports 8000 and 9000 are usually reserved for system use
|
||||||
|
- Go to line 60 and 61 under the `frappe` service and change the ports
|
||||||
|
|
||||||
|
Eg:
|
||||||
|
|
||||||
|
```
|
||||||
|
ports:
|
||||||
|
- 8001-8005:8001-8005
|
||||||
|
- 9002-9005:9002-9005
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6 — Enter the Development Container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -e "TERM=xterm-256color" -w /workspace/development -it devcontainer-frappe-1 bash
|
||||||
|
```
|
||||||
|
|
||||||
|
> The container name is typically `devcontainer-frappe-1`. If it differs, check with `docker ps` and use the actual name shown.
|
||||||
|
|
||||||
|
You are now inside the container as the `frappe` user. All subsequent commands in this guide run **inside the container** unless noted otherwise.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7 — Initialize a Bench
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bench init --skip-redis-config-generation --frappe-branch version-16 frappe-bench
|
||||||
|
cd frappe-bench
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `version-16` for the latest stable release. Swap for `version-15` if needed.
|
||||||
|
|
||||||
|
This creates:
|
||||||
|
|
||||||
|
```
|
||||||
|
development/
|
||||||
|
└── frappe-bench/
|
||||||
|
├── apps/ ← All Frappe apps live here
|
||||||
|
├── sites/ ← Your sites (databases, uploaded files)
|
||||||
|
├── env/ ← Python virtualenv
|
||||||
|
├── logs/
|
||||||
|
└── Procfile
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 8 — Configure Service Hosts
|
||||||
|
|
||||||
|
Tell bench to use the containerised services (not localhost):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bench set-config -g db_host mariadb
|
||||||
|
bench set-config -g redis_cache redis://redis-cache:6379
|
||||||
|
bench set-config -g redis_queue redis://redis-queue:6379
|
||||||
|
bench set-config -g redis_socketio redis://redis-queue:6379
|
||||||
|
```
|
||||||
|
|
||||||
|
If any command fails, edit the file directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nano sites/common_site_config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Paste:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"db_host": "mariadb",
|
||||||
|
"redis_cache": "redis://redis-cache:6379",
|
||||||
|
"redis_queue": "redis://redis-queue:6379",
|
||||||
|
"redis_socketio": "redis://redis-queue:6379"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 9 — Fix the Procfile
|
||||||
|
|
||||||
|
Redis runs in separate containers, so remove it from Honcho's Procfile to avoid conflicts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo sed -i '/redis/d' ./Procfile
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 10 — Create a Site
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bench new-site \
|
||||||
|
--db-root-password 123 \
|
||||||
|
--admin-password admin \
|
||||||
|
--mariadb-user-host-login-scope=% \
|
||||||
|
development.localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
- MariaDB root password: `123` (set in the docker-compose defaults)
|
||||||
|
- Admin password: `admin` (change this to whatever you want)
|
||||||
|
- Site name **must end in `.localhost`**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 11 — Enable Developer Mode
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bench --site development.localhost set-config developer_mode 1
|
||||||
|
bench --site development.localhost clear-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 12 — Add development.localhost to /etc/hosts (on your Mac)
|
||||||
|
|
||||||
|
Run this **on your Mac** (not inside the container):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "127.0.0.1 development.localhost" | sudo tee -a /etc/hosts
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 13 — Start the Dev Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bench build # (optional)
|
||||||
|
bench start
|
||||||
|
```
|
||||||
|
|
||||||
|
Open your browser at **http://development.localhost:8000**
|
||||||
|
Login: `Administrator` / `admin`
|
||||||
62
docs/08-reference/07-how-assets-are-handled.md
Normal file
62
docs/08-reference/07-how-assets-are-handled.md
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
---
|
||||||
|
title: How Assets are handled
|
||||||
|
---
|
||||||
|
|
||||||
|
# Assets Reference
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
The `sites` directory contains both persistent data (site config, uploaded files, etc.) and build-time artifacts (`sites/assets`). Mounting the entire `sites` directory as a Docker volume causes assets to be persisted alongside config, which leads to:
|
||||||
|
|
||||||
|
- Stale assets surviving image updates
|
||||||
|
- Asset/manifest mismatches after rebuilds
|
||||||
|
- Assets being tied to the volume lifecycle rather than the image lifecycle
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Assets are moved out of the `sites` volume during the build process and replaced with a **symlink** later on. This means assets are always served from the image layer, while the rest of `sites` remains persistent.
|
||||||
|
|
||||||
|
### How it works
|
||||||
|
|
||||||
|
During the image build (`Containerfile`), the following is done:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
RUN cp -r /home/frappe/frappe-bench/sites/assets /home/frappe/frappe-bench/assets && \
|
||||||
|
rm -rf /home/frappe/frappe-bench/sites/assets
|
||||||
|
```
|
||||||
|
|
||||||
|
This runs **before** the `VOLUME` declaration, so the **`sites` volume does not contain any assets at all**.
|
||||||
|
|
||||||
|
Additionally an `ENTRYPOINT` is added to the images which adds a **symlink** from `assets` to `site\assets`.
|
||||||
|
|
||||||
|
> This is implemented in the entrypoint instead of baking the symlink directly into the image so it also works with pre-existing or already-initialized `sites` volumes.
|
||||||
|
> Since mounting a volume over `/home/frappe/frappe-bench/sites` hides the image contents at that path, any symlink created during the image build would not be visible inside the mounted volume. The entrypoint recreates the symlink at container startup, ensuring it always exists and automatically repairing older volumes that may not already contain it.
|
||||||
|
|
||||||
|
At runtime:
|
||||||
|
|
||||||
|
```
|
||||||
|
/home/frappe/frappe-bench/
|
||||||
|
├── assets/ ← image layer (ephemeral, always matches the image)
|
||||||
|
├── sites/
|
||||||
|
│ ├── assets -> /home/frappe/frappe-bench/assets ← symlink
|
||||||
|
│ ├── common_site_config.json ← persisted in volume
|
||||||
|
│ └── <site>/ ← persisted in volume
|
||||||
|
└── logs/ ← persisted in volume
|
||||||
|
```
|
||||||
|
|
||||||
|
### Volume behavior
|
||||||
|
|
||||||
|
| Path | Persistent | Source |
|
||||||
|
| -------------------------- | ----------------------- | ---------------------- |
|
||||||
|
| `sites/` (except assets) | ✅ Yes | Named volume (`sites`) |
|
||||||
|
| `sites/assets` (symlink) | ✅ Yes (symlink itself) | Named volume (`sites`) |
|
||||||
|
| `assets/` (symlink target) | ❌ No | Image layer |
|
||||||
|
| `logs/` | ✅ Yes | Unnamed volume |
|
||||||
|
|
||||||
|
The `sites/assets` symlink is stored inside the persistent `sites` volume, but its target (`/home/frappe/frappe-bench/assets`) comes from the container image. When the container is recreated or upgraded, the assets directory is recreated from the new image, ensuring assets always stay in sync with the running version.
|
||||||
|
|
||||||
|
## Important: `bench build` at runtime
|
||||||
|
|
||||||
|
Running `bench build` inside a running container will write new assets and eventually cause a mismatch between `assets.json` and the actual assets, breaking the UI. This can be recovered by recreating the containers
|
||||||
|
|
||||||
|
> Note: restarting the containers is not sufficient — they need to be recreated to discard the writable layer.
|
||||||
|
|
@ -15,7 +15,7 @@ importers:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
vitepress:
|
vitepress:
|
||||||
specifier: 2.0.0-alpha.16
|
specifier: 2.0.0-alpha.16
|
||||||
version: 2.0.0-alpha.16(postcss@8.5.8)
|
version: 2.0.0-alpha.16(postcss@8.5.15)
|
||||||
vitepress-sidebar:
|
vitepress-sidebar:
|
||||||
specifier: 1.33.1
|
specifier: 1.33.1
|
||||||
version: 1.33.1
|
version: 1.33.1
|
||||||
|
|
@ -408,6 +408,7 @@ packages:
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0':
|
'@ungap/structured-clone@1.3.0':
|
||||||
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
||||||
|
deprecated: Potential CWE-502 - Update to 1.3.1 or higher
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.5':
|
'@vitejs/plugin-vue@6.0.5':
|
||||||
resolution: {integrity: sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==}
|
resolution: {integrity: sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==}
|
||||||
|
|
@ -707,8 +708,8 @@ packages:
|
||||||
minisearch@7.2.0:
|
minisearch@7.2.0:
|
||||||
resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==}
|
resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==}
|
||||||
|
|
||||||
nanoid@3.3.11:
|
nanoid@3.3.12:
|
||||||
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
|
@ -739,8 +740,8 @@ packages:
|
||||||
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
postcss@8.5.8:
|
postcss@8.5.15:
|
||||||
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
|
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
property-information@7.1.0:
|
property-information@7.1.0:
|
||||||
|
|
@ -1214,7 +1215,7 @@ snapshots:
|
||||||
'@vue/shared': 3.5.30
|
'@vue/shared': 3.5.30
|
||||||
estree-walker: 2.0.2
|
estree-walker: 2.0.2
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
postcss: 8.5.8
|
postcss: 8.5.15
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
'@vue/compiler-ssr@3.5.30':
|
'@vue/compiler-ssr@3.5.30':
|
||||||
|
|
@ -1491,7 +1492,7 @@ snapshots:
|
||||||
|
|
||||||
minisearch@7.2.0: {}
|
minisearch@7.2.0: {}
|
||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.12: {}
|
||||||
|
|
||||||
oniguruma-parser@0.12.1: {}
|
oniguruma-parser@0.12.1: {}
|
||||||
|
|
||||||
|
|
@ -1516,9 +1517,9 @@ snapshots:
|
||||||
|
|
||||||
picomatch@4.0.4: {}
|
picomatch@4.0.4: {}
|
||||||
|
|
||||||
postcss@8.5.8:
|
postcss@8.5.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.11
|
nanoid: 3.3.12
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
|
@ -1671,7 +1672,7 @@ snapshots:
|
||||||
esbuild: 0.27.4
|
esbuild: 0.27.4
|
||||||
fdir: 6.5.0(picomatch@4.0.4)
|
fdir: 6.5.0(picomatch@4.0.4)
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
postcss: 8.5.8
|
postcss: 8.5.15
|
||||||
rollup: 4.59.0
|
rollup: 4.59.0
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
|
@ -1683,7 +1684,7 @@ snapshots:
|
||||||
gray-matter: 4.0.3
|
gray-matter: 4.0.3
|
||||||
qsu: 1.10.4
|
qsu: 1.10.4
|
||||||
|
|
||||||
vitepress@2.0.0-alpha.16(postcss@8.5.8):
|
vitepress@2.0.0-alpha.16(postcss@8.5.15):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@docsearch/css': 4.6.0
|
'@docsearch/css': 4.6.0
|
||||||
'@docsearch/js': 4.6.0
|
'@docsearch/js': 4.6.0
|
||||||
|
|
@ -1705,7 +1706,7 @@ snapshots:
|
||||||
vite: 7.3.2
|
vite: 7.3.2
|
||||||
vue: 3.5.30
|
vue: 3.5.30
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.5.8
|
postcss: 8.5.15
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- async-validator
|
- async-validator
|
||||||
|
|
|
||||||
13
example.env
13
example.env
|
|
@ -1,6 +1,6 @@
|
||||||
# Reference: https://github.com/frappe/frappe_docker/blob/main/docs/02-setup/04-env-variables.md
|
# Reference: https://github.com/frappe/frappe_docker/blob/main/docs/02-setup/04-env-variables.md
|
||||||
|
|
||||||
ERPNEXT_VERSION=v16.15.0
|
ERPNEXT_VERSION=v16.23.0
|
||||||
|
|
||||||
DB_PASSWORD=123
|
DB_PASSWORD=123
|
||||||
|
|
||||||
|
|
@ -15,6 +15,17 @@ DB_PORT=
|
||||||
REDIS_CACHE=
|
REDIS_CACHE=
|
||||||
REDIS_QUEUE=
|
REDIS_QUEUE=
|
||||||
|
|
||||||
|
|
||||||
|
# The number of threads per Gunicorn worker process for handling concurrent requests.
|
||||||
|
GUNICORN_THREADS=4
|
||||||
|
|
||||||
|
# The number of worker processes for handling requests.
|
||||||
|
# A typical formula is (2 x number of CPU cores) + 1.
|
||||||
|
GUNICORN_WORKERS=2
|
||||||
|
|
||||||
|
# Workers exceeding this timeout (in seconds) will be killed and restarted.
|
||||||
|
GUNICORN_TIMEOUT=120
|
||||||
|
|
||||||
# Only with HTTPS override
|
# Only with HTTPS override
|
||||||
LETSENCRYPT_EMAIL=mail@example.com
|
LETSENCRYPT_EMAIL=mail@example.com
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ LABEL author=frappé
|
||||||
|
|
||||||
ARG GIT_REPO=https://github.com/frappe/bench.git
|
ARG GIT_REPO=https://github.com/frappe/bench.git
|
||||||
ARG GIT_BRANCH=v5.x
|
ARG GIT_BRANCH=v5.x
|
||||||
|
ARG INSTALL_CHROMIUM=true
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
|
|
@ -23,8 +24,6 @@ RUN apt-get update \
|
||||||
libharfbuzz0b \
|
libharfbuzz0b \
|
||||||
libpangoft2-1.0-0 \
|
libpangoft2-1.0-0 \
|
||||||
libpangocairo-1.0-0 \
|
libpangocairo-1.0-0 \
|
||||||
#Chromium
|
|
||||||
chromium-headless-shell \
|
|
||||||
# to work inside the container
|
# to work inside the container
|
||||||
locales \
|
locales \
|
||||||
build-essential \
|
build-essential \
|
||||||
|
|
@ -75,6 +74,11 @@ RUN apt-get update \
|
||||||
file \
|
file \
|
||||||
# For MIME type detection
|
# For MIME type detection
|
||||||
media-types \
|
media-types \
|
||||||
|
# Chromium
|
||||||
|
&& if [ "$INSTALL_CHROMIUM" != "false" ]; then \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
|
chromium-headless-shell; \
|
||||||
|
fi \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \
|
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ COPY resources/core/nginx/security_headers.conf /etc/nginx/snippets/security_hea
|
||||||
|
|
||||||
ARG WKHTMLTOPDF_VERSION=0.12.6.1-3
|
ARG WKHTMLTOPDF_VERSION=0.12.6.1-3
|
||||||
ARG WKHTMLTOPDF_DISTRO=bookworm
|
ARG WKHTMLTOPDF_DISTRO=bookworm
|
||||||
|
ARG INSTALL_CHROMIUM=true
|
||||||
|
|
||||||
ARG NODE_VERSION=24.13.0
|
ARG NODE_VERSION=24.13.0
|
||||||
ENV NVM_DIR=/home/frappe/.nvm
|
ENV NVM_DIR=/home/frappe/.nvm
|
||||||
ENV PATH=${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
|
ENV PATH=${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
|
||||||
|
|
@ -26,8 +28,6 @@ RUN useradd -ms /bin/bash frappe \
|
||||||
libharfbuzz0b \
|
libharfbuzz0b \
|
||||||
libpangoft2-1.0-0 \
|
libpangoft2-1.0-0 \
|
||||||
libpangocairo-1.0-0 \
|
libpangocairo-1.0-0 \
|
||||||
#Chromium
|
|
||||||
chromium-headless-shell \
|
|
||||||
# For backups
|
# For backups
|
||||||
restic \
|
restic \
|
||||||
gpg \
|
gpg \
|
||||||
|
|
@ -62,6 +62,11 @@ RUN useradd -ms /bin/bash frappe \
|
||||||
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
|
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
|
||||||
&& apt-get install -y ./$downloaded_file \
|
&& apt-get install -y ./$downloaded_file \
|
||||||
&& rm $downloaded_file \
|
&& rm $downloaded_file \
|
||||||
|
# Chromium
|
||||||
|
&& if [ "$INSTALL_CHROMIUM" != "false" ]; then \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
|
chromium-headless-shell; \
|
||||||
|
fi \
|
||||||
# Clean up
|
# Clean up
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& rm -fr /etc/nginx/sites-enabled/default \
|
&& rm -fr /etc/nginx/sites-enabled/default \
|
||||||
|
|
@ -118,7 +123,10 @@ USER frappe
|
||||||
|
|
||||||
ARG FRAPPE_BRANCH=version-16
|
ARG FRAPPE_BRANCH=version-16
|
||||||
ARG FRAPPE_PATH=https://github.com/frappe/frappe
|
ARG FRAPPE_PATH=https://github.com/frappe/frappe
|
||||||
|
ARG CACHE_BUST=""
|
||||||
|
|
||||||
RUN --mount=type=secret,id=apps_json,target=/opt/frappe/apps.json,uid=1000,gid=1000 \
|
RUN --mount=type=secret,id=apps_json,target=/opt/frappe/apps.json,uid=1000,gid=1000 \
|
||||||
|
: "${CACHE_BUST}" && \
|
||||||
export APP_INSTALL_ARGS="" && \
|
export APP_INSTALL_ARGS="" && \
|
||||||
if [ -f /opt/frappe/apps.json ] && [ -s /opt/frappe/apps.json ]; then \
|
if [ -f /opt/frappe/apps.json ] && [ -s /opt/frappe/apps.json ]; then \
|
||||||
export APP_INSTALL_ARGS="--apps_path=/opt/frappe/apps.json"; \
|
export APP_INSTALL_ARGS="--apps_path=/opt/frappe/apps.json"; \
|
||||||
|
|
@ -143,20 +151,24 @@ COPY --from=builder --chown=frappe:frappe /home/frappe/frappe-bench /home/frappe
|
||||||
|
|
||||||
WORKDIR /home/frappe/frappe-bench
|
WORKDIR /home/frappe/frappe-bench
|
||||||
|
|
||||||
|
# Move assets to image-layer storage
|
||||||
|
RUN cp -r /home/frappe/frappe-bench/sites/assets /home/frappe/frappe-bench/assets && \
|
||||||
|
rm -rf /home/frappe/frappe-bench/sites/assets
|
||||||
|
|
||||||
VOLUME [ \
|
VOLUME [ \
|
||||||
"/home/frappe/frappe-bench/sites", \
|
"/home/frappe/frappe-bench/sites", \
|
||||||
"/home/frappe/frappe-bench/logs" \
|
"/home/frappe/frappe-bench/logs" \
|
||||||
]
|
]
|
||||||
|
|
||||||
CMD [ \
|
USER root
|
||||||
"/home/frappe/frappe-bench/env/bin/gunicorn", \
|
# This entrypoint script link build assets of the image to the mounted sites volume at container initialization
|
||||||
"--chdir=/home/frappe/frappe-bench/sites", \
|
COPY resources/core/main-entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
"--bind=0.0.0.0:8000", \
|
RUN chmod 755 /usr/local/bin/entrypoint.sh
|
||||||
"--threads=4", \
|
|
||||||
"--workers=2", \
|
COPY resources/core/start.sh /usr/local/bin/start.sh
|
||||||
"--worker-class=gthread", \
|
RUN chmod 755 /usr/local/bin/start.sh
|
||||||
"--worker-tmp-dir=/dev/shm", \
|
|
||||||
"--timeout=120", \
|
USER frappe
|
||||||
"--preload", \
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
"frappe.app:application" \
|
|
||||||
]
|
CMD ["start.sh"]
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ FROM ${FRAPPE_IMAGE_PREFIX}/build:${FRAPPE_BRANCH} AS builder
|
||||||
|
|
||||||
ARG FRAPPE_BRANCH=version-16
|
ARG FRAPPE_BRANCH=version-16
|
||||||
ARG FRAPPE_PATH=https://github.com/frappe/frappe
|
ARG FRAPPE_PATH=https://github.com/frappe/frappe
|
||||||
|
ARG CACHE_BUST=""
|
||||||
|
|
||||||
USER frappe
|
USER frappe
|
||||||
|
|
||||||
RUN --mount=type=secret,id=apps_json,target=/opt/frappe/apps.json,uid=1000,gid=1000 \
|
RUN --mount=type=secret,id=apps_json,target=/opt/frappe/apps.json,uid=1000,gid=1000 \
|
||||||
|
: "${CACHE_BUST}" && \
|
||||||
export APP_INSTALL_ARGS="" && \
|
export APP_INSTALL_ARGS="" && \
|
||||||
if [ -f /opt/frappe/apps.json ] && [ -s /opt/frappe/apps.json ]; then \
|
if [ -f /opt/frappe/apps.json ] && [ -s /opt/frappe/apps.json ]; then \
|
||||||
export APP_INSTALL_ARGS="--apps_path=/opt/frappe/apps.json"; \
|
export APP_INSTALL_ARGS="--apps_path=/opt/frappe/apps.json"; \
|
||||||
|
|
@ -33,20 +35,24 @@ COPY --from=builder --chown=frappe:frappe /home/frappe/frappe-bench /home/frappe
|
||||||
|
|
||||||
WORKDIR /home/frappe/frappe-bench
|
WORKDIR /home/frappe/frappe-bench
|
||||||
|
|
||||||
|
# Move assets to image-layer storage
|
||||||
|
RUN cp -r /home/frappe/frappe-bench/sites/assets /home/frappe/frappe-bench/assets && \
|
||||||
|
rm -rf /home/frappe/frappe-bench/sites/assets
|
||||||
|
|
||||||
VOLUME [ \
|
VOLUME [ \
|
||||||
"/home/frappe/frappe-bench/sites", \
|
"/home/frappe/frappe-bench/sites", \
|
||||||
"/home/frappe/frappe-bench/logs" \
|
"/home/frappe/frappe-bench/logs" \
|
||||||
]
|
]
|
||||||
|
|
||||||
CMD [ \
|
USER root
|
||||||
"/home/frappe/frappe-bench/env/bin/gunicorn", \
|
# This entrypoint script link build assets of the image to the mounted sites volume at container initialization
|
||||||
"--chdir=/home/frappe/frappe-bench/sites", \
|
COPY resources/core/main-entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
"--bind=0.0.0.0:8000", \
|
RUN chmod 755 /usr/local/bin/entrypoint.sh
|
||||||
"--threads=4", \
|
|
||||||
"--workers=2", \
|
COPY resources/core/start.sh /usr/local/bin/start.sh
|
||||||
"--worker-class=gthread", \
|
RUN chmod 755 /usr/local/bin/start.sh
|
||||||
"--worker-tmp-dir=/dev/shm", \
|
|
||||||
"--timeout=120", \
|
USER frappe
|
||||||
"--preload", \
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
"frappe.app:application" \
|
|
||||||
]
|
CMD ["start.sh"]
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ FROM python:${PYTHON_VERSION}-slim-${DEBIAN_BASE} AS base
|
||||||
|
|
||||||
ARG WKHTMLTOPDF_VERSION=0.12.6.1-3
|
ARG WKHTMLTOPDF_VERSION=0.12.6.1-3
|
||||||
ARG WKHTMLTOPDF_DISTRO=bookworm
|
ARG WKHTMLTOPDF_DISTRO=bookworm
|
||||||
|
ARG INSTALL_CHROMIUM=true
|
||||||
|
|
||||||
ARG NODE_VERSION=24.13.0
|
ARG NODE_VERSION=24.13.0
|
||||||
ENV NVM_DIR=/home/frappe/.nvm
|
ENV NVM_DIR=/home/frappe/.nvm
|
||||||
ENV PATH=${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
|
ENV PATH=${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
|
||||||
|
|
@ -22,8 +24,6 @@ RUN useradd -ms /bin/bash frappe \
|
||||||
libharfbuzz0b \
|
libharfbuzz0b \
|
||||||
libpangoft2-1.0-0 \
|
libpangoft2-1.0-0 \
|
||||||
libpangocairo-1.0-0 \
|
libpangocairo-1.0-0 \
|
||||||
#Chromium
|
|
||||||
chromium-headless-shell \
|
|
||||||
# For backups
|
# For backups
|
||||||
restic \
|
restic \
|
||||||
gpg \
|
gpg \
|
||||||
|
|
@ -58,6 +58,11 @@ RUN useradd -ms /bin/bash frappe \
|
||||||
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
|
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
|
||||||
&& apt-get install -y ./$downloaded_file \
|
&& apt-get install -y ./$downloaded_file \
|
||||||
&& rm $downloaded_file \
|
&& rm $downloaded_file \
|
||||||
|
# Chromium
|
||||||
|
&& if [ "$INSTALL_CHROMIUM" != "false" ]; then \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||||
|
chromium-headless-shell; \
|
||||||
|
fi \
|
||||||
# Clean up
|
# Clean up
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& rm -fr /etc/nginx/sites-enabled/default \
|
&& rm -fr /etc/nginx/sites-enabled/default \
|
||||||
|
|
@ -77,6 +82,7 @@ RUN useradd -ms /bin/bash frappe \
|
||||||
COPY resources/core/nginx/nginx-template.conf /templates/nginx/frappe.conf.template
|
COPY resources/core/nginx/nginx-template.conf /templates/nginx/frappe.conf.template
|
||||||
COPY resources/core/nginx/nginx-entrypoint.sh /usr/local/bin/nginx-entrypoint.sh
|
COPY resources/core/nginx/nginx-entrypoint.sh /usr/local/bin/nginx-entrypoint.sh
|
||||||
COPY resources/core/nginx/security_headers.conf /etc/nginx/snippets/security_headers.conf
|
COPY resources/core/nginx/security_headers.conf /etc/nginx/snippets/security_headers.conf
|
||||||
|
RUN chmod 755 /usr/local/bin/nginx-entrypoint.sh
|
||||||
|
|
||||||
FROM base AS build
|
FROM base AS build
|
||||||
|
|
||||||
|
|
@ -136,20 +142,24 @@ COPY --from=builder --chown=frappe:frappe /home/frappe/frappe-bench /home/frappe
|
||||||
|
|
||||||
WORKDIR /home/frappe/frappe-bench
|
WORKDIR /home/frappe/frappe-bench
|
||||||
|
|
||||||
|
# Move assets to image-layer storage
|
||||||
|
RUN cp -r /home/frappe/frappe-bench/sites/assets /home/frappe/frappe-bench/assets && \
|
||||||
|
rm -rf /home/frappe/frappe-bench/sites/assets
|
||||||
|
|
||||||
VOLUME [ \
|
VOLUME [ \
|
||||||
"/home/frappe/frappe-bench/sites", \
|
"/home/frappe/frappe-bench/sites", \
|
||||||
"/home/frappe/frappe-bench/logs" \
|
"/home/frappe/frappe-bench/logs" \
|
||||||
]
|
]
|
||||||
|
|
||||||
CMD [ \
|
USER root
|
||||||
"/home/frappe/frappe-bench/env/bin/gunicorn", \
|
# This entrypoint script link build assets of the image to the mounted sites volume at container initialization
|
||||||
"--chdir=/home/frappe/frappe-bench/sites", \
|
COPY resources/core/main-entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
"--bind=0.0.0.0:8000", \
|
RUN chmod 755 /usr/local/bin/entrypoint.sh
|
||||||
"--threads=4", \
|
|
||||||
"--workers=2", \
|
COPY resources/core/start.sh /usr/local/bin/start.sh
|
||||||
"--worker-class=gthread", \
|
RUN chmod 755 /usr/local/bin/start.sh
|
||||||
"--worker-tmp-dir=/dev/shm", \
|
|
||||||
"--timeout=120", \
|
USER frappe
|
||||||
"--preload", \
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
"frappe.app:application" \
|
|
||||||
]
|
CMD ["start.sh"]
|
||||||
|
|
|
||||||
44
overrides/compose.migrator.yaml
Normal file
44
overrides/compose.migrator.yaml
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Provides a service for automated migration of a given site.
|
||||||
|
|
||||||
|
# Compose extension fields of base compose.yaml. See https://github.com/frappe/frappe_docker/blob/main/compose.yaml
|
||||||
|
# Needed for merging compose files.
|
||||||
|
x-customizable-image: &customizable_image
|
||||||
|
# By default the image used only contains the `frappe` and `erpnext` apps.
|
||||||
|
# See https://github.com/frappe/frappe_docker/blob/main/docs/02-setup/02-build-setup.md#define-custom-apps
|
||||||
|
# about using custom images.
|
||||||
|
image: ${CUSTOM_IMAGE:-frappe/erpnext}:${CUSTOM_TAG:-$ERPNEXT_VERSION}
|
||||||
|
pull_policy: ${PULL_POLICY:-always}
|
||||||
|
restart: ${RESTART_POLICY:-unless-stopped}
|
||||||
|
|
||||||
|
x-depends-on-configurator: &depends_on_configurator
|
||||||
|
depends_on:
|
||||||
|
configurator:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
|
||||||
|
x-backend-defaults: &backend_defaults
|
||||||
|
<<: [*depends_on_configurator, *customizable_image]
|
||||||
|
volumes:
|
||||||
|
- sites:/home/frappe/frappe-bench/sites
|
||||||
|
|
||||||
|
services:
|
||||||
|
migrator:
|
||||||
|
<<: *backend_defaults
|
||||||
|
platform: linux/amd64
|
||||||
|
entrypoint:
|
||||||
|
- bash
|
||||||
|
- -c
|
||||||
|
command:
|
||||||
|
- >
|
||||||
|
if [ "$$MIGRATE_SITES" != "true" ]; then
|
||||||
|
echo "[migrator] Migration disabled";
|
||||||
|
exit 0;
|
||||||
|
fi;
|
||||||
|
if [ -z "$$(find sites -mindepth 2 -maxdepth 2 -name site_config.json 2>/dev/null)" ]; then
|
||||||
|
echo "[migrator] No sites found, skipping migration";
|
||||||
|
exit 0;
|
||||||
|
fi;
|
||||||
|
echo "[migrator] Migrating all sites";
|
||||||
|
bench --site all migrate;
|
||||||
|
environment:
|
||||||
|
MIGRATE_SITES: ${MIGRATE_SITES:-true}
|
||||||
|
restart: on-failure:5
|
||||||
16
pwd.yml
16
pwd.yml
|
|
@ -1,6 +1,6 @@
|
||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -16,7 +16,7 @@ services:
|
||||||
MARIADB_ROOT_PASSWORD: admin
|
MARIADB_ROOT_PASSWORD: admin
|
||||||
|
|
||||||
configurator:
|
configurator:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -45,7 +45,7 @@ services:
|
||||||
- logs:/home/frappe/frappe-bench/logs
|
- logs:/home/frappe/frappe-bench/logs
|
||||||
|
|
||||||
create-site:
|
create-site:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -101,7 +101,7 @@ services:
|
||||||
- db-data:/var/lib/mysql
|
- db-data:/var/lib/mysql
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
@ -127,7 +127,7 @@ services:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
|
|
||||||
queue-long:
|
queue-long:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -146,7 +146,7 @@ services:
|
||||||
FRAPPE_REDIS_QUEUE: redis://redis-queue:6379
|
FRAPPE_REDIS_QUEUE: redis://redis-queue:6379
|
||||||
|
|
||||||
queue-short:
|
queue-short:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -183,7 +183,7 @@ services:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -197,7 +197,7 @@ services:
|
||||||
- logs:/home/frappe/frappe-bench/logs
|
- logs:/home/frappe/frappe-bench/logs
|
||||||
|
|
||||||
websocket:
|
websocket:
|
||||||
image: frappe/erpnext:v16.15.0
|
image: frappe/erpnext:v16.23.0
|
||||||
networks:
|
networks:
|
||||||
- frappe_network
|
- frappe_network
|
||||||
deploy:
|
deploy:
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
pytest==9.0.3
|
pytest==9.1.0
|
||||||
|
|
|
||||||
12
resources/core/main-entrypoint.sh
Executable file
12
resources/core/main-entrypoint.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ASSETS_PATH="/home/frappe/frappe-bench/sites/assets"
|
||||||
|
BAKED_PATH="/home/frappe/frappe-bench/assets"
|
||||||
|
|
||||||
|
echo "Linking fresh assets to volume..."
|
||||||
|
rm -rf "$ASSETS_PATH"
|
||||||
|
mkdir -p "$(dirname "$ASSETS_PATH")"
|
||||||
|
ln -s "$BAKED_PATH" "$ASSETS_PATH"
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
20
resources/core/start.sh
Executable file
20
resources/core/start.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
#Gunicorn defaults
|
||||||
|
GUNICORN_THREADS=${GUNICORN_THREADS:-4}
|
||||||
|
GUNICORN_WORKERS=${GUNICORN_WORKERS:-2}
|
||||||
|
GUNICORN_TIMEOUT=${GUNICORN_TIMEOUT:-120}
|
||||||
|
|
||||||
|
echo "Booting Gunicorn with $GUNICORN_WORKERS workers and $GUNICORN_THREADS threads..."
|
||||||
|
|
||||||
|
exec /home/frappe/frappe-bench/env/bin/gunicorn \
|
||||||
|
--chdir=/home/frappe/frappe-bench/sites \
|
||||||
|
--bind=0.0.0.0:8000 \
|
||||||
|
--threads="$GUNICORN_THREADS" \
|
||||||
|
--workers="$GUNICORN_WORKERS" \
|
||||||
|
--worker-class=gthread \
|
||||||
|
--worker-tmp-dir=/dev/shm \
|
||||||
|
--timeout="$GUNICORN_TIMEOUT" \
|
||||||
|
--preload \
|
||||||
|
frappe.app:application
|
||||||
Loading…
Reference in a new issue