Frappe HRMS v16 – Custom Image & DNS Multi-Tenancy Setup
🎯 Motive
Build a custom Docker image for Frappe + ERPNext + HRMS v16
Run DNS-based multi-tenancy using Traefik
Host multiple HRMS sites on the same stack:
hrms-site-1.somedomain.comhrms-site-2.somedomain.com
Keep deployment reproducible and production-safe
⚠️ Issue Faced
Data Import Tool works correctly on the first site
Data Import Tool silently fails on the second site
No UI error, no job failure, no traceback
All other features (login, CRUD, reports, scheduler) work normally
0. Clean Reset (Fresh Server Only)
docker compose -f frappe-hrms-compose.yml down -v
docker system prune -a --volumes -f
rm -rf frappe_docker frappe-hrms* easy-install.*
1. Download & Prepare Installer
wget https://raw.githubusercontent.com/frappe/bench/develop/easy-install.py
nano easy-install.py
(Custom defaults already set: Frappe version-16, Python 3.14, Node 24.1.0)
2. Build Custom Image (Build #1 – Bootstrap)
[
{
"url": "https://github.com/USERNAME/erpnext",
"branch": "version-16",
"name": "erpnext"
},
{
"url": "https://github.com/USERNAME/hrms",
"branch": "version-16",
"name": "hrms"
}
]
python3 easy-install.py build \
--apps-json apps.json \
--containerfile images/custom/Containerfile \
--tag USERNAME/frappe-hrms:version-16 \
--push
3. Edit Containerfile
nano frappe_docker/images/custom/Containerfile
Ensure:
ARG PYTHON_VERSION=3.14
ARG NODE_VERSION=24.1.0
4. Build Custom Image (Build #2 – Final)
python3 easy-install.py build \
--apps-json apps.json \
--containerfile images/custom/Containerfile \
--tag USERNAME/frappe-hrms:version-16 \
--push
5. Deploy (Deploy #1 – Expected Failure)
python3 easy-install.py deploy \
--project frappe-hrms \
--sitename hrms-site-1.somedomain.com \
--email admin@somedomain.com \
--image USERNAME/frappe-hrms:version-16 \
--app erpnext \
--app hrms
6. Fix Environment File
sed -i '/^ERPNEXT_VERSION=/d' frappe-hrms.env
sed -i 's|CUSTOM_IMAGE=USERNAME/frappe-hrms:version-16|CUSTOM_IMAGE=USERNAME/frappe-hrms|' frappe-hrms.env
echo "CUSTOM_TAG=version-16" >> frappe-hrms.env
7. Deploy (Deploy #2 – Real)
python3 easy-install.py deploy \
--project frappe-hrms \
--sitename hrms-site-1.somedomain.com \
--email admin@somedomain.com \
--image USERNAME/frappe-hrms:version-16 \
--app erpnext \
--app hrms
8. Enable DNS Multitenancy
nano frappe-hrms-compose.yml
Change Traefik rule:
HostRegexp(`{host:.+}`)
Restart stack:
docker compose -f frappe-hrms-compose.yml down
docker compose -f frappe-hrms-compose.yml up -d
Enable in Frappe:
docker exec -it frappe-hrms-backend-1 bash
bench config dns_multitenant on
exit
9. Create Second Site
docker exec -it frappe-hrms-backend-1 bash
bench new-site hrms-site-2.somedomain.com
bench --site hrms-site-2.somedomain.com install-app erpnext
bench --site hrms-site-2.somedomain.com install-app hrms
10. Enable Schedulerbench --site hrms-site-1.somedomain.com enable-scheduler
bench --site hrms-site-2.somedomain.com enable-scheduler
11. Current State
Site
Status
hrms-site-1.somedomain.com
Data Import works
hrms-site-2.somedomain.com
Data Import silently fails
📌 Summary
Custom HRMS v16 image ✔
DNS-based multitenancy ✔
Multiple sites ✔
Scheduler enabled ✔
Data Import inconsistent across sites ❌