[Guide] ERPNext-14 Production Setup (Docker)

ERPNext-14 Production Setup

In this Setup we assume that you have the Custom App and you are using mariadb and OS is Ubuntu 18+.

ERP Discuss

Step 1:

Load the Custom App and other apps are hrms & payments module.

assume my custom app is custom_erpnext

Clone the frappe_docker. Open your Terminal.

Run Command


git clone https://github.com/frappe/frappe_docker

assume you’re using this domain ziptor.com. Note: It’s only for testing purposes don’t use this use your correct domain

Change the frappe_docker folder name to ziptor. Note: this step is only for understanding it’s not necessary

Run Command


sudo mv frappe_docker ziptor

cd ziptor

Load the custom App

Run Command


export APPS_JSON='[

{

"url": "https://github.com/frappe/erpnext",

"branch": "v14.24.1"

},

{

"url": "https://github.com/frappe/hrms",

"branch": "version-14"

},

{

"url": "https://github.com/frappe/payments",

"branch": "version-14"

},

{

"url": "https://access_token@github.com/my-github/custom_app",

"branch": "main"

}

]'

Note: change your custom app repo link and access_token and respective branch

Run Command


export APPS_JSON_BASE64=$(echo ${APPS_JSON} | base64 -w 0)

After taking your custom image change the compose.yaml file


x-customizable-image: &customizable_image

image: customapp:1.0.0

pull_policy: never

Run Command


docker build \

--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \

--build-arg=FRAPPE_BRANCH=v14.24.1 \

--build-arg=PYTHON_VERSION=3.10.5 \

--build-arg=NODE_VERSION=16.16.0 \

--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \

--tag=customapp:1.0.0 \

--file=images/custom/Containerfile .

Note: custom_app_14:1.0.0 is your custom image

:warning:Note​:warning:: after taking the build if you want to update the code add --no-cache in the command. like this.


docker build --no-cache \

--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \

--build-arg=FRAPPE_BRANCH=v14.24.1 \

--build-arg=PYTHON_VERSION=3.10.5 \

--build-arg=NODE_VERSION=16.16.0 \

--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \

--tag=customapp:1.0.0 \

--file=images/custom/Containerfile .

Step 2:

Create configuration and resources directory

Run Command


mkdir ~/gitops

Step 3:

Basic Traefik setup using docker compose. Create a file called traefik.env in ~/gitops

Run Command


echo 'TRAEFIK_DOMAIN=ziptor.com' > ~/gitops/traefik.env

echo 'EMAIL=admin@ziptor.com' >> ~/gitops/traefik.env

echo 'HASHED_PASSWORD='$(openssl passwd -apr1 changeit | sed 's/\$/\\\$/g') >> ~/gitops/traefik.env

Deploy the traefik container with letsencrypt SSL

Run Command


docker compose --project-name traefik \

--env-file ~/gitops/traefik.env \

-f overrides/compose.traefik.yaml \

-f overrides/compose.traefik-ssl.yaml up -d

Step 4

Install MariaDB

Basic MariaDB setup using docker compose. Create a file called mariadb.env in ~/gitops

Run Command


echo "DB_PASSWORD=changeit" > ~/gitops/mariadb.env

Note:

Change the password from changeit to more secure. env file generated at location ~/gitops/mariadb.env will look like following:

Deploy the mariadb container


docker compose --project-name mariadb --env-file ~/gitops/mariadb.env -f overrides/compose.mariadb-shared.yaml up -d

Step 5

Install ERPNext

Create First Bench

Create first bench called erpnext-one with ziptor.com.

Create a file called erpnext-one.env in ~/gitops

Run Command


cp example.env ~/gitops/erpnext-one.env

sed -i 's/DB_PASSWORD=123/DB_PASSWORD=changeit/g' ~/gitops/erpnext-one.env

sed -i 's/DB_HOST=/DB_HOST=mariadb-database/g' ~/gitops/erpnext-one.env

sed -i 's/DB_PORT=/DB_PORT=3306/g' ~/gitops/erpnext-one.env

sed -i 's/SITES=`erp.example.com`/SITES=\`ziptor.com\`/g' ~/gitops/erpnext-one.env

echo 'ROUTER=erpnext-one' >> ~/gitops/erpnext-one.env

echo "BENCH_NETWORK=erpnext-one" >> ~/gitops/erpnext-one.env

Create erpnext-one.yaml

Run Command


docker compose --project-name erpnext-one \

--env-file ~/gitops/erpnext-one.env \

-f compose.yaml \

-f overrides/compose.redis.yaml \

-f overrides/compose.multi-bench.yaml \

-f overrides/compose.multi-bench-ssl.yaml config > ~/gitops/erpnext-one.yaml

Deploy erpnext-one containers:

Run Command


docker compose --project-name erpnext-one -f ~/gitops/erpnext-one.yaml up -d

Create sites ziptor.com:


docker compose --project-name erpnext-one exec backend \

bench new-site ziptor.com --no-mariadb-socket --mariadb-root-password changeit --install-app erpnext --admin-password changeit

Note: change the correct DB and Admin password changeit to some secure one

----------------------------------------🔥SET UP DONE🔥--------------------------------------------

But here you have to notice something. the sechedular is disabled

Schedular

List of containers using custom image i mean customapp


erpnext-one-frontend-1

erpnext-one-backend-1

erpnext-one-queue-short-1

erpnext-one-scheduler-1

erpnext-one-websocket-1

erpnext-one-queue-long-1

erpnext-one-queue-default-1

Use this command to check in all these containers your custom app installed.


docker exec -it <CONTAINER_NAME> bash

example


docker exec -it erpnext-one-frontend-1 bash

Enable Schedular


bench --site ziptor.com enable-scheduler

12 Likes

Thanks for your nice tutorial.

@Antony_Praveenkumar
how we could update the ERPNext to the specific version of ERPNext, in side the container?

1 Like

Could you explain this , what mean by update the codes?

You have have custom_app if you want to deploy the erpnext with new features you have to update your custom_app code right for that you have to again built a Custom Image in that case you already have a image customapp:1.0.0 if you run the normal command, the code won’t be updated. for that you have to use --no--cache tag in docker built command.

what is the meaning of this setting?

the pull_policy setting determines whether a container image should be pulled from the registry or not

you are wonderfull

1 Like

@Antony_Praveenkumar This is really helpful
Thanks

While creating the site you didn’t install the custom apps loaded earlier (hrms, payments). Are they installed along with the image built earlier?

yes you have to navigate inside the container and install all your apps like

bench --site mysite.com install-app hrms
bench --site mysite.com install-app payments
bench --site mysite.com install-app custom_app
1 Like

Do you mean to use install-app?

bench --site mysite.com install-app hrms

yes sorry typo. please check now

2 Likes

I keep having problems with this output. It seems like traefik is not parsing the password the way it is intended. If the reader’s facing the same problem as I am, he can single quote the output in traefik.env file. Or do that in the echo command:

echo 'HASHED_PASSWORD='$(openssl passwd -apr1 changeit | sed 's/\(^.*$\)/\x27\1\x27/g') >> ~/gitops/traefik.env

After doing the above, no more complains from traefik startup.

2 Likes

does this assume that you have no Traefik installed? If so how can I replicate the same for instances where I have Traefik (docker version)

If traefik is already installed check labels for frontend service and tweak them for your use

1 Like

Thanks kind sir for the reply. So my current setup is somewhat a homelab, using proxmox and created a VM using Ubuntu 22 . I am managing my DNS using cloudflare. Initially i had managed using NGINX proxy manager but upon installing HRMS, i get Internal server error, efforts trying to fix it proved futile. I encountered this post and tried to follow but i encountered some errors

ERROR: failed to solve: process "/bin/sh -c useradd -ms /bin/bash frappe     && apt-get update     && apt-get install --no-install-recommends -y     curl     git     vim     nginx     gettext-base     libpango-1.0-0     libharfbuzz0b     libpangoft2-1.0-0     libpangocairo-1.0-0     restic     mariadb-client     libpq-dev     postgresql-client     wait-for-it     jq     && mkdir -p ${NVM_DIR}     && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash     && . ${NVM_DIR}/nvm.sh     && nvm install ${NODE_VERSION}     && nvm use v${NODE_VERSION}     && npm install -g yarn     && nvm alias default v${NODE_VERSION}     && rm -rf ${NVM_DIR}/.cache     && echo 'export NVM_DIR=\"/home/frappe/.nvm\"' >>/home/frappe/.bashrc     && echo '[ -s \"$NVM_DIR/nvm.sh\" ] && \\. \"$NVM_DIR/nvm.sh\"  # This loads nvm' >>/home/frappe/.bashrc     && echo '[ -s \"$NVM_DIR/bash_completion\" ] && \\. \"$NVM_DIR/bash_completion\"  # This loads nvm bash_completion' >>/home/frappe/.bashrc     && if [ \"$(uname -m)\" = \"aarch64\" ]; then export ARCH=arm64; fi     && if [ \"$(uname -m)\" = \"x86_64\" ]; then export ARCH=amd64; fi     && downloaded_file=wkhtmltox_${WKHTMLTOPDF_VERSION}.${WKHTMLTOPDF_DISTRO}_${ARCH}.deb     && curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file     && apt-get install -y ./$downloaded_file     && rm $downloaded_file     && rm -rf /var/lib/apt/lists/*     && rm -fr /etc/nginx/sites-enabled/default     && pip3 install frappe-bench     && sed -i '/user www-data/d' /etc/nginx/nginx.conf     && ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log     && touch /run/nginx.pid     && chown -R frappe:frappe /etc/nginx/conf.d     && chown -R frappe:frappe /etc/nginx/nginx.conf     && chown -R frappe:frappe /var/log/nginx     && chown -R frappe:frappe /var/lib/nginx     && chown -R frappe:frappe /run/nginx.pid     && chmod 755 /usr/local/bin/nginx-entrypoint.sh     && chmod 644 /templates/nginx/frappe.conf.template" did not complete successfully: exit code: 3

how can i solve this?

Below is the initial command that i ran

I was trying with pwd.yml and other methods but always ended up with errors in my db container.

After trying your method, this is the first error I got:
pymysql.err.OperationalError: (2003, “Can’t connect to MySQL server on ‘mariadb-database’ ([Errno -2] Name or service not known)”)

Apparently backend and db containers were in different networks. Made them join the same and was able to create my site.

Unfortunately, I got the same packet error as other methods I was trying
2023-07-06 1:53:45 648 [Warning] Aborted connection 648 to db: ‘_3b545afc96aa58dc’ user: ‘_3b545afc96aa58dc’ host: ‘192.168.128.8’ (Got an error reading communication packets)

I already tried changing packet size to something big like --max_allowed_packet=32505856, but it looks like mariadb isn’t taking any argument from the docker compose file.

Edited manually my /etc/mysql/my.cnf changing max_allowed_packet=256M and innodb_read_only_compressed = 0, still errors and access denied to my site.

I’ve been trying for some hours to deploy with no success.

Try it as command param?

Hello @revant_one so i had to rewire my setup to use Debian 11(old stable). Come’s with minimum programs possible and upon installation it was swift and works pretty fine. And i actually never noticed the extensive doc was located in the repo. Although that is said …one last problem is upon installation, i noticed i cannot load the custom app.
This is the initial script that i ran

export APPS_JSON='[
  {
    "url": "https://github.com/frappe/erpnext",
    "branch": "v14.24.1"
  },
  {
    "url": "https://github.com/frappe/hrms",
    "branch": "version-14"
  },
  {
    "url": "https://github.com/frappe/payments",
    "branch": "version-14"
  }
]'

and finally ended it with

export APPS_JSON_BASE64=$(echo ${APPS_JSON} | base64 -w 0)

So when i tried to run this command when all is wired

bench --site mysite.com install-app hrms

or any other apps i get an error that it doesn’t exist.

No module named 'hrms'
An error occurred while installing hrms: No module named 'hrms'
Traceback (most recent call last):
  File "apps/frappe/frappe/utils/caching.py", line 55, in wrapper
    return frappe.local.request_cache[func][args_key]
KeyError: -2033177531763587219

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "apps/frappe/frappe/commands/site.py", line 416, in install_app
    _install_app(app, verbose=context.verbose, force=force)
  File "apps/frappe/frappe/installer.py", line 262, in install_app
    app_hooks = frappe.get_hooks(app_name=name)
  File "apps/frappe/frappe/__init__.py", line 1494, in get_hooks
    hooks = _dict(_load_app_hooks(app_name))
  File "apps/frappe/frappe/utils/caching.py", line 57, in wrapper
    return_val = func(*args, **kwargs)
  File "apps/frappe/frappe/__init__.py", line 1466, in _load_app_hooks
    app_hooks = get_module(f"{app}.hooks")
  File "apps/frappe/frappe/__init__.py", line 1328, in get_module
    return importlib.import_module(modulename)
  File "/usr/local/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'hrms'

I currently don’t have any kind of custom app. Kindly advice

execute

ls -1 apps > sites/apps.txt

Then try installing app