Installing ERPNext 15 on Debian 12 with Virtualmin
By Eben van Deventer on August 5, 2025
IntermediateERPNext 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 = FALSEcharacter-set-server = utf8mb4collation-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 pageserror_page 502 /502.html;location /502.html {root /usr/local/lib/python3.11/dist-packages/bench/config/templates;internal;}# optimizationssendfile 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-forgegzip on;gzip_http_version 1.1;gzip_comp_level 5;gzip_min_length 256;gzip_proxied any;gzip_vary on;gzip_typesapplication/atom+xmlapplication/javascriptapplication/jsonapplication/rss+xmlapplication/vnd.ms-fontobjectapplication/x-font-ttfapplication/font-woffapplication/x-web-app-manifest+jsonapplication/xhtml+xmlapplication/xmlfont/opentypeimage/svg+xmlimage/x-icontext/csstext/plaintext/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