By Eben van Deventer on August 5, 2025
Intermediate

ERPNext is an amazing, free and open-source ERP system built using the Frappe Bench framework. It is scale-able, simple to use and quite beautiful. It is also quite difficult to install outside of the easy-installers which do not play nice with Debian.


In my case, I have a server running Debian 12, with Virtualmin installed, which means that MariaDB and Nginx are already serving several apps configured to various subdomains, this requires some tweaking of the ERPNext installation using DNS_Multitenant in bench.


In this tutorial, we will work through the steps necessary to implement ERPNext on an already configured Virtualmin installation.


This how-to assumes that you are logged in as root and have already configured your DNS server to forward the relevant subdomain to the correct server, and have created the relevant subdomain for your ERPNext site in Virtualmin (in this example erpnext.domain.com), Virtualmin will create the user erpnext (i.e. if you created a domain called erpnext.domain.com, normally the user is erpnext in Virtualmin), you should grant that user sudo priveleges:

usermod -aG sudo erpnext


Step 1 - Install Pre-requisite Software Packages:


Install the required packages:

apt install build-essential curl git python3-dev python3-setuptools python3-pip python3-distutils python3-venv supervisor software-properties-common redis-server mariadb-client libmariadb-dev pkg-config xvfb libfontconfig fontconfig xfonts-75dpi nodejs npm -y

Install wkhtmltopdf with patched qt

wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb


dpkg -i wkhtmltox_0.12.6.1-3.bookworm_amd64.deb

Install the Yarn NMP Package:

npm install -g yarn

Step 2 - Configure MariaDB


Configure MariaDB for use with Frappe-Bench:Edit your mariadb.cnf file to enable the Baracuda engine for innodb:

nano /etc/mysql/mariadb.conf.d/50-server.cnf

Insert the following below the [mysqld] block:

[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

Insert the following [mysql] block:

[mysql]
default-character-set = utf8mb4

Restart Mariadb

systemctl restart mariadb


Step 3 - Install Frappe Bench Python Packages


Login to Debian with the Virtualmin user that admins the domain you created for your Frappe site and make sure you are in the user's home directory:

cd ~

Install Frappe Bench:

sudo pip install frappe-bench ansible --break-system-packages


Step 4 - Create a Bench instance for your ERPNext installation


Create a Bench instance, name it anything you'd like, however I am going to use frappe-bench for ease of reference (you can use any folder name, but will need to replace frappe-bench with that folder name).

Make sure you are in your home directory:

cd

Initiate a version 15 bench:

bench init --frappe-branch version-15 frappe-bench

Switch to the newly created Bench instance folder, the name you chose at point 1 above will be the name of the bench folder:

cd frappe-bench

You can test whether it installed correctly with the following command, which should return the currently installed Bench version, 5.25.9 at the time of updating this how-to:

bench --version

Setup DNS Multitenant

bench config dns_multitenant on


Step 5 - Download the ERPNext app for Bench:


Here we make sure that we download all the apps we want to install in our Frappe Site, at the very least, you will need ERPNext:

bench get-app --branch version-15 erpnext

Otther apps you can consider:

Frappe HRMS (HR Management System):

bench get-app --branch version-15 hrms

My Industrial Relations Management App:

bench get-app https://github.com/buff0k/ir

Shridapatil's WhatsApp Integration for Frappe:

bench get-app https://github.com/shridarpatil/frappe_whatsapp

My Mining Production Tracking App:

bench get-app https://github.com/buff0k/is_production

My Mining Engineering Managing App:

bench get-app https://github.com/buff0k/engineering

My Internal IT Management App:

bench get-app https://github.com/buff0k/frappe_it

My Procurement Management App:

bench get-app https://github.com/buff0k/procurement


Step 6 - Create a site which will host your ERPNext instance:


Note that you should use the fqdn (Fully Qualified Domain Name) which you set up in Virtualmin. For this example we will use erpnext.domain.com. You will need the MariaDB root user password you set up when setting up Virtualmin, Create the Bench site:

bench new-site erpnext.domain.com --db-name erpnext

Provide the MariaDB root password which you configured during Virtualmin installation.


During the installation, the installer will ask you to create an Administrator Password, make a note of the password you choose as you will need it to log in to ERPNext once it is installed.


Step 7 - Install the ERPNext App in your Site


Install the ERPNext Bench App in the Bench Site you created in Step 6 above:

bench --site erpnext.domain.com install-app erpnext

You can also install any additional Apps using the same method, substituting the app name:

bench --site erpnext.domain.com install-app hrms

You can now manually start Bench using the command bench start, however we won't be doing that as we want it to start automatically, which is done by setting up Bench for Production Use.


Step 8 - Set up Bench for production use


In order to use your ERPNext installation in a production environment, you should automate starting, maintenance and various other tasks, luckily Bench can do this for you by making use of Supervisor, which we installed during Step 1 (note, the last reference to erpnext refers to the username in which you installed your Bench):

sudo bench setup production erpnext

Enable Scheduler:

bench --site erpnext.domain.com enable-scheduler

Step 9 - Make it work with Virtualmnin


In order to use your ERPNext installation Virtualmin, we now need to tweak some settings to properly ensure that the default nginx.conf installation of Frappe does not break your Virtualmin NginX setup (Again, we used frappe-bench, your bench foldername will inform the filename):

sudo rm /etc/nginx/conf.d/frappe-bench.conf

Manually edit the NginX config for Virtualmin to add the following lines from your Frappe nginx.conf file to the top of the NginX config file for Virtualmin:

upstream lab-bench-frappe {
server 127.0.0.1:8000 fail_timeout=0;
}

upstream lab-bench-socketio-server {
server 127.0.0.1:9000 fail_timeout=0;
}

Manually edit the NginX config for Virtualmin to add the followng lines from your Frappe nginx.conf file into the server block of the NginX config file for Virtualmin:

   proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;


add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "same-origin, strict-origin-when-cross-origin";

location /assets {
     try_files $uri =404;
     add_header Cache-Control "max-age=31536000";
}

location ~ ^/protected/(.*) {
     internal;
     try_files /$host/$1 =404;
}

location /socket.io {
     proxy_http_version 1.1;
     proxy_set_header Upgrade $http_upgrade;
     proxy_set_header Connection "upgrade";
     proxy_set_header X-Frappe-Site-Name $host;
     proxy_set_header Origin $scheme://$http_host;
     proxy_set_header Host $host;

     proxy_pass http://lab-bench-socketio-server;
}

location / {

    rewrite ^(.+)/$ $1 permanent;
     rewrite ^(.+)/index\.html$ $1 permanent;
     rewrite ^(.+)\.html$ $1 permanent;

     location ~* ^/files/.*.(htm|html|svg|xml) {
      add_header Content-disposition "attachment";
    try_files /$host/public/$uri @webserver;
     }

     try_files /$host/public/$uri @webserver;
}

location @webserver {
     proxy_http_version 1.1;
     proxy_set_header X-Forwarded-For $remote_addr;
     proxy_set_header X-Forwarded-Proto $scheme;
     proxy_set_header X-Frappe-Site-Name $host;
     proxy_set_header Host $host;
     proxy_set_header X-Use-X-Accel-Redirect True;
     proxy_read_timeout 120;
     proxy_redirect off;

     proxy_pass  http://lab-bench-frappe;
}

# error pages
error_page 502 /502.html;
location /502.html {
     root /usr/local/lib/python3.11/dist-packages/bench/config/templates;
     internal;
  }


# optimizations
sendfile on;
keepalive_timeout 15;
client_max_body_size 50m;
client_body_buffer_size 16K;
client_header_buffer_size 1k;

# enable gzip compresion
# based on https://mattstauffer.co/blog/enabling-gzip-on-nginx-servers-including-laravel-forge
gzip on;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
     application/atom+xml
     application/javascript
     application/json
     application/rss+xml
     application/vnd.ms-fontobject
     application/x-font-ttf
     application/font-woff
     application/x-web-app-manifest+json
     application/xhtml+xml
     application/xml
     font/opentype
     image/svg+xml
     image/x-icon
     text/css
     text/plain
     text/x-component
   ;

Manually edit the NginX config for Virtualmin and comment out your root directive (add # infront of) as follows:

#root /home/erpnext/public_html

Manually edit the NginX config for Virtualmin and insert the root directive from the Frappe nginx.conf file:

root /home/erpnext/frappe-bench/sites;

Restart Nginx

sudo systemctl restart nginx


Step 10 - BUGFIX - Supervisor


There appears to be an issue with the installation wherein configuring production does not properly enable Supervisor on Debain 12. The workaround is to just point supervisor to the correct .conf file.


Stop Supervisor

sudo supervisorctl stop all

Create a synlink for the Frappe-Bench supervisorctl.conf file in the Supervisor conf.d folder:

sudo ln -sf /home/erpnext/frappe-bench/config/supervisor.conf /etc/supervisor/conf.d/frappe-bench.conf

Reconfigure Supervisor:

sudo supervisorctl reread


sudo supervisorctl update


sudo supervisorctl restart all


Step 11 - Fix CSS (Optional, might not be necessary)


Due to the way in which Debian 12 works wit permissions and python3, sometimes the css will not load properly, your Frappe Site will not display properly, if this occurs, we need to fix the permissions of the frappe user folder:

sudo chmod 701 /home/frappe

And you are done, now simply point your browser at the site you configured: http://erpnext.domain.com/ and it should show you the login page. Use Administrator as the username and the password which you configured during point 3 in Step 7.


Edit - Updating your Bench Sites


When you need to update your Bench sites to the latest version, login as the bench user and cd to your bench instance folder:

cd frappe-bench


bench update


Edit - Updating Frappe Bench


From time to time you might need to update Frappe-Bench, the correct method is to login as the bench user you have created and running the following command:

sudo pip install --upgrade frappe-bench


Edit - Restoring from backups


Make sure that you upload the backup files to the /tmp folder, note that there are three (3) files, being ...-database.sql.gz which contains the backup of your ERPNext data, ...-files.tar which contains your public files and ...-private-files.tar which contains your private files. Again, this must be run from your bench folder:

cd frappe-bench


bench --site erpnext.domain.com --force restore /tmp/...-database.sql.gz --with-private-files /tmp/...-private-files.tar --with-public-files /tmp/...-files.tar


Edit - Restart from scratch


If you want to delete all the setup and configuration (Such as when testing) but don't want to go through all the steps of starting up a new setup, you can simply reset the database as follows:

cd frappe-bench


bench --site erpnext.domain.com --force reinstall


Edit - Redis issues with new installs


Configure Bench to use the default Redis configuration (This is a workaround for a known issue where initial installation does not deploy redis properly):

bench set-config -g redis_cache redis://127.0.0.1:6379


bench set-config -g redis_queue redis://127.0.0.1:6379


bench set-config -g redis_socketio redis://127.0.0.1:6379


Edit - Multipiple Benches as Seperate Users


If you are doing this, remember to edit the port numbers in /home/user/bench-folder/sites/commong_site_config.json, /home/user/bench-folder/config/redis_cache.conf and /home/user/bench-folder/config/redis_queue.conf to different port numbers, and then remember to run


bench setup redis

Edit - Setup Developer Mode


If you plan to develop Frappe apps in your bench deployment, you should set the bench to developer mode, in order to do this, you should execute the following in your bench directory:


bench set-config -g developer_mode 1


You should also install the developer requirements


bench setup requirements --dev


More articles on ERPNext



More articles on ERPNext
Comments

No comments yet.

Add a comment
Ctrl+Enter to add comment