Jump to content

Erpnextv15-SSH-setup-241111

From Game in the Brain Wiki

FORCETOC

ERPNext v15 Deployment Guide: Portainer + ZeroTier + Nginx Proxy Manager

This tutorial covers setting up a production-ready ERPNext environment using a local Host Machine for processing power and a Cloud VM for public accessibility, connected securely via ZeroTier.

1. Architectural Overview & Requirements

The "Cloud VM" (Gateway)

Providers: Contabo or Hetzner.

Cost: ~4,000–6,000 PHP/year (Confirmed: €4.50–€6.00/mo).

Purpose: Runs Nginx Proxy Manager (NPM) in Docker. It acts as the public face with a Static IP.

Network: Connected to your ZeroTier network.

The "Host Machine" (ERPNext Engine)

Recommended Hardware: Dell 3070 Micro (i5 8th Gen, 16GB RAM, 256GB SSD).

OS: Ubuntu 24.04 LTS or Debian 12 (Clean install).

Network: Connected to the same ZeroTier network.

2. Host Machine: Remote Access & Preparation

To operate the machine "headless" (without a monitor), you must set up SSH for command-line control and RDP for graphical access.

A. SSH Access (Command Line)

SSH is the primary way to manage your server. From your Windows or Mac laptop, you can connect using a terminal.

Update the system

sudo apt update && sudo apt upgrade -y

Install OpenSSH Server

sudo apt install openssh-server -y

Check if SSH is running

sudo systemctl status ssh

To connect from your main computer: ssh username@your-machine-ip

B. Remote Desktop & Remmina (Graphical UI)

If you prefer a visual interface, use xRDP on the server and Remmina on your client machine (if using Linux) or Microsoft Remote Desktop (if using Windows).

On the Host Machine (Server):

Install xRDP

sudo apt install xrdp -y
sudo systemctl enable --now xrdp

Add xrdp to ssl-cert group to avoid permission issues

sudo adduser xrdp ssl-cert

On your Client Machine (using Remmina):

Open Remmina.

Create a new connection profile.

Select RDP as the protocol.

Enter the IP address of the Host Machine.

Set the color depth to "High Color (16bpp)" for better performance over ZeroTier.

C. Screen for Persistent Sessions

Since ERPNext installation can take time, use screen so the process doesn't die if your SSH connection drops.

Install screen

sudo apt install screen -y

To start a session:

screen -S erp-install

To detach (if you want to close the window): press Ctrl+A, then D

To re-attach later:

screen -r erp-install

3. ZeroTier Networking

Install ZeroTier on both the Cloud VM and the Local Host to create a virtual "local" bridge.

curl -s https://www.google.com/search?q=https://install.zerotier.com | sudo bash
sudo zerotier-one -q join [YOUR_NETWORK_ID]

Go to the ZeroTier Central dashboard and Authorize both devices. Note the Managed IP of your Local Host (e.g., 10.147.17.5).

4. Install Docker & Portainer CE

On your Host Machine, run the following to install the engine and the management UI.

A. Docker Engine & Compose

Install dependencies

sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release -y

Add Docker’s official GPG key

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://www.google.com/search?q=https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Set up the repository

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y

B. Portainer CE Installation

sudo docker volume create portainer_data
sudo docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/var/data portainer/portainer-ce:latest

Access Portainer at: https://[Your-Host-ZeroTier-IP]:9443

5. Deploying the ERPNext Stack

Log into Portainer.

Go to Stacks > Add stack.

Name it erpnext-v15.

Paste the following configuration into the Web editor:

version: "3"

services:
backend:
image: frappe/erpnext:v15.51.1
restart: always
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs

configurator:
image: frappe/erpnext:v15.51.1
restart: always
entrypoint:
- bash
- -c
command:
- >
ls -1 apps > sites/apps.txt;
bench set-config -g db_host $$DB_HOST;
bench set-config -gp db_port $$DB_PORT;
bench set-config -g redis_cache "redis://$$REDIS_CACHE";
bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";
bench set-config -gp socketio_port $$SOCKETIO_PORT;
environment:
DB_HOST: db
DB_PORT: "3306"
REDIS_CACHE: redis-cache:6379
REDIS_QUEUE: redis-queue:6379
SOCKETIO_PORT: "9000"
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs

create-site:
image: frappe/erpnext:v15.51.1
restart: always
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs
entrypoint:
- bash
- -c
command:
- >
wait-for-it -t 120 db:3306;
wait-for-it -t 120 redis-cache:6379;
wait-for-it -t 120 redis-queue:6379;
export start=date +%s;
until [[ -n grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty" ]] &&

[[ -n grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty" ]] &&

[[ -n grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty" ]];
do
echo "Waiting for sites/common_site_config.json to be created";
sleep 5;
if (( date +%s-start > 120 )); then
echo "could not find sites/common_site_config.json with required keys";
exit 1
fi
done;
echo "sites/common_site_config.json found";
bench new-site --no-mariadb-socket --admin-password=admin --db-root-password=admin --install-app erpnext --set-default erpnv15.comfac-it.net;

db:
image: mariadb:10.6
healthcheck:
test: mysqladmin ping -h localhost --password=admin
interval: 1s
retries: 15
restart: always
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
- --skip-innodb-read-only-compressed
environment:
MYSQL_ROOT_PASSWORD: admin
volumes:
- db-data:/var/lib/mysql

frontend:
image: frappe/erpnext:v15.51.1
depends_on:
- websocket
restart: always
command:
- nginx-entrypoint.sh
environment:
BACKEND: backend:8000
FRAPPE_SITE_NAME_HEADER: erpnv15.comfac-it.net
SOCKETIO: websocket:9000
UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
UPSTREAM_REAL_IP_HEADER: X-Forwarded-For
UPSTREAM_REAL_IP_RECURSIVE: "off"
PROXY_READ_TIMEOUT: 120
CLIENT_MAX_BODY_SIZE: 50m
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs
ports:
- "8715:8080"

queue-long:
image: frappe/erpnext:v15.51.1
restart: always
command: [bench, worker, --queue, "long,default,short"]
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs

queue-short:
image: frappe/erpnext:v15.51.1
restart: always
command: [bench, worker, --queue, "short,default"]
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs

redis-queue:
image: redis:6.2-alpine
restart: always
volumes:
- redis-queue-data:/data

redis-cache:
image: redis:6.2-alpine
restart: always
volumes:
- redis-cache-data:/data

scheduler:
image: frappe/erpnext:v15.51.1
restart: always
command: [bench, schedule]
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs

websocket:
image: frappe/erpnext:v15.51.1
restart: always
command: [node, /home/frappe/frappe-bench/apps/frappe/socketio.js]
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs

volumes:
db-data:
redis-queue-data:
redis-cache-data:
sites:
logs:

Click Deploy the stack.

6. Finalizing with Nginx Proxy Manager

On your Cloud VM (where NPM is running):

Add a new Proxy Host.

Domain Names: erpnv15.comfac-it.net

Scheme: http

Forward IP: Enter the ZeroTier IP of your Host Machine (e.g., 10.147.17.5).

Forward Port: 8715 (as defined in your frontend service).

Enable Websockets Support.

In the SSL tab, request a new Let's Encrypt Certificate.

Important Notes

Permissions: If you run into folder permission issues on the host, ensure the sites volume is owned by the user running docker or set to 775.

Site Creation: The create-site container will run once to initialize the database. Monitor its logs in Portainer to ensure the --new-site command completes successfully.