ERPNext 16 Manual Installation Guide on Ubuntu 24.04
This knowledgebase shows how to install ERPNext 16 manually on Ubuntu 24.04 using the same working flow you adapted in your automation. It also shows how to attach one domain or multiple domains after installation.
uv, Node 24 with nvm, MariaDB, Redis, Supervisor, Nginx, and HTTPS with Certbot.1. Example values used in this guide
| Item | Example |
|---|---|
| Frappe user | frappe |
| Main site/domain | erp.example.com |
| Additional domains | erp2.example.com, erp.customer.co.za |
| Admin password | StrongAdminPasswordHere |
| MariaDB root password | StrongDbRootPasswordHere |
| ERPNext branch | version-16 |
| Let's Encrypt email | admin@example.com |
2. Prepare the server
2.1 Update packages
sudo apt update sudo apt -y upgrade
2.2 Install base packages
sudo apt install -y \ git curl dirmngr apt-transport-https software-properties-common \ mariadb-server mariadb-client redis-server supervisor nginx \ python3-dev python3-pip python3-setuptools python3-venv \ pkg-config xvfb fontconfig libmysqlclient-dev \ snapd
fontconfig, not libfontconfig, on Ubuntu 24.04.2.3 Start and enable core services
sudo systemctl enable --now mariadb sudo systemctl enable --now redis-server sudo systemctl enable --now nginx sudo systemctl enable --now supervisor
3. Secure and tune MariaDB
3.1 Set root password and remove defaults
sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('StrongDbRootPasswordHere');
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.user WHERE User='root' AND Host='%';
FLUSH PRIVILEGES;
EXIT;
3.2 Save root credentials locally
sudo bash -c 'cat > /root/.my.cnf <
3.3 Enable utf8mb4
sudo bash -c 'cat >> /etc/mysql/my.cnf < /etc/mysql/conf.d/frappe.cnf <
4. Create the Frappe user
sudo useradd -m -s /bin/bash frappe sudo usermod -aG sudo frappe sudo passwd frappe
4.1 Allow Supervisor control without password
echo 'frappe ALL=(ALL) NOPASSWD: /usr/bin/supervisorctl' | sudo tee /etc/sudoers.d/frappe-supervisor sudo chmod 440 /etc/sudoers.d/frappe-supervisor sudo visudo -cf /etc/sudoers.d/frappe-supervisor
5. Install Node 24 and Yarn as the frappe user
sudo -iu frappe curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm install 24 nvm alias default 24 nvm use 24 npm install -g yarn command -v node command -v npm command -v yarn node -v npm -v yarn -v
6. Install Certbot from snap
sudo apt remove -y certbot python3-certbot-nginx python3-certbot-apache || true sudo snap install --classic certbot sudo ln -sf /snap/bin/certbot /usr/bin/certbot
7. Install uv and Bench
sudo -iu frappe curl -LsSf https://astral.sh/uv/install.sh | sh export PATH="$HOME/.local/bin:$PATH" uv python install 3.14 --default uv tool install frappe-bench command -v uv command -v bench python3 --version bench --version
8. Initialize Bench
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~ bench init --skip-redis-config-generation --frappe-branch version-16 frappe-bench
9. Install wkhtmltopdf
cd /tmp wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb sudo apt install -y ./wkhtmltox_0.12.6.1-2.jammy_amd64.deb
10. Create the site
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench bench new-site erp.example.com --admin-password StrongAdminPasswordHere --db-root-password StrongDbRootPasswordHere
11. Point Bench to system Redis
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench bench set-config -g redis_queue "redis://127.0.0.1:6379/1" bench set-config -g redis_cache "redis://127.0.0.1:6379/2" bench set-config -g redis_socketio "redis://127.0.0.1:6379/3"
12. Set up production services
export PATH="/home/frappe/.local/bin:$PATH" cd /home/frappe/frappe-bench yes | sudo env "PATH=$PATH" bench setup production frappe
12.1 Link Supervisor config and reload
sudo ln -sf /home/frappe/frappe-bench/config/supervisor.conf /etc/supervisor/conf.d/frappe-bench.conf sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl restart all sudo supervisorctl status
12.2 Restart Bench
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench bench restart
13. Get and install ERPNext apps
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench bench get-app --branch version-16 erpnext bench get-app --branch version-16 hrms bench get-app --branch version-16 payments bench get-app --branch version-16 education bench --site erp.example.com install-app erpnext bench --site erp.example.com install-app hrms bench --site erp.example.com install-app payments bench --site erp.example.com install-app education
lending app was excluded because its repository branching did not match the ERPNext 16 branch flow you were using.14. Enable scheduler and disable maintenance mode
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench bench --site erp.example.com enable-scheduler bench --site erp.example.com set-maintenance-mode off
15. Add one or multiple domains
15.1 Enable DNS multitenancy
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench bench config dns_multitenant on
15.2 Add the primary domain
bench setup add-domain erp.example.com --site erp.example.com
15.3 Add extra domains to the same site
You can point multiple domains or aliases to the same site by repeating bench setup add-domain.
bench setup add-domain www.erp.example.com --site erp.example.com bench setup add-domain erp2.example.com --site erp.example.com bench setup add-domain erp.customer.co.za --site erp.example.com
16. Rebuild nginx for the domain(s)
sudo -iu frappe export HOME=/home/frappe export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm use 24 export PATH="$HOME/.local/bin:$PATH" export PATH="$(npm bin -g):$PATH" cd ~/frappe-bench yes | bench setup nginx
17. Fix nginx log format for Bench-generated config
Bench-generated nginx config may reference log format main. Ensure nginx defines it globally.
sudo nano /etc/nginx/nginx.conf
Add this inside the http { ... } block:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
18. Validate nginx and install HTTPS with Certbot
sudo nginx -t sudo certbot --nginx -d erp.example.com --non-interactive --agree-tos -m admin@example.com
18.1 If you have multiple domains
You can request a certificate for multiple names in one command:
sudo certbot --nginx \ -d erp.example.com \ -d www.erp.example.com \ -d erp2.example.com \ -d erp.customer.co.za \ --non-interactive --agree-tos -m admin@example.com
19. Confirm service health
sudo nginx -t sudo systemctl status nginx --no-pager sudo systemctl status supervisor --no-pager sudo systemctl status redis-server --no-pager sudo systemctl status mariadb --no-pager sudo supervisorctl status
20. Useful Bench checks
sudo -iu frappe cd ~/frappe-bench bench --site erp.example.com list-apps bench doctor bench version
21. Final access
After successful completion, your ERPNext instance should be available at:
https://erp.example.com
Default login user:
Administrator
22. Troubleshooting notes
- If
bench initfails on missingyarn, make sure the shell loadsnvm, runsnvm use 24, and has global npm binaries inPATH. - If
bench get-appfails on rerun because a directory already exists, skip that app or remove the existing app directory first. - If Certbot fails with nginx plugin errors, run
sudo nginx -tfirst and fix nginx before retrying Certbot. - If nginx reports
unknown log format "main", add the globallog_format mainblock shown above. - If a site was created with an IP address instead of a domain, check what value was actually passed into
site_name.