Step-by-Step Guide: Installing ERPNext 15 Using Docker Compose with Portainer

ERPNext is a comprehensive open-source ERP solution used by many businesses for managing various aspects of their operations. In this guide, we’ll walk you through how to set up ERPNext version 15 using Docker Compose with Portainer. This setup simplifies the installation process and ensures all services required by ERPNext are properly configured.

By the end of this guide, you will have ERPNext running on your server, accessible via a web browser. Here’s how to get started.

Prerequisites

Before we dive into the installation, ensure the following:

1. Portainer Installed: Portainer is a container management platform that simplifies the use of Docker. If you haven’t installed Portainer, you can find instructions [here]
2. Docker & Docker Compose: Docker should be installed on your system. If not, follow the Docker installation guide for your operating system: [Docker Installation]
3. Basic Knowledge of Docker and Portainer: While this guide simplifies the process, some basic knowledge will be helpful.

Step 1: Log in to Portainer

1. Open your browser and access Portainer at the IP address or domain of your server, followed by Portainer’s default port (usually `9000`), like so:

http://<your-server-ip>:9000

2. Log in with your credentials or set up an admin account if it’s your first time.

Step 2: Create a New Docker Stack

Once you are logged into Portainer, you’ll use the Docker Compose file to deploy ERPNext. Here’s how:

1. Navigate to the “Stacks” menu: On the Portainer dashboard, go to Stacks in the left-hand menu.
2. Click ‘Add stack’: This will open up a form for you to create a new stack.

Step 3: Paste the Docker Compose File

1. Name the Stack: In the Name field, provide a name for your stack (e.g., `erpnext`).
2. Paste the Docker Compose file: Copy the provided `docker-compose.yml` file (below) and paste it into the Web editor section of the form.

version: "3"

services:
  backend:
    image: frappe/erpnext:v15.19.1
    deploy:
      restart_policy:
        condition: on-failure
    volumes:
      - sites:/home/frappe/frappe-bench/sites
      - logs:/home/frappe/frappe-bench/logs

  configurator:
    image: frappe/erpnext:v15.19.1
    deploy:
      restart_policy:
        condition: none
    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.19.1
    deploy:
      restart_policy:
        condition: none
    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 frontend;

  db:
    image: mariadb:10.6
    healthcheck:
      test: mysqladmin ping -h localhost --password=admin
      interval: 1s
      retries: 15
    deploy:
      restart_policy:
        condition: 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: admin
    volumes:
      - db-data:/var/lib/mysql

  frontend:
    image: frappe/erpnext:v15.19.1
    depends_on:
      - websocket
    deploy:
      restart_policy:
        condition: on-failure
    command:
      - nginx-entrypoint.sh
    environment:
      BACKEND: backend:8000
      FRAPPE_SITE_NAME_HEADER: frontend
      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:
      - "8080:8080"

  queue-long:
    image: frappe/erpnext:v15.19.1
    deploy:
      restart_policy:
        condition: on-failure
    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.19.1
    deploy:
      restart_policy:
        condition: on-failure
    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
    deploy:
      restart_policy:
        condition: on-failure
    volumes:
      - redis-queue-data:/data

  redis-cache:
    image: redis:6.2-alpine
    deploy:
      restart_policy:
        condition: on-failure
    volumes:
      - redis-cache-data:/data

  scheduler:
    image: frappe/erpnext:v15.19.1
    deploy:
      restart_policy:
        condition: on-failure
    command:
      - bench
      - schedule
    volumes:
      - sites:/home/frappe/frappe-bench/sites
      - logs:/home/frappe/frappe-bench/logs

  websocket:
    image: frappe/erpnext:v15.19.1
    deploy:
      restart_policy:
        condition: on-failure
    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:

Step 4: Deploy the Stack

1. Click ‘Deploy the Stack’ at the bottom of the page. Portainer will now begin deploying ERPNext using the services defined in the Docker Compose file.

2. Monitor the process: You can monitor the logs and status of each service from the Portainer dashboard to ensure everything runs correctly.

Step 5: Access ERPNext

Once the stack is deployed, you can access ERPNext through your server’s IP address or domain followed by port `8080` (as defined in the `frontend` service).

http://<your-server-ip>:8080

You should now see the ERPNext login page. Use the admin credentials you specified in the `create-site` service (`admin` as both the username and password).

Conclusion

That’s it! You’ve successfully installed ERPNext 15

Leave the first comment