[GUIDE] How to Run Development Mode and Production Mode Benches On A Single Server

So I’m running a few benches on my dev server. But I need some of my sites to run in production-mode so that I don’t need to start bench and migration complications when shifting the production environment. Maybe not the best setup stability-wise but its fast and cost-effective.

Here’s my setup:

  1. bench-production - runs on startup but requires bench build and bench restart when you change code
  2. bench-develop - requires bench start but detects code changes, shows a live terminal as your apps run

Problem

The main issue is that once you activate certbot on the production bench with multitenancy, the develop bench is very difficult to access.

  1. You get https problems, unless certbot is setup
  2. Using http://IP:PORT gives 404 problems

Solution

Create your own nginx config file in /etc/nginx/conf.d/

  1. Activate multitenancy
bench config dns_multitenant on
bench setup nginx --yes
  1. Create a new nginx conf for bench-develop in /etc/nginx/conf.d/bench-develop.conf. Be sure to update your Ports here 8004 and 9004 according to your bench, the last digit can be found in your bench ~/bench-develop/sites/common_sites_config.json file

upstream bench-develop-frappe {
	server 127.0.0.1:8004 fail_timeout=0;
}

upstream bench-develop-socketio-server {
	server 127.0.0.1:9004 fail_timeout=0;
}

server {
    listen 80;
    listen [::]:80;
    server_name subdomain.domain.com;

    root /home/frappe/bench-develop/sites;

    proxy_buffer_size 128k;
	proxy_buffers 4 256k;
	proxy_busy_buffers_size 256k;

    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";
	add_header Referrer-Policy "same-origin, strict-origin-when-cross-origin";

	location /assets {
		try_files $uri =404;
		add_header Cache-Control "max-age=31536000";
	}

	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://bench-develop-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_http_version 1.1;
		proxy_set_header X-Forwarded-For $remote_addr;
		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://bench-develop-frappe;
	}

	# error pages
	error_page 502 /502.html;
	location /502.html {
		root /home/frappe/.local/lib/python3.11/site-packages/bench/config/templates;
		internal;
	}


    access_log  /var/log/nginx/access.log;
	error_log  /var/log/nginx/error.log;

	# 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
}

  1. Get a certificate
sudo service nginx reload
sudo certbot --nginx

A cool thing with this setup is that it will retain bench-develop configs if you run bench setup nginx in another bench like bench-production, and it works!

4 Likes

Thanks @adam26d!

2 Likes