[Guide] How to install ERPNext v14 on Linux Ubuntu (step-by-step instructions)

Hello,
I am so sorry, I should have updated the progress here.

I learnt that the error Server has gone away. has something to do with max_allowed_packet in /etc/mysql/my.cnf.

Adding this line below [mysqld] solved that problem.

max_allowed_packet = 1024M

Apparently this error had occurred because my sql backup file was too huge.

Even though this problem was solved, ERPNext did not run as expected as there appeared other problems. I ultimately had to install fresh v14 again on ubuntu 22.04, then rollback to v13 (with switch to branch), then restore that backup in v13 and then upgrade it to v14. Now ERPNext is running fine.

I had to go through all this fuss because a simple upgrade of OS to 22.04, upgrading of python/pip and then v13 to v14 produced alot of errors which I could not resolve. I wish someone had made a detailed guide like this one to upgrade v13 to v14.

Thank you for this wonderful step by step guide, though.

@anupd great to know that you managed to resolve the issue. If possible to share the exact steps you followed to restore the v13 database into v14 post the OS update to 22.04. It’ll be helpful to others who might face similar issues. Thanks!

Sure. I will try to list out the steps soon. However, since I didnot record the steps back then, I can now only share the steps and not the exact commands.

Anyone also got this error? My upgrade is stuck on it…

@pronext you can safely ignore this error message and continue with the installation process.

I thought that too, but is takes a little more commands than that.
I created a update script which was working for me on to update v13 to v14 and I shared it here in the community: V13 to v14 Upgrade Script - want that for every major version

Thank you @shashank_shirke for easiest & simplest guide to install ERPnext V14, as for the windows user this one is the best guide.

I have done installation on ubuntu server 22.04 and debian 11 bullseye netinstall with minimal lxde environment on virtualbox & comparing both like the debian version more just because of the low memory footprint and better performance. For debian version I have install the python 3.10 and related packages, mariadb and default-libmysqlclient-dev package with aptitude (to solve the dependency error) from bookworm and remaining from stable repo.

Now to update erpnext version which command to use bench update or bench update --reset?

@NURAV glad to know that you found this guide helpful. Regarding updating, first try using bench update. Only if there are any local changes to the core files you’ll need to use the --reset flag which will overwrite all local changes so use it with caution.

You can force install an app with bench install-app hrms --force

Just wanted to say thanks very much for this! I tried DigitalOcean’s 2020 tutorial twice but kept having issues with all their complex extra command steps… Was very straight forward and easy to follow if you’ve setup a web server before.

how to get education app?

Hi @GhadaEbrahim to get any app you just need to run the bench get-app and then then bench install-app commands. For eg. to get education app you can run the following:

bench get-app education
bench --site yoursitename.com install-app education

For more details check the official repo here: GitHub - frappe/education

After initiating frappe I am having some waring “WARN: restart failed: Couldn’t find supervisorctl in PATH”

Any one know what to do?

I have tried to install with this waring I was successfully install erpnext.

You must not complete the setup wizard before installing erpnext app.

Once you perform setup wizard, erpnext app cannot be installed.

I get the same error too with hrms app.

However I also get an error when installing payments app:

An error occurred while installing payments: 'CustomField' object has no attribute 'is_virtual'

My problem was to UPGRADE a site, instead of installing a new site. I do this then it works:

bench --verbose --site SITE_NAME migrate

Then you can:

bench --verbose --site SITE_NAME install-app hrms

Hope this helps

All this was working fine until 90 days were over. The certificate seemed to renew it self but after a huge trouble I learnt that we had to run this line after 90 days to keep the web application running on https.

sudo certbot --nginx

Is there any way to automate this ?

Here is how I sorted the error

pymysql.err.OperationalError: (1698, “Access denied for user ‘root’@‘localhost’”)

while creating the site by running command

bench new-site site1.local

I also faced following error. Following is my full terminal message trail.

frappe@erpnext14-ubuntu22041:~/frappe-bench$ bench new-site site1.local
MySQL root password: 
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 109, in <module>
    main()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 18, in main
    click.Group(commands=commands)(prog_name="bench")
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 74, in new_site
    _new_site(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/installer.py", line 80, in _new_site
    install_db(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/installer.py", line 156, in install_db
    setup_database(force, source_sql, verbose, no_mariadb_socket)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/__init__.py", line 20, in setup_database
    return frappe.database.mariadb.setup_db.setup_database(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/setup_db.py", line 41, in setup_database
    if force or (db_name not in dbman.get_database_list()):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/db_manager.py", line 49, in get_database_list
    return self.db.sql("SHOW DATABASES", pluck=True)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 199, in sql
    self.connect()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 113, in connect
    self._conn = self.get_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 98, in get_connection
    conn = self._get_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 104, in _get_connection
    return self.create_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 107, in create_connection
    return pymysql.connect(**self.get_connection_settings())
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 353, in __init__
    self.connect()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 633, in connect
    self._request_authentication()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 907, in _request_authentication
    auth_packet = self._read_packet()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 725, in _read_packet
    packet.raise_for_error()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.OperationalError: (1698, "Access denied for user 'root'@'localhost'")

When I tried to uninstall the site with command bench drop-site site1.local , I again got the error as below:

Taking backup of site1.local
================================================================================
Error: The operation has stopped because backup of site1.local's database failed.
Reason: (1045, "Access denied for user '_c6a99b789ee42f7a'@'localhost' (using password: YES)")

Fix the issue and try again.
Hint: Use 'bench drop-site site1.local --force' to force the removal of site1.local
frappe@erpnext14-ubuntu22041:~/frappe-bench$ bench drop-site site1.local --force
Taking backup of site1.local
Dropping site database and user
MySQL root password: 
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 109, in <module>
    main()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 18, in main
    click.Group(commands=commands)(prog_name="bench")
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 832, in drop_site
    _drop_site(site, db_root_username, db_root_password, archived_sites_path, force, no_backup)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/site.py", line 870, in _drop_site
    drop_user_and_database(frappe.conf.db_name, db_root_username, db_root_password)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/__init__.py", line 37, in drop_user_and_database
    return frappe.database.mariadb.setup_db.drop_user_and_database(
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/setup_db.py", line 86, in drop_user_and_database
    dbman.drop_database(db_name)
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/db_manager.py", line 30, in drop_database
    self.db.sql_ddl(f"DROP DATABASE IF EXISTS `{target}`")
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 363, in sql_ddl
    self.commit()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 999, in commit
    self.sql("commit")
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 199, in sql
    self.connect()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/database.py", line 113, in connect
    self._conn = self.get_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 98, in get_connection
    conn = self._get_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 104, in _get_connection
    return self.create_connection()
  File "/home/frappe/frappe-bench/apps/frappe/frappe/database/mariadb/database.py", line 107, in create_connection
    return pymysql.connect(**self.get_connection_settings())
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 353, in __init__
    self.connect()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 633, in connect
    self._request_authentication()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 907, in _request_authentication
    auth_packet = self._read_packet()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/connections.py", line 725, in _read_packet
    packet.raise_for_error()
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "/home/frappe/frappe-bench/env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.OperationalError: (1698, "Access denied for user 'root'@'localhost'")

Even using –force didn’t help. Then I referred the official documentation and used following command to create site and it successfully created site. But note that before running command, I manually deleted the site folder /home/frappe/frappe-bench/sites/site1.local

bench new-site site1.local --db-name erpnext --db-password password --db-root-username frappe --db-root-password password --admin-password password

I actually used the userid and password that i created while installing mariadb. my mariadb server admin user was frappe and password is password. This is apart from the root user that gets automatically created while installing mariadb.

And following is the message trail in my terminal:

frappe@erpnext14-ubuntu22041:~/frappe-bench$ bench new-site site1.local --db-name erpnext --db-password password --db-root-username frappe --db-root-password password --admin-password password

Installing frappe...
Updating DocTypes for frappe        : [====================] 100%
Updating country info               : [====================] 100%
Updating Dashboard for frappe
site1.local: SystemSettings.enable_scheduler is UNSET
*** Scheduler is disabled ***
frappe@erpnext14-ubuntu22041:~/frappe-bench$

It worked just like that! :slightly_smiling_face:

For those who are interested in creating an explicit user for frappe in mariadb, here is what I did.
When the command sudo mysql_secure_installation is run, terminal shows some options to configure, here is what i chose to do:

-> Configuring MariaDB
	Commands:
	
		> sudo mysql_secure_installation
	Result:
		=> Enter current password for root (enter for none): Since you have not set one up yet, press ENTER to indicate “none”. I pressed **Enter**
		=> Switch to unix_socket authentication [Y/n]: n (Since you already have a protected root account, you can skip this step. Type n and then press ENTER.)
		=> Change the root password? [Y/n]:n (Type n and then press ENTER.)
		=> Remove anonymous users? [Y/n]:y
		=> Disallow root login remotely? [Y/n]: y
		=> Remove test database and access to it? [Y/n]: y
		=> Reload privilege tables now? [Y/n]: y
	Message:
		All done!  If you've completed all of the above steps, your MariaDB installation should now be secure.
		Thanks for using MariaDB!

Then, I did as follows:

-> Creating an Administrative User that Employs Password Authentication
	Commands:
	
		> sudo mariadb
		> GRANT ALL ON *.* TO 'frappe'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;
		> FLUSH PRIVILEGES;
		> exit

I am getting same error with some additional one also.

frappe@erpnext14-ubuntu22041:~/frappe-bench$ bench get-app hrms
Getting hrms
$ git clone https://github.com/frappe/hrms.git  --depth 1 --origin upstream
Cloning into 'hrms'...
remote: Enumerating objects: 1160, done.
remote: Counting objects: 100% (1160/1160), done.
remote: Compressing objects: 100% (948/948), done.
remote: Total 1160 (delta 284), reused 587 (delta 148), pack-reused 0
Receiving objects: 100% (1160/1160), 1.64 MiB | 1.65 MiB/s, done.
Resolving deltas: 100% (284/284), done.
Ignoring dependencies of hrms. To install dependencies use --resolve-deps
Installing hrms
$ /home/frappe/frappe-bench/env/bin/python -m pip install --quiet --upgrade -e /home/frappe/frappe-bench/apps/hrms 
$ bench build --app hrms
Linking /home/frappe/frappe-bench/apps/frappe/node_modules to ./assets/frappe/node_modules                                                                      Linking /home/frappe/frappe-bench/apps/erpnext/erpnext/public to ./assets/erpnext                                                                               Linking /home/frappe/frappe-bench/apps/erpnext/node_modules to ./assets/erpnext/node_modules                                                                    Linking /home/frappe/frappe-bench/apps/payments/payments/public to ./assets/payments                                                                            ✔ Application Assets Linked                                            


yarn run v1.22.19
$ node esbuild --production --apps hrms --run-build-command
clean: postcss.plugin was deprecated. Migration guide:
https://evilmartians.com/chronicles/postcss-8-plugin-migration
clean: postcss.plugin was deprecated. Migration guide:
https://evilmartians.com/chronicles/postcss-8-plugin-migration
File                                                        Size

hrms/dist/js/
└─ hrms.bundle.B55RAXO2.js                                  0.90 Kb

 DONE  Total Build Time: 1.434s

 WARN  Cannot connect to redis_cache to update assets_json
 WARN  Cannot connect to redis_cache to update assets_json
 WARN  Cannot connect to redis_cache to update assets_json
Done in 5.94s.
$ supervisorctl restart frappe:
frappe: ERROR (no such group)
frappe: ERROR (no such group)
WARN: restarting supervisor failed. Use `bench restart` to retry.

Here is my supervisord.conf file entry

[unix_http_server]
file=/var/run/supervisor.sock   ; (the path to the socket file)
chmod=0700                       ; sockef file mode (default 0700)
;chmod=0700                     ;Added by LLC on 01/02/23 to solve permission problem>
chown=frappe:frappe             

Apart from that warning Cannot connect to redis_cache to update assets_json, I am also getting the permission error

> supervisorctl restart frappe
error: <class 'PermissionError'>, [Errno 13] Permission denied: file: /usr/lib/python3/dist-packages/supervisor/xmlrpc.py line: 560

This problem actually sorted as follows:
Ref URL: URL

Change the entry in supervisor.conf file to below:
file=/var/run/supervisor.sock
;chmod=0700
chmod=0770
chown=frappe:frappe

Now Run commands from frappe-bench folder:

> bench setup supervisor
> sudo ln -s `pwd`/config/supervisor.conf /etc/supervisor/conf.d/frappe-bench.conf

then restart supervisord

> sudo service supervisor restart
> sudo bench restart

Now bench will restart successfully without any issue.
Output:

$ supervisorctl restart frappe-bench-workers: frappe-bench-web:
		frappe-bench-workers:frappe-bench-frappe-schedule: stopped
		frappe-bench-workers:frappe-bench-frappe-long-worker-0: stopped
		frappe-bench-workers:frappe-bench-frappe-default-worker-0: stopped
		frappe-bench-workers:frappe-bench-frappe-short-worker-0: stopped
		frappe-bench-web:frappe-bench-node-socketio: stopped
		frappe-bench-web:frappe-bench-frappe-web: stopped
		frappe-bench-workers:frappe-bench-frappe-schedule: started
		frappe-bench-workers:frappe-bench-frappe-default-worker-0: started
		frappe-bench-workers:frappe-bench-frappe-short-worker-0: started
		frappe-bench-workers:frappe-bench-frappe-long-worker-0: started
		frappe-bench-web:frappe-bench-frappe-web: started
		frappe-bench-web:frappe-bench-node-socketio: started
		frappe@erpnext14-ubuntu22041:~/frappe-bench$

I was left to install ecommerce integrations app , so I ran command as mentioned in this guide like mentioned below and it ran successfully.

bench get-app ecommerce_integrations --branch main

Here is the output in my terminal:

frappe@erpnext14-ubuntu22041:~/frappe-bench$ bench get-app ecommerce_integrations --branch main
Getting ecommerce_integrations
$ git clone https://github.com/frappe/ecommerce_integrations.git --branch main --depth 1 --origin upstream
Cloning into 'ecommerce_integrations'...
remote: Enumerating objects: 232, done.
remote: Counting objects: 100% (232/232), done.
remote: Compressing objects: 100% (191/191), done.
remote: Total 232 (delta 40), reused 137 (delta 33), pack-reused 0
Receiving objects: 100% (232/232), 241.51 KiB | 977.00 KiB/s, done.
Resolving deltas: 100% (40/40), done.
Ignoring dependencies of ecommerce_integrations. To install dependencies use --resolve-deps
Installing ecommerce_integrations
$ /home/frappe/frappe-bench/env/bin/python -m pip install --quiet --upgrade -e /home/frappe/frappe-bench/apps/ecommerce_integrations 
$ bench build --app ecommerce_integrations
✔ Application Assets Linked                                                                                                                                         


yarn run v1.22.19
$ node esbuild --production --apps ecommerce_integrations --run-build-command
File                                                        Size

 DONE  Total Build Time: 822.729ms

clean: postcss.plugin was deprecated. Migration guide:
https://evilmartians.com/chronicles/postcss-8-plugin-migration
Done in 1.52s.
$ supervisorctl restart frappe-bench-workers: frappe-bench-web:
frappe-bench-workers:frappe-bench-frappe-schedule: stopped
frappe-bench-workers:frappe-bench-frappe-long-worker-0: stopped
frappe-bench-workers:frappe-bench-frappe-default-worker-0: stopped
frappe-bench-workers:frappe-bench-frappe-short-worker-0: stopped
frappe-bench-web:frappe-bench-node-socketio: stopped
frappe-bench-web:frappe-bench-frappe-web: stopped
frappe-bench-workers:frappe-bench-frappe-schedule: started
frappe-bench-workers:frappe-bench-frappe-default-worker-0: started
frappe-bench-workers:frappe-bench-frappe-short-worker-0: started
frappe-bench-workers:frappe-bench-frappe-long-worker-0: started
frappe-bench-web:frappe-bench-frappe-web: started
frappe-bench-web:frappe-bench-node-socketio: started
frappe@erpnext14-ubuntu22041:~/frappe-bench$

Surprisingly, the warning message WARN Cannot connect to redis_cache to update assets_json also did not appear