How to setup & self-host ERPNext in Docker without Treafik (NGINX only)
5 min read

How to setup & self-host ERPNext in Docker without Treafik (NGINX only)

Correct docker-compose & env file for self-hosting ERPNext quickly without Treafik.
How to setup & self-host ERPNext in Docker without Treafik (NGINX only)

Table of contents

ERPNext is an HR and business management platform that can be self-hosted on-premise both directly and via Docker (and even Kubernetes and the like). Though their documentation is 'ok', it's a bit confusing and it's missing some steps for setup.

In this article I will show you the settings, setup files and steps needed to get ERPNext hosted on your own hardware without Treafik.

Why without Treafik? Simple: I don't need it, nor want it and I already have a well configured reverse proxy I use for everything so I don't need yet another tool doing the same thing and causing conflicts.

A few very important notes about my setup here and general important notes:

  • While I use it in a production-like environment, I am NOT too picky about perfection.
  • I used the built in database setup instead using an existing sql setup. Why? I was lazy. You may remove the MariaDB container here and use your own if you wish, I simply didn't due to laziness.
  • I changed the default ports because I have things already running on the original ports suggested.
  • Frappe's original docker-compose file did not include port settings for NGINX, and their documentation says NGINX will use port 80. It does not. It uses port 8080, thus I've set up port forwarding to that.
  • Also not documented by them (at least no where where I saw), erp-next worker (the erpnext-python container) should have port 8000 (container side) available as that's what 'serves' the data to their nginx (which serves it to the public)
  • In my current setup, I used a specific ERPNext version. They, for some odd reason, initially put using edge version which is, what we call here in the business tech world ... a "Bad Idea (tm)". That version rarely worked and we had a lot of problems with it. Use a stable release. Such as stable or v13 or what I did, I use a specific version: v13.16.0. Though I'll be soon changing to use the v13 branch to stay up to date.
  • Use reasonably long but not too long passwords for admin and mysql. Also do NOT use special characters. Someone smarter than me can probably explain, but using special characters and long passwords has always broken setup for me when using docker compose. So, in this setup I've used 27 character long passwords with numbers and letters only.
  • I did NOT setup my own docker network for this. Meh. I let Docker & Portainer handle that automatic network creation for me when I did all this through a Portainer stack.
  • The docker-compose.yml and .env files have been edited and slimmed down by me in-order to get rid of Treafik and make them work for us.
  • You may have to specifically open up the ports on your server so that this will all run.
  • In our setup here, we are using an external reverse proxy, so this current setup will NOT work and will NOT be accessible directly. You WILL have to wrap it in reverse proxy in-order to access. In this case we had an existing NGINX centralized and working.
  • And yes.... this means you will have TWO NGINX setups ... one here in this docker setup which does the site 'serving' and then your own NGINX (or other reverse proxy) to wrap it in a domain so you can actually access it.

This setup will start eleven (11) containers. One container is there only to initial the system initially and do that kind of work. The container site-creator will do it's work and then end (stop itself). This is a-ok. Assuming all works well on launch for you, this container will run and depending on your server it will take a while to do the initial setup and migrations. Give it a good while.

First, here is a working ERPNext docker-compose file (docker-compose.yml):

version: "3"

services:
  erpnext-nginx:
    image: frappe/erpnext-nginx:${ERPNEXT_VERSION}
    restart: on-failure
    environment:
      - FRAPPE_PY=erpnext-python
      - FRAPPE_PY_PORT=8000
      - FRAPPE_SOCKETIO=frappe-socketio
      - SOCKETIO_PORT=9007
      - SKIP_NGINX_TEMPLATE_GENERATION=${SKIP_NGINX_TEMPLATE_GENERATION}
    ports:
      - 8007:8080
    volumes:
      - sites-vol:/var/www/html/sites:rw
      - assets-vol:/assets:rw

  erpnext-python:
    image: frappe/erpnext-worker:${ERPNEXT_VERSION}
    restart: on-failure
    environment:
      - MARIADB_HOST=${MARIADB_HOST}
      - REDIS_CACHE=redis-cache:6379
      - REDIS_QUEUE=redis-queue:6379
      - REDIS_SOCKETIO=redis-socketio:6379
      - SOCKETIO_PORT=9007
      - AUTO_MIGRATE=1
      - WORKER_CLASS=${WORKER_CLASS}
    ports:
      - 8000:8000
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw
      - assets-vol:/home/frappe/frappe-bench/sites/assets:rw

  frappe-socketio:
    image: frappe/frappe-socketio:${FRAPPE_VERSION}
    restart: on-failure
    depends_on:
      - redis-socketio
    ports:
      - 9000:9007
      - 9007:9007
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw
      - logs-vol:/home/frappe/frappe-bench/logs:rw

  erpnext-worker-default:
    image: frappe/erpnext-worker:${ERPNEXT_VERSION}
    restart: on-failure
    command: worker
    depends_on:
      - redis-queue
      - redis-cache
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw
      - logs-vol:/home/frappe/frappe-bench/logs:rw

  erpnext-worker-short:
    image: frappe/erpnext-worker:${ERPNEXT_VERSION}
    restart: on-failure
    command: worker
    environment:
      - WORKER_TYPE=short
    depends_on:
      - redis-queue
      - redis-cache
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw
      - logs-vol:/home/frappe/frappe-bench/logs:rw

  erpnext-worker-long:
    image: frappe/erpnext-worker:${ERPNEXT_VERSION}
    restart: on-failure
    command: worker
    environment:
      - WORKER_TYPE=long
    depends_on:
      - redis-queue
      - redis-cache
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw

  erpnext-schedule:
    image: frappe/erpnext-worker:${ERPNEXT_VERSION}
    restart: on-failure
    command: schedule
    depends_on:
      - redis-queue
      - redis-cache
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw
      - logs-vol:/home/frappe/frappe-bench/logs:rw

  redis-cache:
    image: redis:latest
    restart: on-failure
    volumes:
      - redis-cache-vol:/data

  redis-queue:
    image: redis:latest
    restart: on-failure
    volumes:
      - redis-queue-vol:/data

  redis-socketio:
    image: redis:latest
    restart: on-failure
    volumes:
      - redis-socketio-vol:/data

  mariadb:
    image: mariadb:10.6
    restart: on-failure
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --skip-character-set-client-handshake
      - --skip-innodb-read-only-compressed # Temporary fix for MariaDB 10.6
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      # Sometimes db initialization takes longer than 10 seconds and site-creator goes away.
      # Frappe doesn't use CONVERT_TZ() function that requires time zone info, so we can just skip it.
      - MYSQL_INITDB_SKIP_TZINFO=1
    volumes:
      - mariadb-vol:/var/lib/mysql

  site-creator:
    image: frappe/erpnext-worker:${ERPNEXT_VERSION}
    restart: "no"
    command: new
    depends_on:
      - erpnext-python
    environment:
      - SITE_NAME=${SITE_NAME}
      - DB_ROOT_USER=${DB_ROOT_USER}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - INSTALL_APPS=${INSTALL_APPS}
    volumes:
      - sites-vol:/home/frappe/frappe-bench/sites:rw
      - logs-vol:/home/frappe/frappe-bench/logs:rw

volumes:
  mariadb-vol:
  redis-cache-vol:
  redis-queue-vol:
  redis-socketio-vol:
  assets-vol:
  sites-vol:
  cert-vol:
  logs-vol:
docker-compose.yml

Here is a slimmed down ERPNext env file you can use (in Portainer you can add them line by line or use the advanced editor button when creating a stack to just copy-paste this in after making your changes)

Quick note about the .env file: the 'SITES' variables HAS TO have the url in back quotes  ==> ` <<==

ERPNEXT_VERSION=v13
FRAPPE_VERSION=v13
MARIADB_HOST=mariadb
MYSQL_ROOT_PASSWORD=a_mysql_Passw0rd_CHANGEME
SITE_NAME=my.mywebsite.com
SITES=`my.mywebsite.com`
DB_ROOT_USER=root
ADMIN_PASSWORD=myfancyadminPasswordCHANGEME
INSTALL_APPS=erpnext
SKIP_NGINX_TEMPLATE_GENERATION=0
WORKER_CLASS=gthread
.env

Toss the above into a Portainer stack or via command line, and it'll set itself all up. Of course, change the emails, passwords and url's and ports as needed for your own unique setup.