Host Multiple Installations In 1 Server

Hi, I am interested in hosting multiple ERPNext installations on 1 server, obviously to save on hosting costs.

I came across this guide and would like know if this would enable me to achieve my desired goal:

It is possible to install multiple copies of frappe-bench.

Within each bench you can create multiple sites.

I have not yet tried multiple sites in multiple benches.

I have found that when you create a new bench and add a new site, the access ports increment automatically. So, your first site in your first bench communicates through 8000, 9000 & 11000. A site created in a subsequent bench will communicate through 8001, 9001 & 11001, etc.

The following would create benches for development, staging and production.

bench init --frappe-branch version-12 --python /usr/bin/python3 frappe-bench-DEV;
bench init --frappe-branch version-12 --python /usr/bin/python3 frappe-bench-STG;
bench init --frappe-branch version-12 --python /usr/bin/python3 frappe-bench-PRD;

You would want to set up supervisorctl in frappe-bench-STG and frappe-bench-PRD. but not in frappe-bench-DEV.

When you place multiple sites in a single bench changes can affect all sites at once, so you definitely want to keep staging and production in distinct benches.

For DevOps “purity”, scripts to install, configure and update your staging and production areas should be perfectly identical, distinguished only by site name and access port numbers in a configuration file.

Hope this helps.

Thank you Martin…

“When you place multiple sites in a single bench changes can affect all sites at once, so you definitely want to keep staging and production in distinct benches” - Do you mean upgrades and updates only?

Don’t you have a guide on how I can implement your suggestion? - I am new to Frappe and to Linux…

Also, will these benches be able to point to independent domain names and thus operate independent of each other?

“When you place multiple sites in a single bench changes can affect all sites at once, so you definitely want to keep staging and production in distinct benches” - Do you mean upgrades and updates only?

To be 100% honest, I do not yet know, I am researching this my self right now.

Don’t you have a guide on how I can implement your suggestion? - I am new to Frappe and to Linux…

No. I have had to pick over bits and pieces of instructions and examples here in the forum and on the many 3rd party installation guides. Even with a lot experience already it has been difficult. A single small mistake can go unnoticed, then cause inexplicable failures later.

However if you have a successful installation already, you just need to start again from where you created your first bench. Create a second bench and proceed as before.

Also, will these benches be able to point to independent domain names and thus operate independent of each other?

When setting up NGinx configuration you need to be aware of directory names and config unique names. This is a template I use to generate my NGinx config files:

upstream frappe-bench-${NICK}-frappe {
  server 127.0.0.1:${BENCH_PORT} fail_timeout=0;
}

upstream frappe-bench-${NICK}-socketio-server {
  server 127.0.0.1:${SCKTIO_PORT} fail_timeout=0;
}

server {
  
  listen 443 ssl;

  server_name ${VHOST};

  ssl_certificate /etc/letsencrypt/live/${VHOST}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/${VHOST}/privkey.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/dhparams_4096.pem;

  root /home/erpdev/frappe-bench-${NICK}/sites;

  add_header X-Frame-Options "SAMEORIGIN";
  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";

  location /assets {
    try_files \$uri =404;
  }

  location ~ ^/protected/(.*) {
    internal;
    try_files /\$host/\$1 =404;
  }

  location /socket.io {
    proxy_http_version 1.1;
    proxy_set_header Upgrade \$http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Frappe-Site-Name \$host;
    proxy_set_header Origin \$scheme://\$http_host;
    proxy_set_header Host \$host;

    proxy_pass http://frappe-bench-${NICK}-socketio-server;
  }

  location / {

      rewrite ^(.+)/\$ \$1 permanent;
      rewrite ^(.+)/index\.html\$ \$1 permanent;
      rewrite ^(.+)\.html\$ \$1 permanent;

    location ~ ^/files/.*.(htm|html|svg|xml) {
      add_header Content-disposition "attachment";
      try_files /\$host/public/\$uri @webserver;
    }

    try_files /\$host/public/\$uri @webserver;
  }

  location @webserver {
    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto \$scheme;
    proxy_set_header X-Frappe-Site-Name \$host;
    proxy_set_header Host \$host;
    proxy_set_header X-Use-X-Accel-Redirect True;
    proxy_read_timeout 120;
    proxy_redirect off;

    proxy_pass  http://frappe-bench-${NICK}-frappe;
  }

  # error pages
  error_page 502 /502.html;
  location /502.html {
    root /usr/local/lib/python3.8/dist-packages/bench/config/templates;
    internal;
  }

  # optimizations
  sendfile on;
  keepalive_timeout 15;
  client_max_body_size 50m;
  client_body_buffer_size 16K;
  client_header_buffer_size 1k;

  # enable gzip compresion
  # based on https://mattstauffer.co/blog/enabling-gzip-on-nginx-servers-including-laravel-forge
  gzip on;
  gzip_http_version 1.1;
  gzip_comp_level 5;
  gzip_min_length 256;
  gzip_proxied any;
  gzip_vary on;
  gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/rss+xml
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/font-woff
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/svg+xml
    image/x-icon
    text/css
    text/plain
    text/x-component
    ;
    # text/html is always compressed by HttpGzipModule
}

You will find the following variables: NICK, BENCH_PORT, SCKTIO_PORT, VHOST.

Site PRD:

  • NICK = PRD
  • BENCH_PORT = 8000
  • SCKTIO_PORT = 9000
  • VHOST = prd.erpnext.host

Site PRD:

  • NICK = STG
  • BENCH_PORT = 8001
  • SCKTIO_PORT = 9001
  • VHOST = stg.erpnext.host

Look for ‘upstream’ and ‘proxy_pass’. Proxy pass basically tell NGinx, “No static files to return from here. Go ask Mr. & Mrs Upstream if they have anything”. The upstream names have to be unique across all your sites.

Look for ‘root’. That tells NGinx, “Hey! Here are the static files you wanted.” Likewise the NICKname in there ensures the two sites deliver their own static files, not anyone else’s.

1 Like

This looks so complicated

Yes.

Self-hosting is expensive in time, in money or both. It’s the reason most users see $50/user/mth as a reasonable cost for ERPNext Cloud.

You really need to be over 100 users, or have specialized requirements, before self-hosting pays off.

Is there a reason why you have to choose self-hosting? If it seems less expensive, I promise you, it isn’t.

I am looking at starting a business by installing the script for other companies. Hosting on a single server would save costs on my side.

Also, $50 is expensive when converted to ZAR

The you will need either to hire a technician or expect to spend many months yourself learning and developing the tools you will need to properly manage those sites: security, backups, integrations, data import & export, upgrades, special customizations, etc, etc.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.