Introduction

Shopware 6.7 represents a mature evolution of the platform, bringing refined configuration management, optimized container compatibility, and improved performance across search, cache, and session handling. While enterprise deployments often transition to Kubernetes or managed PaaS solutions, Docker Compose remains an exceptional tool for local development, staging validation, and lightweight cloud hosting. This guide focuses on architectural understanding rather than copy-pasting configurations, ensuring you grasp how each component interacts within a Shopware 6.7 stack.

Prerequisites

Before diving in, ensure your environment meets these baseline requirements:

  • Docker Engine 24.0+ with Docker Compose plugin (v2.20+)
  • At least 4 GB RAM and 2 CPU cores for smooth container execution
  • Basic familiarity with Symfony configuration patterns and Linux permissions
  • A valid domain (optional) if targeting HTTPS termination in your setup

Organizing your files intentionally prevents configuration drift and simplifies maintenance. A clean layout looks like this:

shopware-compose/
├── .env                  # Environment variables & secrets
├── docker-compose.yml    # Service orchestration
├── config/
│   └── shopware/         # Custom bundles & overrides
├── data/
│   ├── media/            # Persistent uploads
│   ├── files/            # System logs & cache
│   └── db/               # Database dumps (optional)
└── nginx/
    └── conf.d/           # Reverse proxy rules

Docker Compose Configuration Explained

Shopware 6.7 requires a tightly coupled but loosely integrated stack. Below is a production-aware docker-compose.yml tailored for version 6.7 and beyond:

services:
  shopware:
    image: ghcr.io/shopware/platform:6.7-latest
    environment:
      - APP_ENV=prod
      - APP_DEBUG=0
      - DATABASE_URL=mysql://swuser:S3cur3P@ssw0rd@mariadb:3306/shopware?serverVersion=10.11&charset=utf8mb4
      - REDIS_HOST=redis
      - OPENSEARCH_HTTP_HOSTS=http://opensearch:9200
      - SW_SKU_DOMAIN=localhost
      - TRUSTED_PROXIES=172.16.0.0/12,10.0.0.0/8
    volumes:
      - ./data/media:/var/www/html/custom/plugins/media
      - ./data/files:/var/www/html/var/files
      - ./config/shopware:/var/www/html/config/packages/shopware
    depends_on:
      mariadb: { condition: service_healthy }
      redis: { condition: service_started }
      opensearch: { condition: service_healthy }

  mariadb:
    image: mariadb:10.11
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: shopware
      MYSQL_USER: swuser
      MYSQL_PASSWORD: S3cur3P@ssw0rd
    volumes:
      - db-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data

  opensearch:
    image: opensearchproject/opensearch:2.14.0
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock: { soft: -1, hard: -1 }
    volumes:
      - os-data:/usr/share/opensearch/data

  nginx-proxy:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
    depends_on:
      - shopware

volumes:
  db-data:
  redis-data:
  os-data:

Architecture Breakdown

The shopware container acts as the application layer. Note the use of ghcr.io/shopware/platform rather than older Docker Hub registries; this is the officially maintained image for 6.7+ and includes precompiled assets and optimized PHP-FPM workers. The TRUSTED_PROXIES environment variable ensures Shopware correctly reads client IPs when running behind a reverse proxy, preventing IP spoofing in logs and rate limiters.

mariadb provides the relational store. Shopware 6.7 relies heavily on complex product associations and sales channel mappings, making proper charset=utf8mb4 configuration non-negotiable for emoji and international character support. The healthcheck prevents race conditions during container startup.

redis handles session storage, cache layering, and queue worker coordination. The Alpine variant reduces attack surface while maintaining compatibility with Shopware's serialization requirements.

opensearch replaces the legacy Elasticsearch stack. While 6.7 introduces native search enhancements for catalog browsing, full-text filters, faceted navigation, and storefront search still depend on OpenSearch. Memory allocation is explicitly capped to prevent OOM kills in constrained environments.

nginx-proxy terminates TLS, handles HTTP/2, and routes traffic to the PHP-FPM pool. In production, you would mount Let's Encrypt certificates here and enforce strict security headers.

Environment & Configuration Strategy

Shopware 6.7 decouples configuration from code through environment-first design. Rather than editing config/packages/shopware.yaml directly in containers, rely on the .env file mapped into your compose stack:

APP_ENV=prod
APP_SECRET=your_generated_hex_secret
DATABASE_URL=mysql://swuser:S3cur3P@ssw0rd@mariadb:3306/shopware?serverVersion=10.11&charset=utf8mb4
REDIS_HOST=redis
OPENSEARCH_HTTP_HOSTS=http://opensearch:9200
SW_SKU_DOMAIN=localhost
TRUSTED_PROXIES=172.16.0.0/12,10.0.0.0/8

The APP_SECRET must be regenerated for each environment. Shopware uses it for CSRF protection, signed URLs, and cache tagging. For sensitive values like database passwords, consider using Docker secrets or a vault integration in staging/production rather than plaintext .env files.

Building & Initializing the Stack

Once your files are in place, initialize the stack with explicit dependency ordering:

docker compose up -d mariadb redis opensearch
docker compose run --rm shopware bin/console system:install --basic-setup --skip-licenses
docker compose up -d shopware nginx-proxy

The initial installation creates admin users, sales channels, and baseline data. Shopware 6.7 streams this output with progress indicators, but do not interrupt it. Afterward, clear compiled containers and verify asset publication:

docker compose exec shopware bin/console core:dump gc
docker compose exec shopware bin/console assets:install --symlink
docker compose exec shopware bin/console theme:compile

Post-Deployment & Best Practices

A running stack is only the beginning. Shopware 6.7 introduces stricter cache invalidation rules and requires attention to background processing. Configure your deployment pipeline or crontab to execute queue workers:

* * * * * docker compose exec shopware bin/console marketplace:fetch --limit=10

For production-hardening:

  • Never expose mariadb or opensearch ports externally
  • Use named volumes or mount persistent storage for db-data and os-data
  • Implement periodic snapshots via docker compose exec mariadb mysqldump > backup.sql
  • Enable rate limiting by adding client_max_body_size and limit_req_zone in your nginx config

Shopware 6.7’s configuration layer also supports bundle-level overrides. Place custom YAML files in config/shopware/ and they will merge automatically during container boot. This eliminates the need to rebuild images for minor tweaks.

Conclusion

Deploying Shopware 6 with Docker Compose is less about memorizing service definitions and more about understanding data flow, dependency health, and configuration precedence. Version 6.7 simplifies many pain points from earlier releases while maintaining strict expectations around environment management and cache consistency. By treating your compose stack as a declarative specification rather than a throwaway script, you gain reproducible, version-controlled deployments that scale cleanly into staging or production. Master these fundamentals, and you’ll avoid the majority of container-related pitfalls that plague modern e-commerce infrastructure.