Home

Blog

Home

Blog

How to Install ERPNext on Ubuntu 24 Using Bench (Manual Setup)

12 min read
By David Muraya • February 9, 2026
Illustration of ERPNext manual installation on Ubuntu using Frappe Bench terminal commands

While Docker offers a quick containerized setup for ERPNext, many production environments and developers prefer the "Bench" method. This "bare metal" approach gives you granular control over the services, easier debugging, and direct access to the configuration files.

This guide covers installing ERPNext Version 16 on Ubuntu 24.04 LTS using modern tools like uv for Python management and nvm for Node.js.

Phase 1: System Preparation & Dependencies

Before we begin, we need to install the core engines and build tools. We will also create a dedicated frappe user, as running ERPNext directly as root is a significant security risk.

1. Update your system

Start by ensuring your package lists and installed packages are up to date.

sudo apt update && sudo apt upgrade -y

2. Install Core Dependencies

We need Git, Redis, MariaDB, Nginx, Supervisor, and various development headers.

sudo apt install -y git redis-server mariadb-server mariadb-client \
pkg-config libmariadb-dev gcc build-essential libssl-dev cron \
nginx supervisor python3-dev python3-setuptools python3-pip xvfb libfontconfig nano

3. Install wkhtmltopdf

ERPNext relies on wkhtmltopdf (with patched Qt) to generate PDFs. Since Ubuntu 24.04 has dropped support for this package and its dependencies (libssl1.1), we must manually install the library and the package.

# 1. Install libssl1.1 (Required dependency not in Noble repos)
wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb
sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb

# 2. Install wkhtmltopdf (Jammy Build)
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb
sudo dpkg -i wkhtmltox_0.12.6.1-3.jammy_amd64.deb

# 3. Fix any missing font/X11 dependencies
sudo apt --fix-broken install -y

Phase 2: Database Configuration

1. Configure MariaDB (Crucial Step)

ERPNext requires a specific database format (Barracuda) and character set. Without this, the installation will fail.

Edit the configuration file:

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

Add the following configuration block under [mysqld]:

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

[mysql]
default-character-set = utf8mb4

Restart MariaDB to apply changes:

sudo systemctl restart mariadb

2. Secure MariaDB

Run the security script to set a root password and remove insecure defaults.

sudo mariadb-secure-installation

Follow these responses:

  • Set root password? Yes (Choose a strong password)
  • Switch to unix_socket? No
  • Remove anonymous users? Yes
  • Disallow root login remotely? Yes
  • Remove test database? Yes
  • Reload privilege tables? Yes

Phase 3: User Setup

We will create the frappe user, set a password, and prepare the directory. We will also add the www-data user (which Nginx runs as) to the frappe group, ensuring it can read the static assets securely without opening permissions to the whole world.

# 1. Create the user and set a password
sudo useradd -m -s /bin/bash frappe
sudo usermod -aG sudo frappe
sudo passwd frappe

# 2. Add www-data to the frappe group (For Nginx Access)
sudo usermod -aG frappe www-data

# 3. Create the directory and set ownership
sudo mkdir -p /opt/frappe
sudo chown -R frappe:frappe /opt/frappe

# 4. Secure directory permissions
# 750: User(rwx), Group(rx), Others(none).
# This allows Nginx (in group) to read, but blocks others.
sudo chmod 750 /opt/frappe

# 5. Switch to the frappe user
sudo su - frappe

Note: All subsequent steps should be run as the frappe user unless specified otherwise.

Phase 4: Environment Setup (Node.js, UV, & Bench)

For a production environment, we recommend installing Node.js system-wide using the official NodeSource repository rather than nvm. This prevents path issues with Supervisor/Systemd.

1. Install Node.js 20 (LTS)

# Download and setup the NodeSource repository
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -

# Install Node.js
sudo apt-get install -y nodejs

# Install Yarn
sudo npm install -g yarn

2. Install UV & Python 3.14

We use pure Python 3.14 for this Version 16 setup using uv.

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.bashrc
uv python install 3.14 --default

3. Install Bench CLI

Install the bench command line tool using uv into a managed environment.

uv tool install frappe-bench --python python3.14

Phase 5: Initialize Bench & Install ERPNext

Now we initialize the Frappe Bench and install the ERPNext application.

cd /opt/frappe

# 1. Initialize Bench
bench init frappe-bench --frappe-branch version-16 --python python3.14
cd frappe-bench

# 2. Download the ERPNext App
bench get-app --branch version-16 erpnext

# 3. Create a New Site
# Replace 'erp.yourdomain.com' with your actual domain
bench new-site erp.yourdomain.com --admin-password 'YourAdminPass' --mariadb-root-password 'YourDBRootPass'

# 4. Install ERPNext on the site
bench --site erp.yourdomain.com install-app erpnext

# 5. Enable the Scheduler
bench --site erp.yourdomain.com enable-scheduler

Phase 6: Production Setup

For a production environment, we use Nginx as a reverse proxy and Supervisor to manage the processes.

1. Generate Configuration Files

Enable DNS multitenancy so Bench uses domain names to serve sites.

bench config dns_multitenant on
bench setup nginx
bench setup supervisor

We need to link the generated configs to the system directories. Run these as a user with sudo access (or use sudo).

# Remove default Nginx site
sudo rm /etc/nginx/sites-enabled/default

# Link Nginx config
sudo ln -s /opt/frappe/frappe-bench/config/nginx.conf /etc/nginx/conf.d/frappe.conf

# Link Supervisor config
sudo ln -s /opt/frappe/frappe-bench/config/supervisor.conf /etc/supervisor/conf.d/frappe.conf

# Reload services
sudo supervisorctl reread
sudo supervisorctl update
sudo systemctl restart nginx

3. Secure with Let's Encrypt (SSL)

Install Certbot and generate an SSL certificate for your domain.

# Install Certbot via Snap
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

# Run the Bench SSL setup command using the full path
sudo /home/frappe/.local/bin/bench setup lets-encrypt erp.yourdomain.com

Phase 7: Final Permissions Check

Because we are using a restricted directory (/opt/frappe), verify that the home directory permissions are applied correctly so Nginx (running as www-data) can read the assets.

# Ensure the group 'frappe' has execute (traverse) permissions on the home directory
sudo chmod 750 /opt/frappe

Your ERPNext instance should now be accessible at https://erp.yourdomain.com.


FAQ

1. Why use uv instead of standard pip? uv is significantly faster and handles Python version management cleanly without interfering with the system Python system. It simplifies managing specific versions like Python 3.14.

2. I get a "Permission Denied" error on static files. Ensure you ran the Phase 7 commands. Nginx runs as the www-data user, so it needs execute (traverse) permissions on the parent directories /opt and /opt/frappe to reach the static assets inside frappe-bench.

3. How do I update ERPNext? With bench, updating is straightforward:

cd /opt/frappe/frappe-bench
bench update

This pulls the latest code, runs database migrations, and builds the assets.

Share This Article

About the Author

David Muraya is a Solutions Architect specializing in Python, FastAPI, and Cloud Infrastructure. He is passionate about building scalable, production-ready applications and sharing his knowledge with the developer community. You can connect with him on LinkedIn.

Related Blog Posts

Enjoyed this blog post? Check out these related posts!

How to Install ERPNext on Ubuntu with Docker

How to Install ERPNext on Ubuntu with Docker

A Complete Guide to Deploying ERPNext with Docker Compose, Nginx, and SSL

Read More...

Add Client-Side Search to Your Reflex Blog with MiniSearch

Add Client-Side Search to Your Reflex Blog with MiniSearch

How to Build Fast, Offline Search for Your Python Blog Using MiniSearch and Reflex

Read More...

Run Python Scripts for Free with GitHub Actions: A Complete Guide

Run Python Scripts for Free with GitHub Actions: A Complete Guide

Schedule and Automate Python Scripts Without Managing Servers or Cloud Bills

Read More...

Stop Running Python Scripts Manually: A Guide to Google Cloud Scheduler

Stop Running Python Scripts Manually: A Guide to Google Cloud Scheduler

A Step-by-Step Guide to Creating Cron Jobs for Your Cloud Functions.

Read More...

On this page

Back to Blogs

Contact Me

Have a project in mind? Send me an email at hello@davidmuraya.com and let's bring your ideas to life. I am always available for exciting discussions.

© 2026 David Muraya. All rights reserved.