Add new Shopware 6 role with OIDC/LDAP plugin integration and Docker-based deployment configuration.

Includes:
- New role: web-app-shopware (Docker, MariaDB, Redis, OpenSearch)
- Updated networks and ports configuration
- Automated install, migration, and admin creation
- Optional IAM integration via OIDC/LDAP plugins

Reference: https://chatgpt.com/share/6907b0d4-ab14-800f-b576-62c0d26c8ad1
This commit is contained in:
2025-11-02 20:29:13 +01:00
parent d61c81634c
commit d1ccfd9cdd
17 changed files with 406 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
# Shopware
## Description
Empower your e-commerce vision with **Shopware 6**, a modern, flexible, and open-source commerce platform built on **Symfony and Vue.js**. Designed for growth and innovation, it enables seamless integration, outstanding customer experiences, and complete control over your digital business. Build, scale, and sell with confidence.
## Overview
This role deploys **Shopware 6** using **Docker**. It automates installation, migration, and configuration of your storefront, integrating with a central **MariaDB** database.
Optional components like **Redis** and **OpenSearch** enhance performance and search capabilities, while **OIDC** and **LDAP** support integration with centralized identity systems such as **Keycloak**.
With automated setup, update handling, variable management, and plugin-based authentication, this role simplifies the deployment and maintenance of your Shopware instance.
## Features
* **Modern and Scalable:** A robust Symfony-based framework optimized for commerce innovation.
* **Automated Setup & Maintenance:** Installs, migrates, and configures Shopware automatically.
* **Extensible Architecture:** Optional Redis, OpenSearch, and plugin-based IAM integrations.
* **Centralized Database Access:** Connects seamlessly to the shared MariaDB service.
* **Integrated Configuration:** Environment and Docker Compose variables managed automatically.
## Further Resources
* [Shopware Official Website](https://www.shopware.com/en/)
* [Shopware Developer Documentation](https://developer.shopware.com/)
* [Shopware Store (Plugins)](https://store.shopware.com/en/)
## Credits
Developed and maintained by **Kevin Veen-Birkenbach**.
Learn more at [veen.world](https://www.veen.world).
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code)
Licensed under [Infinito.Nexus NonCommercial License](https://s.infinito.nexus/license).

View File

@@ -0,0 +1,48 @@
title: "{{ SOFTWARE_NAME }} Shop"
configuration:
search:
engine: "{{ SHOPWARE_SEARCH_ENGINE }}"
features:
central_database: true
redis: true
ldap: true # via plugin
oidc: false # via plugin (Keycloak)
logout: true
server:
csp:
flags: {}
whitelist: {}
domains:
aliases: []
canonical:
- shop.{{ PRIMARY_DOMAIN }}
docker:
services:
database:
enabled: true
php:
image: "{{ SHOPWARE_PHP_IMAGE }}"
version: "{{ SHOPWARE_VERSION }}"
name: "{{ SHOPWARE_PHP_CONTAINER }}"
cpus: 2.0
mem_reservation: 2g
mem_limit: 4g
pids_limit: 2048
nginx:
image: "{{ SHOPWARE_NGINX_IMAGE }}"
version: "{{ SHOPWARE_NGINX_VERSION }}"
name: "{{ SHOPWARE_NGINX_CONTAINER }}"
port: 8080
cpus: 0.5
mem_reservation: 256m
mem_limit: 512m
redis:
enabled: "{{ SHOPWARE_REDIS_ENABLED }}"
cpus: 0.25
mem_reservation: 256m
mem_limit: 512m
search:
enabled: "{{ SHOPWARE_SEARCH_ENABLED }}"
engine: "{{ SHOPWARE_SEARCH_ENGINE }}"
volumes:
data: "{{ SHOPWARE_VOLUME }}"

View File

@@ -0,0 +1,26 @@
---
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Open-Source Commerce (PHP/Symfony) with optional OIDC/LDAP, Redis & OpenSearch — containerized & automated."
license: "Infinito.Nexus NonCommercial License"
license_url: "https://s.infinito.nexus/license"
company: |
Kevin Veen-Birkenbach
Consulting & Coaching Solutions
https://www.veen.world
galaxy_tags:
- shopware
- ecommerce
- docker
- symfony
- oidc
- ldap
repository: https://s.infinito.nexus/code
issue_tracker_url: https://s.infinito.nexus/issues
documentation: "https://docs.infinito.nexus/"
logo:
class: "fa-solid fa-cart-shopping"
run_after:
- web-app-keycloak
- web-app-mailu
dependencies: []

View File

@@ -0,0 +1,2 @@
# Minimal schema placeholder (extend with your own config contract if desired)
credentials: {}

View File

@@ -0,0 +1,10 @@
---
- name: Flush handlers to ensure containers are up before rendering .env
meta: flush_handlers
- name: Render .env for Shopware
template:
src: "templates/env.j2"
dest: "{{ docker_compose.directories.instance }}/.env"
mode: "0640"
notify: docker compose up

View File

@@ -0,0 +1,7 @@
- name: Install & configure OIDC plugin (if enabled)
include_tasks: setup/oidc.yml
when: applications | get_app_conf(application_id, 'features.oidc')
- name: Install & configure LDAP plugin (if enabled)
include_tasks: setup/ldap.yml
when: applications | get_app_conf(application_id, 'features.ldap')

View File

@@ -0,0 +1,7 @@
- name: Remove OIDC plugin if disabled
include_tasks: cleanup/oidc.yml
when: not (applications | get_app_conf(application_id, 'features.oidc'))
- name: Remove LDAP plugin if disabled
include_tasks: cleanup/ldap.yml
when: not (applications | get_app_conf(application_id, 'features.ldap'))

View File

@@ -0,0 +1,10 @@
- name: "Deactivate/uninstall LDAP plugin if present"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
cd {{ SHOPWARE_ROOT }}
php bin/console plugin:deactivate INFX_LDAP_PLUGIN || true
php bin/console plugin:uninstall INFX_LDAP_PLUGIN --keep-user-data || true
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"

View File

@@ -0,0 +1,10 @@
- name: "Deactivate/uninstall OIDC plugin if present"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
cd {{ SHOPWARE_ROOT }}
php bin/console plugin:deactivate INFX_OIDC_PLUGIN || true
php bin/console plugin:uninstall INFX_OIDC_PLUGIN --keep-user-data || true
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"

View File

@@ -0,0 +1,71 @@
---
- name: "Load docker, DB and proxy for {{ application_id }}"
include_role:
name: sys-stk-full-stateful
- name: Wait for Shopware HTTP endpoint
wait_for:
host: "127.0.0.1"
port: "{{ ports.localhost.http[application_id] }}"
delay: 5
timeout: 300
- name: Render environment and DB settings
include_tasks: 01_database.yml
- name: "Run Shopware install / migrations"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
set -e
cd {{ SHOPWARE_ROOT }}
php bin/console system:install --basic-setup --create-database --force
php bin/console database:migrate --all
php bin/console database:migrate-destructive --all
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"
register: migrate
changed_when: migrate.rc == 0
- name: "Create initial admin user (idempotent)"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
set -e
cd {{ SHOPWARE_ROOT }}
php bin/console user:create "{{ users.administrator.username }}" \
--admin --password="{{ users.administrator.password }}" \
--firstName="Admin" --lastName="User" --email="{{ users.administrator.email }}" || true
'
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: "Warm up caches and index"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
cd {{ SHOPWARE_ROOT }}
php bin/console messenger:consume --time-limit=60 --limit=100 || true
php bin/console dal:refresh:index || true
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: Execute setup routines (OIDC/LDAP)
include_tasks: 02_setup.yml
- name: Execute cleanup routines
include_tasks: 03_cleanup.yml
when: MODE_CLEANUP
- name: Register DNS records for Shopware domain(s)
include_role:
name: sys-dns-cloudflare-records
vars:
cloudflare_records:
- zone: "{{ domains | get_domain(application_id) | to_zone }}"
type: A
name: "{{ domains | get_domain(application_id) }}"
content: "{{ networks.internet.ip4 }}"
proxied: true
when: DNS_PROVIDER == 'cloudflare'

View File

@@ -0,0 +1,27 @@
# Replace INFX_LDAP_PLUGIN with the actual plugin name you use
- name: "Install LDAP admin plugin & activate"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
set -e
cd {{ SHOPWARE_ROOT }}
php bin/console plugin:refresh
php bin/console plugin:install --activate INFX_LDAP_PLUGIN || true
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: "Configure LDAP connection"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
set -e
cd {{ SHOPWARE_ROOT }}
php bin/console system:config:set "InfxLdap.config.host" "{{ LDAP.SERVER.DOMAIN }}"
php bin/console system:config:set "InfxLdap.config.port" "{{ LDAP.SERVER.PORT }}"
php bin/console system:config:set "InfxLdap.config.bindDn" "{{ LDAP.DN.ADMINISTRATOR.DATA }}"
php bin/console system:config:set "InfxLdap.config.password" "{{ LDAP.BIND_CREDENTIAL }}"
php bin/console system:config:set "InfxLdap.config.userBase" "{{ LDAP.DN.OU.USERS }}"
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"

View File

@@ -0,0 +1,26 @@
# Replace INFX_OIDC_PLUGIN with the actual plugin name (Composer or local)
- name: "Install OIDC plugin & activate"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
set -e
cd {{ SHOPWARE_ROOT }}
php bin/console plugin:refresh
php bin/console plugin:install --activate INFX_OIDC_PLUGIN || true
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: "Configure OIDC via system:config"
shell: |
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_PHP_CONTAINER }} bash -lc '
set -e
cd {{ SHOPWARE_ROOT }}
php bin/console system:config:set "InfxOidc.config.clientId" "{{ OIDC.CLIENT.ID }}"
php bin/console system:config:set "InfxOidc.config.clientSecret" "{{ OIDC.CLIENT.SECRET }}"
php bin/console system:config:set "InfxOidc.config.discoveryUrl" "{{ OIDC.CLIENT.DISCOVERY_DOCUMENT }}"
php bin/console system:config:set "InfxOidc.config.scopes" "openid profile email"
php bin/console cache:clear
'
args:
chdir: "{{ docker_compose.directories.instance }}"

View File

@@ -0,0 +1,66 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
php:
{% include 'roles/docker-container/templates/base.yml.j2' %}
image: "{{ SHOPWARE_PHP_IMAGE }}:{{ SHOPWARE_VERSION }}"
container_name: "{{ SHOPWARE_PHP_CONTAINER }}"
working_dir: /var/www/html
volumes:
- data:/var/www/html
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
nginx:
{% include 'roles/docker-container/templates/base.yml.j2' %}
image: "{{ SHOPWARE_NGINX_IMAGE }}:{{ SHOPWARE_NGINX_VERSION }}"
container_name: "{{ SHOPWARE_NGINX_CONTAINER }}"
ports:
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}"
volumes:
- data:/var/www/html:ro
depends_on:
- php
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% if SHOPWARE_REDIS_ENABLED %}
redis:
image: redis:7-alpine
container_name: redis
command: ["redis-server", "--appendonly", "yes"]
restart: unless-stopped
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% endif %}
{% if SHOPWARE_SEARCH_ENABLED %}
{% if SHOPWARE_SEARCH_ENGINE == 'opensearch' %}
opensearch:
image: opensearchproject/opensearch:2
environment:
- discovery.type=single-node
- plugins.security.disabled=true
ulimits:
memlock: { soft: -1, hard: -1 }
mem_limit: 2g
restart: unless-stopped
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% else %}
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.22
environment:
- discovery.type=single-node
ulimits:
memlock: { soft: -1, hard: -1 }
mem_limit: 2g
restart: unless-stopped
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% endif %}
{% endif %}
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
data:
name: {{ SHOPWARE_VOLUME }}
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -0,0 +1,32 @@
# DOMAIN/URL
DOMAIN={{ domains | get_domain(application_id) }}
APP_URL="{{ domains | get_url(application_id, WEB_PROTOCOL) }}/"
# Shopware
APP_ENV={{ 'dev' if (ENVIRONMENT | lower) == 'development' else 'prod' }}
APP_URL_TRUSTED_PROXIES=127.0.0.1
INSTANCE_ID={{ application_id }}
# Database
DATABASE_URL="mysql://{{ database_username }}:{{ database_password }}@{{ database_host }}:{{ database_port }}/{{ database_name }}"
# Redis (optional)
{% if SHOPWARE_REDIS_ENABLED | bool %}
REDIS_URL="redis://{{ SHOPWARE_REDIS_ADDRESS }}/0"
CACHE_URL="redis://{{ SHOPWARE_REDIS_ADDRESS }}/1"
MESSENGER_TRANSPORT_DSN="redis://{{ SHOPWARE_REDIS_ADDRESS }}/2"
{% else %}
CACHE_URL="file://cache"
{% endif %}
# Search
{% if SHOPWARE_SEARCH_ENABLED %}
{% if SHOPWARE_SEARCH_ENGINE == 'opensearch' %}
OPENSEARCH_URL="http://opensearch:9200"
{% else %}
ELASTICSEARCH_URL="http://elasticsearch:9200"
{% endif %}
{% endif %}
# Mail (Mailu)
MAILER_DSN="smtps://{{ users['no-reply'].email }}:{{ users['no-reply'].mailu_token }}@{{ SYSTEM_EMAIL.HOST }}:{{ SYSTEM_EMAIL.PORT }}"

View File

@@ -0,0 +1,27 @@
# General
application_id: "web-app-shopware"
database_type: "mariadb"
# Docker
container_port: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.port') }}"
docker_compose_flush_handlers: true
# Shopware container/image vars
SHOPWARE_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.php.version') }}"
SHOPWARE_PHP_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.php.image') }}"
SHOPWARE_PHP_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.php.name') }}"
SHOPWARE_NGINX_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.image') }}"
SHOPWARE_NGINX_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.version') }}"
SHOPWARE_NGINX_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.nginx.name') }}"
SHOPWARE_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
SHOPWARE_USER: "www-data"
SHOPWARE_ROOT: "/var/www/html"
# Search/Cache
SHOPWARE_REDIS_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.redis.enabled') }}"
SHOPWARE_REDIS_ADDRESS: "redis:6379"
SHOPWARE_SEARCH_ENABLED: "{{ applications | get_app_conf(application_id, 'docker.services.search.enabled') }}"
SHOPWARE_SEARCH_ENGINE: "{{ applications | get_app_conf(application_id, 'docker.services.search.engine') }}"
# IAM (true if either OIDC or LDAP is enabled)
SHOPWARE_IAM_ENABLED: "{{ applications | get_app_conf(application_id, 'features.oidc') or applications | get_app_conf(application_id, 'features.ldap') }}"