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

You can also increase your swap memory if your server has limited RAM:

sudo fallocate -l 8G /swapfile && \
sudo chmod 600 /swapfile && \
sudo mkswap /swapfile && \
sudo swapon /swapfile && \
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

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 character set configuration (utf8mb4) to function correctly. We will create a dedicated configuration file to ensure these settings are applied without modifying the default system files.

sudo tee /etc/mysql/mariadb.conf.d/99-frappe.cnf > /dev/null <<'EOF'
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

[mysql]
default-character-set = utf8mb4
EOF

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.

We also need to ensure the frappe user's home path is correctly added to the $PATH variable for executing local binaries.

# 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

# 6. Add ~/.local/bin to PATH
echo 'export PATH=$PATH:~/.local/bin/' >> ~/.bashrc
source ~/.bashrc

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 24 (LTS)

# Download and setup the NodeSource repository
curl -fsSL https://deb.nodesource.com/setup_24.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

Tip: If you encounter "EXTERNALLY-MANAGED" errors with pip later, creating a pipConfig or deleting the EXTERNALLY-MANAGED file (risky) is common, but using uv or pipx (as we did above) is the cleaner solution.

4. Verification Checkpoint

Before initializing the bench, ensure all core components are correctly installed and accessible by the frappe user.

# Check Python version (Should be 3.14.x)
python3.14 --version && \

# Check Node.js version (Should be v24.x)
node --version && \

# Check NPM version
npm --version && \

# Check Yarn version
yarn --version && \

# Check MariaDB version
mariadb --version && \

# Check Redis
redis-server --version && \

# Check wkhtmltopdf (Should be 0.12.6 with patched qt)
wkhtmltopdf --version

If any of these commands fail or return unexpected versions, review the previous steps before proceeding.

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. Fix Nginx Log Format (If Nginx Fails)

If Nginx fails to start, it is often due to an undefined main log format. Adjust the configuration to use the default format.

Open the Frappe Nginx config:

nano /opt/frappe/frappe-bench/config/nginx.conf

Find the line (around line 101):

access_log  /var/log/nginx/access.log main;

Change it to:

access_log  /var/log/nginx/access.log;

Then restart Nginx:

sudo systemctl restart nginx

4. 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 & Service 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

Finally, verify that all production services are running correctly:

# Check Supervisor status (Processes should be 'RUNNING')
sudo supervisorctl status

# Check Nginx status
sudo systemctl status nginx

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

ERPNext comes with a standard print format builder, but for pixel-perfect invoices and reports, we recommend the Print Designer app. It offers a modern drag-and-drop interface.

1. Get the App

Download the app code into your bench.

cd /opt/frappe/frappe-bench

# Get the app (defaults to the latest compatible version)
bench get-app print_designer

Note: If you are strictly version-binding, you can add --branch version-16 (or 15/14) to match your setup.

2. Install on Your Site

Install the application on your active site.

bench --site erp.yourdomain.com install-app print_designer

3. Restart & Verify

Restart the bench processes to load the new app, then confirm it is listed.

bench restart

# Verify installation
bench --site erp.yourdomain.com list-apps

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? To update your apps (ERPNext, Frappe) and sites, run:

cd /opt/frappe/frappe-bench
bench update

This pulls the latest code, runs database migrations, and builds the assets. To update the Bench CLI tool itself (e.g., if you see "A newer version of bench is available"), run:

uv tool upgrade frappe-bench

4. How do I fix "Unknown Column" database errors? This error occurs when the database schema is out of sync with the code (common after updates). To fix it, run the migration command manually:

cd /opt/frappe/frappe-bench
bench --site erp.yourdomain.com migrate

5. How do I backup my site data? Regular backups are critical. Run this command to snapshot your database and files:

bench --site erp.yourdomain.com backup --with-files

Files are saved in sites/erp.yourdomain.com/private/backups.

6. How do I reset the Administrator password? If you lose access to the admin account, reset it via the terminal:

bench --site erp.yourdomain.com set-admin-password 'NewStrongPassword'

7. My scheduled jobs (emails) are not sending. First, validate that the scheduler is active:

bench --site erp.yourdomain.com enable-scheduler

If issues persist, check that the execution workers are running:

sudo supervisorctl status

8. Where can I find error logs? If the site shows an "Internal Server Error", check the logs in frappe-bench/logs:

# Web request errors
tail -f logs/web.error.log

# Background job errors
tail -f logs/worker.error.log

9. How do I enable Server Scripts? Server scripts allow you to add custom Python logic directly from the desk interface but are disabled by default. To enable them:

cd /opt/frappe/frappe-bench

# Enable globally
bench set-config -g server_script_enabled 1

# Enable for your specific site
bench --site erp.yourdomain.com set-config server_script_enabled 1

# Restart services to apply changes
bench restart

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!

Install ERPNext 16 on Windows (WSL): A Complete Development Guide in 2026

Install ERPNext 16 on Windows (WSL): A Complete Development Guide in 2026

The Ultimate Guide to Building Frappe Apps on Windows with WSL 2, and VS Code

Read More...

Mastering ERPNext 16 Development: The Complete Guide to Building Custom Apps

Mastering ERPNext 16 Development: The Complete Guide to Building Custom Apps

Build, Test, Deploy: A Modern CI/CD Pipeline for ERPNext Developers

Read More...

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

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.