Multitenant production server setup

When you have a multitenant setup after you have installed your first successful deployment follow these steps:

  • define A record on your DNS pointing to the server IP address
  • login to your server and switch to your bench folder
  • if you haven’t done so, set the root-url for your active site using:
    bench set-url-root SITENAME SITEROOTURL
    SITEROOTURL starts with http:// or https:// depending on your configuration. You do not need to spare any port numbers as nginx will take care of the routing of the requests from SITEROOTURL
  • Run the following command for your new site:
    bench new-site --db-name DBNAME --db-type mariadb --admin-password ADMINPASSWORD --install-app erpnext SITENAME
  • Set your new site’s root-url via:
    bench set-url-root SITENAME SITEROOTURL
  • (optional) Setup Lets Encrypt for https:// access:
    sudo bench setup lets-encrypt SITENAME
  • To enable scheduler:
    bench scheduler enable --site SITENAME

Good, useful info. Thank you


I had never heard of using the “bench set-root-url” command. Is it a new addition to the bench commands? It does not show up in the list that I have (from about a year ago).

Doesn’t this command accomplish the same thing? :

bench setup add-domain --site site1.local []

Or is there something different about this new bench set-root-url that I am missing?

Please enlighten me.


My method works, so I don’t bother with other options until I need them. I have never user add-domain functionality. Sorry.

What are you using the add-domain for?

I use this as one of the steps to setting up a multi-tenant installation. The command is used to add the URL to the first site of a multi-tenant site. Then subsequent tenant sites use the following command:

bench new-site []

This creates the new site with the URL without having to do extra steps. Once this command is done, I have to run:

bench –site [sitename] install-app erpnext

to complete the site installation, but no further name work is needed.

Your approach is just new to me. I had never before seen that particular way of doing it. That is why I asked if it did anything different form what I normally do. Once I run my version of the command, I just have to make sure the DNS pointers are already in place and everything works.

Well, there is the need to run “bench setup nginx” after any name changes, but that is just good protocol.


EDIT: Oh yeah, there is one other thing I guess that might be important. I use my version of the commands to setup only production systems. I have no idea what may be needed to setup a multi-tenant developer system. Maybe that is where your commands come into play?


As the topic implies my setup is for production. Please note that they share the same bench.

Looks like you are saving on SSL certificates in the way that you are getting one for the domain only and the hosts make use of it. Haven’t tried though, just guessing.

@bkm, I don’t see this command either. To test, I just now merged Frappe’s master branch of Bench, into my own. To see if perhaps it was new. But there’s no such command set-root-url in the latest version.

Yeah, I though as much. I do not like trying to rely on undocumented commands because they may or may not ever work at some point in the future. Thanks for the confirmation.


Last login: Fri Oct 18 18:23:15 2019 from
frappe@erp:~$ cd bench/
frappe@erp:~/bench$ bench version
erpnext 12.1.6
frappe 12.0.16
frappe@erp:~/bench$ bench --help

Bench manager for Frappe

–help Show this message and exit.

backup backup site
backup-all-sites backup all sites
config change bench configuration
disable-production Disables production environment for the…
download-translations Download latest translations
exclude-app Exclude app from updating
get-app clone an app from the internet and set it up…
include-app Include app from updating
init Create a New Bench Instance.
install Install system dependancies
migrate-env Migrate Virtual Environment to desired Python…
new-app start a new app
prepare-beta-release Prepare major beta release from develop…
release Release app (internal to the Frappe team)
remote-reset-url Reset app remote url to frappe official
remote-set-url Set app remote url
remote-urls Show apps remote url
remove-app completely remove app from bench
renew-lets-encrypt Renew Let’s Encrypt certificate
restart Restart supervisor processes or systemd units
set-default-site Set default site for bench
set-mariadb-host Set MariaDB host for bench
set-nginx-port Set nginx port for site
set-ssl-certificate Set ssl certificate path for site
set-ssl-key Set ssl certificate private key path for site
set-url-root Set url root for site
setup Setup bench
src Prints bench source folder path, which can be…
start Start Frappe development processes
switch-to-branch Switch all apps to specified branch, or…
switch-to-develop Switch frappe and erpnext to develop branch
switch-to-master Switch frappe and erpnext to master branch
update Update bench

Framework commands:

add-system-manager Add a new system manager to a site
add-to-email-queue Add an email to the Email Queue
add-to-hosts Add site to hosts
backup Backup
browse Opens the site on web browser
build Minify + concatenate JS and CSS files, build…
build-message-files Build message files for translation
bulk-rename Rename multiple records via CSV file
clear-cache Clear cache, doctype cache and defaults
clear-website-cache Clear website cache
console Start ipython console for a site
data-import Import documents in bulk from CSV or XLSX…
destroy-all-sessions Clear sessions of all users (logs them out)
disable-scheduler Disable scheduler
doctor Get diagnostic info about background workers
enable-scheduler Enable scheduler
execute Execute a function
export-csv Export data import template with data for…
export-doc Export a single document to csv
export-fixtures Export fixtures
export-json Export doclist as json to the given path, use…
get-untranslated Get untranslated strings for language
import-csv Import CSV using data import
import-doc Import (insert/update) doclist.
import-translations Update translated strings
install-app Install a new app to site, supports multiple…
list-apps List apps in site
make-app Creates a boilerplate app
make-demo Reinstall site and setup demo
mariadb Enter into mariadb console for a given site.
migrate Run patches, sync schema and rebuild…
mysql Deprecated
new-language Create lang-code.csv for given app
new-site Create a new site
postgres Enter into postgres console for a given site.
publish-realtime Publish realtime event from bench
purge-jobs Purge any pending periodic tasks, if event…
rebuild-global-search Setup help table in the current site (called…
reinstall Reinstall site ie.
reload-doc Reload schema for a DocType
reload-doctype Reload schema for a DocType
remove-from-installed-apps Remove app from site’s installed-apps list
request Run a request as an admin
reset-perms Reset permissions for all doctypes
restore Restore site database from an sql file
run-patch Run a particular patch
run-setup-wizard-ui-test Run setup wizard UI test
run-tests Run tests
run-ui-tests Run UI tests
serve Start development web server
set-admin-password Set Administrator password for a site
set-config Insert/Update a value in site_config.json
set-last-active-for-user Set users last active date to current datetime
setup-global-help Deprecated: setup help table in a separate…
setup-help Deprecated: Setup help table in the current…
show-config print configuration file
show-pending-jobs Get diagnostic info about background jobs
trigger-scheduler-event Trigger a scheduler event
uninstall-app Remove app and linked modules from site
update-translations Update translated strings
use Set a default site
version Show the versions of all the installed apps
watch Watch and concatenate JS and CSS files as and…

Nope. I get separate certificates for each tenant.

The first site gets a certificate using the following:

sudo –H bench setup lets-encrypt site1.local --custom-domain [sitename]

(The -H is removed when on Ubuntu 18.04 hosts and ‘sitename’ is a fully qualified domain name)

The tenant sites get their certificates with the following:

sudo –H bench setup lets-encrypt [sitename]

(The -H is removed when on Ubuntu 18.04 hosts and ‘sitename’ is a fully qualified domain name)

Certificate sharing is never a good idea. They do not cost anything, so it doesn’t make sense to try it.

Setting up the way I do it, allows me to easily delete any tenant. Since I am not sure exactly what your “set-root-url” does to the config.json file I would be reluctant to use it myself.

I do see in your post that the “set-root-url” appears in the command list, but I will have to try it on a test site and then do a forensic check to find out exactly what it changes in the system. It may very well be a new and different way of accomplishing the same thing.

Thanks for sharing. I will try this new way of doing it so I can better understand exactly what it does. :grin:


Yes, the title of the post does say that but the post is tagged with the “Development” tag so I was not sure.


Mystery solved. Tufan (initially) mentioned a command “set-root-url”, that does not exist.

The command he’s referring to is called “set-url-root”.

I’m doing Nginx, Let’s Encrypt, and all other production setups outside of Bench. So nothing more for me to add to this discussion. :stuck_out_tongue:

1 Like

That’s true… better to copy from command line…

You mean Deployment?

1 Like

Yup, sure do. I completely misread that and led myself down a wrong path. :stuck_out_tongue_winking_eye:


I’ll have 2 A-Records pointing to the same ip addresse then, like

  • A-Record sub1 ==>
  • A-Record sub2 ==>


yes, that’s how it works

and … the above works like a charm (used with version-12) thx @Tufan_Kaynak2 @brian_pond