Installing ERPNext on Ubuntu 16.04: What the Easy Install Script Does Not Tell You
ERPNext ships an install script that claims to take a bare Ubuntu server and hand you a working ERP. On a clean machine with enough memory, it genuinely does, and that is impressive for software this size. On the machines people actually buy, it stops somewhere in the middle, prints a Python traceback, and leaves a half-built system that is neither installed nor clean.
I have now done this on enough servers to have opinions. The first is that the script is not the problem, the prerequisites are. Almost every failure I see comes from one of four things: MariaDB configured for the last decade rather than for Frappe, an install run as the wrong user, a server with too little memory to build the assets, and a PDF engine that produces garbage. Fix those four and the script is boring, which is what you want.
Before running anything, give the machine at least 2GB of RAM, and put this in /etc/mysql/my.cnf, then restart MariaDB:
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
innodb-file-format = barracuda
innodb-file-per-table = 1
innodb-large-prefix = 1
[mysql]
default-character-set = utf8mb4
Then run the install as a normal user with sudo rights, never as root:
wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
sudo python install.py --production --user frappe
Failure 1: the database rejects the schema
This is the one that wastes the most time, because it does not appear during installation. It appears later, when a site is created or an app is installed, and it looks like this:
_mysql_exceptions.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')
Here is the mechanism, because knowing it saves you from every future variation. Frappe stores text as utf8mb4, which is real four byte Unicode and the only way an emoji or some non Latin scripts survive a round trip. In utf8mb4 a single character can take four bytes, so a 255 character indexed column needs 1020 bytes. InnoDB's older Antelope file format caps an index prefix at 767 bytes. The schema is therefore impossible until you switch InnoDB to the Barracuda format with a large index prefix, which is what the three innodb- lines above do.
Set them before you create any site. Changing them afterwards does not retroactively convert tables that were already created, so you end up converting them one by one.
The other database failure is simpler and reads worse than it is:
InternalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
The installer asks for the MariaDB root password and hands it to Ansible, which uses it to create the database and the user for your site. If MariaDB was already on the machine with a different root password, or with no root password at all, this is what you get. Confirm the password works by hand first, with mysql -u root -p -e "SELECT 1", and only then run the script.
Failure 2: installing as root
The script takes a --user argument for a reason. Bench refuses to operate as root, and this is a deliberate design decision, not an oversight. Frappe runs your Python code, your custom app's code, and any print format anyone writes in the UI. Every one of those becomes a root process if the stack runs as root.
Create the user first if you want control over it:
sudo adduser frappe
sudo usermod -aG sudo frappe
Then run the installer with --user frappe. Everything lands in /home/frappe/frappe-bench and is owned by that user. When you later find files in there owned by root, which happens the first time somebody runs a bench command with sudo out of habit, fix it immediately:
sudo chown -R frappe:frappe /home/frappe/frappe-bench
Mixed ownership inside a bench produces failures that look like anything except a permissions problem, usually a Python module that cannot be imported by the worker but imports fine when you test it.
Failure 3: the build gets killed
On a 1GB VPS, which is what most people buy first, the install runs for twenty minutes and then ends without an obvious error, or with a single unhelpful word:
Killed
Confirm what happened before you theorise:
dmesg | tail -n 20
Out of memory: Kill process 20475 (node) score 812 or sacrifice child
Killed process 20475 (node) total-vm:1483092kB, anon-rss:611044kB
The kernel ran out of memory and killed the asset build. Nothing is corrupt, there is simply not enough RAM to compile the JavaScript bundles. Add swap so the build can finish:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Swap gets you through the installation. It does not make 1GB a production server. A single company with a handful of users needs the web process, the background workers, the scheduler, Redis and MariaDB all resident at once, and 4GB is where that stops being uncomfortable. This is a place where the cheapest plan costs more than it saves.
Failure 4: the invoices look wrong
Everything works, and then the first PDF comes out with the layout collapsed and half the styling missing. This is not ERPNext. It is wkhtmltopdf: the version in the Ubuntu repository is built against unpatched Qt, which cannot render much of the CSS that print formats rely on. Frappe expects the build with patched Qt, and the difference is total.
Remove the distribution package and install the patched build for your architecture from the wkhtmltopdf project's releases, then confirm what you have:
wkhtmltopdf --version
The output must contain the words with patched qt. If it does not, no amount of editing the print format will fix your invoices.
Finishing a half-installed bench
If the script died partway, you usually do not need to start again. Log in as the bench user and carry on by hand:
su - frappe
cd frappe-bench
bench new-site erp.example.com
bench get-app erpnext https://github.com/frappe/erpnext
bench --site erp.example.com install-app erpnext
Then turn the development bench into a real one:
sudo bench setup production frappe
sudo supervisorctl status
Expected output is one RUNNING line per process from the diagram above. Anything in FATAL has a log in /home/frappe/frappe-bench/logs/ named after the process, and that log names the actual problem.
Verification
curl -I http://localhost/api/method/ping
sudo supervisorctl status | grep -c RUNNING
sudo nginx -t
Then reboot the server and check again. Supervisor and Nginx are both started by systemd on 16.04, so if you have been fighting an init system this week, the units you need to be enabled are supervisor and nginx. I wrote about converting old jobs to units in the piece on Upstart and systemd, and the same check applies here: a stack that only comes up when you type the command is not installed, it is balanced.
What people get wrong
Running bench commands with sudo. It appears to fix a permissions error, and it creates root owned files inside the bench that break the next command. Fix ownership instead.
Editing the generated Nginx and supervisor configuration by hand. Bench regenerates both files, so your edits vanish on the next bench setup nginx. Put custom Nginx configuration in a separate file that is included, and keep bench's output untouched.
Skipping the MariaDB settings because the install worked without them. It will work until somebody types a character outside Latin-1, or until a patch adds an index to a text column. Set them at the start.
Exposing the site on plain HTTP because "it is only internal". Staff log in to this from phones on mobile data. A certificate is free now; issue one and automate the renewal before you hand the system over.
When it is still broken
- The site loads but assets 404. Run
bench buildand check thatsites/assetsexists and is readable by the Nginx user. - Background jobs never run.
bench doctorreports the state of the queues, and the scheduler must be enabled for that site withbench --site <site> enable-scheduler. - The web process starts and dies in a loop. Read
logs/web.error.log, not the browser. A missing Python dependency in a custom app is the usual answer. - Everything is slow after go live. Look at MariaDB before you blame Frappe. Default InnoDB buffer pool settings assume a much smaller database than an ERP produces.
Frequently asked questions
- Can I install ERPNext on a server with 1GB of RAM?
- You can install it, but you should not run it in production. The install itself often fails while building assets because node runs out of memory. Give the machine at least 2GB, or add swap for the install and treat 4GB as the realistic production floor for a small company.
- Should I install ERPNext as root?
- No. The install script creates and uses a normal user with sudo rights, and bench refuses to run as root on purpose. Running the stack as root means a bug in a web request runs as root, and it also breaks file ownership for the supervisor and Nginx configuration bench generates.
- What is the difference between a development bench and a production bench?
- A development bench is started by hand with bench start, which runs the web server, the workers and the scheduler in the foreground. A production bench is generated by bench setup production, which writes supervisor and Nginx configuration so the same processes are managed by the system and survive a reboot.
- Why do PDF prints come out with broken layout?
- Because wkhtmltopdf was installed from the distribution repository, which builds against unpatched Qt and ignores much of the CSS. Install the version with patched Qt that Frappe expects, then re-run the print. This single mismatch is behind most complaints about ugly ERPNext invoices.