In DNS-based multitenant setup, Data Import works on first site but silently fails on second site

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.com

    • hrms-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 :white_check_mark: Data Import works
hrms-site-2.somedomain.com :cross_mark: Data Import silently fails

📌 Summary

  • Custom HRMS v16 image ✔

  • DNS-based multitenancy ✔

  • Multiple sites ✔

  • Scheduler enabled ✔

  • Data Import inconsistent across sites ❌


:white_check_mark: Issue Fixed: Database Permissions (Critical)

The issue was resolved by correcting MariaDB user permissions to ensure stable access regardless of container IP changes.

:wrench: Steps Performed

1. Exit backend container and connect to database

docker exec -it frappe-hrms-db-1 mariadb -u root -p

Enter the DB_PASSWORD from frappe-hrms.env.


2. Get database credentials from site config

docker exec -it frappe-hrms-backend-1 bash
cat sites/site2.yourdomain.com/site_config.json

Note the following values:

  • db_name
  • db_password
  • db_user

3. Fix permissions in MariaDB console

-- Check current user
SELECT User, Host FROM mysql.user WHERE User = 'YOUR_DB_USER';

-- Grant wildcard access (prevents IP change issues)
GRANT ALL PRIVILEGES ON `YOUR_DB_NAME`.* 
TO 'YOUR_DB_USER'@'%' 
IDENTIFIED BY 'YOUR_DB_PASSWORD';

FLUSH PRIVILEGES;

-- Verify
SELECT User, Host FROM mysql.user WHERE User = 'YOUR_DB_USER';

exit

:white_check_mark: Expected Result

  • Database user should have Host = %
  • Application connects successfully without permission errors
  • Issue fully resolved