From edf2be504c2461b1a16142211e9848280900e062 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 25 Apr 2025 12:34:09 +0200 Subject: [PATCH] Implemented espocrm draft --- group_vars/all/03_domains.yml | 2 + group_vars/all/09_ports.yml | 1 + group_vars/all/10_networks.yml | 2 + roles/docker-espocrm/Administration.md | 32 +++++++++++++++ roles/docker-espocrm/Installation.md | 25 ++++++++++++ roles/docker-espocrm/README.md | 16 ++++++++ roles/docker-espocrm/Todo.md | 2 + roles/docker-espocrm/meta/main.yml | 22 +++++++++++ roles/docker-espocrm/tasks/main.yml | 17 ++++++++ .../templates/docker-compose.yml.j2 | 39 +++++++++++++++++++ roles/docker-espocrm/templates/env.j2 | 38 ++++++++++++++++++ roles/docker-espocrm/vars/main.yml | 5 +++ 12 files changed, 201 insertions(+) create mode 100644 roles/docker-espocrm/Administration.md create mode 100644 roles/docker-espocrm/Installation.md create mode 100644 roles/docker-espocrm/README.md create mode 100644 roles/docker-espocrm/Todo.md create mode 100644 roles/docker-espocrm/meta/main.yml create mode 100644 roles/docker-espocrm/tasks/main.yml create mode 100644 roles/docker-espocrm/templates/docker-compose.yml.j2 create mode 100644 roles/docker-espocrm/templates/env.j2 create mode 100644 roles/docker-espocrm/vars/main.yml diff --git a/group_vars/all/03_domains.yml b/group_vars/all/03_domains.yml index 6019970a..5d4cca55 100644 --- a/group_vars/all/03_domains.yml +++ b/group_vars/all/03_domains.yml @@ -10,6 +10,7 @@ defaults_domains: bluesky_web: "bskyweb.{{primary_domain}}" discourse: "forum.{{primary_domain}}" elk: "elk.{{primary_domain}}" + espocrm: "espocrm.{{primary_domain}}" file_server: "files.{{primary_domain}}" friendica: "friendica.{{primary_domain}}" funkwhale: "music.{{primary_domain}}" @@ -55,6 +56,7 @@ defaults_redirect_domain_mappings: - { source: "akaunting.{{primary_domain}}", target: "{{domains.akaunting}}" } - { source: "bbb.{{primary_domain}}", target: "{{domains.bigbluebutton}}" } - { source: "discourse.{{primary_domain}}", target: "{{domains.discourse}}" } +- { source: "crm.{{primary_domain}}", target: "{{domains.espocrm}}" } - { source: "funkwhale.{{primary_domain}}", target: "{{domains.funkwhale}}" } - { source: "gitea.{{primary_domain}}", target: "{{domains.gitea}}" } - { source: "keycloak.{{primary_domain}}", target: "{{domains.keycloak}}" } diff --git a/group_vars/all/09_ports.yml b/group_vars/all/09_ports.yml index 75b0168b..0f28bfde 100644 --- a/group_vars/all/09_ports.yml +++ b/group_vars/all/09_ports.yml @@ -53,6 +53,7 @@ ports: phpldapadmin: 8037 fusiondirectory: 8038 presentation: 8039 + espocrm: 8040 bigbluebutton: 48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port # Ports which are exposed to the World Wide Web public: diff --git a/group_vars/all/10_networks.yml b/group_vars/all/10_networks.yml index ff7068d5..4c9aa677 100644 --- a/group_vars/all/10_networks.yml +++ b/group_vars/all/10_networks.yml @@ -80,6 +80,8 @@ defaults_networks: subnet: 192.168.103.32/28 presentation: subnet: 192.168.103.48/28 + espocrm: + subnet: 192.168.103.64/28 # /24 Networks / 254 Usable Clients bigbluebutton: diff --git a/roles/docker-espocrm/Administration.md b/roles/docker-espocrm/Administration.md new file mode 100644 index 00000000..2c3b92ca --- /dev/null +++ b/roles/docker-espocrm/Administration.md @@ -0,0 +1,32 @@ +# Administration + +## 🗑️ Cleanup (Remove instance & volumes) +```bash +cd {{path_docker_compose_instances}}espocrm/ +docker compose down +# EspoCRM keeps all uploaded files in the *data* volume +docker volume rm espocrm_data espocrm_database +cd {{path_docker_compose_instances}} && rm -vR {{path_docker_compose_instances}}espocrm +``` + +## 🔍 Access EspoCRM container shell +```bash +docker compose exec -it web /bin/bash +``` + +## 🛠️ Database migrations (after image upgrade) +EspoCRM applies migrations automatically on start‑up. To run them manually: +```bash +docker compose exec -it web php command.php upgrade +``` + +## 🗄️ Backup database +```bash +# Dump the MySQL/MariaDB database +docker exec espocrm_database /usr/bin/mysqldump -u root -p$MYSQL_ROOT_PASSWORD espocrm > backup_$(date +%F).sql +``` + +## 🧹 Clear cache +```bash +docker compose exec web php command.php clear cache +``` \ No newline at end of file diff --git a/roles/docker-espocrm/Installation.md b/roles/docker-espocrm/Installation.md new file mode 100644 index 00000000..bc8de8e3 --- /dev/null +++ b/roles/docker-espocrm/Installation.md @@ -0,0 +1,25 @@ +# ⚙️ Configuration & Setup + +## 🔧 Create credentials & pull image +```bash +# Pull the latest EspoCRM image +docker pull espocrm/espocrm:latest + +# If you need to pre‑create a config file, copy the default +# (the container will generate one automatically on first start) +``` + +## 🏗️ Initial deployment with Docker Compose +```bash +# Change into the instance directory created by the role +cd {{path_docker_compose_instances}}espocrm/ + +# Launch the stack +docker compose up -d +``` +The first start can take a minute while EspoCRM initialises the database schema. + +## 🔐 LDAP & OIDC authentication +Both mechanisms are supported out of the box: +- **LDAP:** Configure under *Administration → Authentication → LDAP* after the first login. +- **OIDC:** Configure under *Administration → Authentication → OpenID Connect* and paste the Issuer URL, Client ID and Client Secret from your IdP (Keycloak, Authentik, Entra ID, …). \ No newline at end of file diff --git a/roles/docker-espocrm/README.md b/roles/docker-espocrm/README.md new file mode 100644 index 00000000..e29179bf --- /dev/null +++ b/roles/docker-espocrm/README.md @@ -0,0 +1,16 @@ +# EspoCRM + +## Description + +EspoCRM is a lightweight, open‑source Customer Relationship Management platform that helps you manage leads, accounts, opportunities and post‑sale support in a single, web‑based interface. +This Ansible role deploys EspoCRM with Docker, mirroring the structure of the Mastodon role for a consistent operations workflow. + +## Overview +- **Sales Pipeline & Activities Stream** – track every interaction and schedule follow‑ups. +- **Workflow & BPM** – automate routine tasks and notifications. +- **Extensible Authentication** – native LDAP and OpenID Connect (OIDC) login support. +- **Containerised Architecture** – separate services for the web application, cron jobs and an upstream MySQL/MariaDB database. + +For detailed instructions see: +- [Installation.md](./Installation.md) +- [Administration.md](./Administration.md) diff --git a/roles/docker-espocrm/Todo.md b/roles/docker-espocrm/Todo.md new file mode 100644 index 00000000..66736ae0 --- /dev/null +++ b/roles/docker-espocrm/Todo.md @@ -0,0 +1,2 @@ +# Todos +- Finish draft implementation \ No newline at end of file diff --git a/roles/docker-espocrm/meta/main.yml b/roles/docker-espocrm/meta/main.yml new file mode 100644 index 00000000..102e775e --- /dev/null +++ b/roles/docker-espocrm/meta/main.yml @@ -0,0 +1,22 @@ +galaxy_info: + author: "Kevin Veen-Birkenbach" + description: "EspoCRM is an open‑source CRM with workflow automation, LDAP/OIDC SSO and a lightweight UI" + license: "CyMaIS NonCommercial License (CNCL)" + license_url: "https://s.veen.world/cncl" + company: | + Kevin Veen-Birkenbach + Consulting & Coaching Solutions + https://www.veen.world + galaxy_tags: + - espocrm + - crm + - docker + - sales + - ldap + - oidc + repository: "https://s.veen.world/cymais" + issue_tracker_url: "https://s.veen.world/cymaisissues" + documentation: "https://s.veen.world/cymais" + logo: + class: "fa-solid fa-briefcase" +dependencies: [] \ No newline at end of file diff --git a/roles/docker-espocrm/tasks/main.yml b/roles/docker-espocrm/tasks/main.yml new file mode 100644 index 00000000..82c4deed --- /dev/null +++ b/roles/docker-espocrm/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: "include docker-central-database" + include_role: + name: docker-central-database + +- name: "copy docker-compose.yml and env file" + include_tasks: copy-docker-compose-and-env.yml + +- name: flush docker service + meta: flush_handlers + when: applications.espocrm.setup | bool + +- name: "run database setup / upgrade" + command: + cmd: "docker compose run --rm web php command.php upgrade" + chdir: "{{ docker_compose.directories.instance }}" + when: applications.espocrm.setup | bool \ No newline at end of file diff --git a/roles/docker-espocrm/templates/docker-compose.yml.j2 b/roles/docker-espocrm/templates/docker-compose.yml.j2 new file mode 100644 index 00000000..6e35ffcd --- /dev/null +++ b/roles/docker-espocrm/templates/docker-compose.yml.j2 @@ -0,0 +1,39 @@ +services: + +{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %} + + web: + image: espocrm/espocrm:{{ applications.espocrm.version }} +{% include 'roles/docker-compose/templates/services/base.yml.j2' %} + environment: + - DATABASE_HOST={{ database_host }} + - DATABASE_PORT={{ database_port }} + - DATABASE_NAME={{ database_name }} + - DATABASE_USER={{ database_username }} + - DATABASE_PASSWORD={{ database_password }} + - CRON=disable # cron handled by separate service + command: apache2-foreground + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/" ] + ports: + - "127.0.0.1:{{ ports.localhost.http[application_id] }}:80" +{% include 'templates/docker/container/depends-on-database.yml.j2' %} +{% include 'templates/docker/container/networks.yml.j2' %} + volumes: + - data:/var/www/html + + cron: + image: espocrm/espocrm:{{ applications.espocrm.version }} + command: /usr/local/bin/cron.sh + restart: unless-stopped +{% include 'templates/docker/container/depends-on-database.yml.j2' %} + volumes: + - data:/var/www/html +{% include 'templates/docker/container/networks.yml.j2' %} + healthcheck: + test: ["CMD", "pgrep", "cron"] + +{% include 'templates/docker/compose/volumes.yml.j2' %} + data: + +{% include 'templates/docker/compose/networks.yml.j2' %} \ No newline at end of file diff --git a/roles/docker-espocrm/templates/env.j2 b/roles/docker-espocrm/templates/env.j2 new file mode 100644 index 00000000..5b20513d --- /dev/null +++ b/roles/docker-espocrm/templates/env.j2 @@ -0,0 +1,38 @@ +# EspoCRM environment +# Database connection +DATABASE_HOST={{ database_host }} +DATABASE_PORT={{ database_port }} +DATABASE_NAME={{ database_name }} +DATABASE_USER={{ database_username }} +DATABASE_PASSWORD={{ database_password }} + +# SMTP settings (example) +SMTP_HOST={{ system_email.host }} +SMTP_PORT={{ system_email.port }} +SMTP_USER={{ users['no-reply'].email }} +SMTP_PASS={{ users['no-reply'].mailu_token }} +SMTP_SECURE=tls + +################################### +# LDAP settings (optional) +################################### +{% if applications[application_id].features.ldap | bool %} +LDAP_ENABLED=true +LDAP_HOST={{ ldap.server.domain }} +LDAP_PORT={{ ldap.server.port }} +LDAP_BASE_DN={{ ldap.dn.users }} +LDAP_BIND_DN={{ ldap.dn.administrator }} +LDAP_BIND_PASSWORD={{ ldap.bind_credential }} +LDAP_UID_ATTRIBUTE={{ ldap.attributes.user_id }} +{% endif %} + +################################### +# OpenID Connect (OIDC) settings (optional) +################################### +{% if applications[application_id].features.oidc | bool %} +OIDC_ENABLED=true +OIDC_ISSUER_URL={{ oidc.client.issuer_url }} +OIDC_CLIENT_ID={{ oidc.client.id }} +OIDC_CLIENT_SECRET={{ oidc.client.secret }} +OIDC_REDIRECT_URI=https://{{ domains[application_id] }}/oidc/callback +{% endif %} \ No newline at end of file diff --git a/roles/docker-espocrm/vars/main.yml b/roles/docker-espocrm/vars/main.yml new file mode 100644 index 00000000..f5c30caa --- /dev/null +++ b/roles/docker-espocrm/vars/main.yml @@ -0,0 +1,5 @@ +application_id: "espocrm" +# Password for the espocrm DB user (taken from inventory applications dict) +database_password: "{{ applications[application_id].credentials.database.password }}" +# EspoCRM uses MySQL/MariaDB +database_type: "mysql" \ No newline at end of file