Skip to content

Repository files navigation

Shopware 6 Docker Stack

Build Docker image

The stack consists of:

  • PHP 8.4 (FPM) under Debian Bullseye
  • MariaDB 11.8.8 under Debian
  • Caddy 2.11.4
  • Redis 8.2.7

The compose stack will take care of building a customized PHP container image with the necessary extensions.

  • Pre-configured Caddy server (except domain)
    • Dotfiles blocked (except .well-known/)
    • HTTPS ready; easy to set up with a reverse proxy
  • Pre-configured MariaDB 11.8.8
    • Secure access - inaccessible from outside, even the host itself
  • Pre-configured PHP 8.4 for Shopware
    • Pre-installed modules: mbstring, gd, intl, pdo_mysql, zip, exif, redis
    • Pre-configured and enabled opcache
    • GD compiled with WebP, JPEG, PNG, AVIF and XPM support
    • Increased memory limit to 512M
    • Increased execution time limit to 3m
  • Pre-configured background service runners for Shopware 6
    • messenger:consume
      • Runs as a separate container
      • Memory limit: 512MB
    • scheduled-task:run
      • Runs as a separate container
      • Memory limit: 512MB

All Docker images are version-locked to ensure maximum stability. Caddy and MariaDB are strictly locked and need to be manually updated in the Compose file. PHP is is only locked to version 8.3, so minor updates are available automatically when rebuilding the image.

Supported Shopware versions

Shopware version Supported
6.6.10.5
6.7.0.1
6.7.1.2
6.7.2.2
6.7.6.2
6.7.7.1
6.7.10.1
6.7.11.1
6.7.12.1
6.7.12.2
6.7.13.0
Legend
  • ✅: Supported, tested
  • ❌: Unsupported, tested
  • ❓: Unknown, not tested
Supported plugins

The following plugins have been tested and are known to work with this stack:

  • PayPal for Shopware 6 - 10.4.1
  • Shopware Language Pack - 5.36.0
  • Tools - 3.2.5
  • Migration Assistant - 15.0.4
  • Stripe Payments for Shopware 6 App - 1.4.4
  • Shopware Store - 4.1.1
  • Shopware GMV Reporting - 1.0.0
  • Custom JavaScript/CSS Manager for Shopware 6 - 5.0.3
  • Custom Template Manager - 4.0.0
  • [[moori]] Foundation - 1.7.59

Note that this does not mean that other plugins will not work, these are just the ones that have been tested.

Getting started

Before you start, you may change the default database password in the compose file. Do not attempt to create additional database users, you cannot grant permissions due to how restricted the database is. If you really want this, you'll need to at least temporarily open the MariaDB port on the container.

ℹ️ If you are running on a slow system, you can also use pre-built images from the CI. You can find the latest images here.

Simply replace the build section in the compose file with image: ghcr.io/tesyl-sro/shopware-stack:latest and run docker compose pull to download the latest image.

  1. Install Docker using these instructions.

  2. Download this repo as a zip to your server.

  3. Extract the archive.

  4. cd into the extracted folder.

    cd shopdock2
  5. Edit the Caddyfile according to your domain(s). Also make sure that the root folder is /app/public.

  6. Create a site directory:

    mkdir site
  7. Change ownership of the site directory to the www-data user and group:

    chown -hR www-data:www-data site
  8. Run the stack using Docker Compose, without shopware_sched_task_runner and shopware_messenger_runner.

    docker compose up caddy php-fpm database

    You can add -d to run it in the background.

    The latest Shopware installer will be automatically downloaded to site/public/shopware-installer.phar.php on the first run. If you want to use a specific version of Shopware, you can download the installer manually and place it in that location.

  9. Complete the initial Shopware setup at http://[host]:8888/shopware-installer.phar.php.

  10. Edit the Caddyfile so that the root folder is /app/public/public.

  11. Restart Caddy using docker compose restart caddy.

  12. Complete the Shopware database configuration at http://[host]:8888/installer. Wait until the page is no longer loading after clicking Next during the Configuration step.

  13. Open the admin panel by going to /admin (e.g. http://[host]:8888/admin).

  14. Complete the first-time setup.

  15. Shut down the server according to step 11.

  16. Restart the server as well as all services using docker compose up.

Note that during the installation, you should not start shopware_sched_task_runner and shopware_messenger_runner. These services should only ever be started after Shopware is fully installed, including the OOBE setup. Running these services with an incomplete installation of Shopware may brick your installation and you have to start over.

Testing on localhost

Use http://localhost:8888 to access the Shopware store and http://localhost:8888/admin to access the admin panel.

On some systems, the www-data user and group may not exist. In this case, use the UID 33 and GID 33 in the chown commands. Additionnaly, you may need to use sudo.

HTTPS Configuration

⚠️ As of July 2026, we have removed automatic HTTPS configuration from this stack.

The original setup forced Caddy as the main web server, making it more difficult to run other services on the same server. You'll now need to set up a reverse proxy in front of this stack to provide HTTPS.

⚠️ You will need to complete the installation of Shopware before setting up HTTPS!

This stack only provides an HTTP server. For production use, you should set up a reverse proxy in front of this stack to provide HTTPS. The simplest setup is a separate docker-compose.yml wuth a Caddy container.

Firstly, make sure that your sales channel already has the HTTPS URL set in the Shopware admin panel. If you already started messing with HTTPS configuration, and you no longer have access to the admin panel, use the command docker compose exec database mariadb -uroot -pshopware shopware -e "SELECT url FROM sales_channel_domain;" to check the current URLs. Additionally, you can look up commands to change the sales channel URL using the CLI.

After that, shut down the stack using docker compose down and follow the steps below.

Caddy

In a separate directory, create a docker-compose.yml file with the following content:

services:
  caddy:
    image: caddy:2.11.4-alpine
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy-data:/data
      - ./caddy-config:/config

Then create a Caddyfile in the same directory with the following content:

https://example.com {
  reverse_proxy host.docker.internal:8888
}

Replace example.com with your store domain.

Cloudflare Tunnel

If you are using Cloudflare, you can also use a Cloudflare Tunnel to provide HTTPS.

In a separate directory, create a docker-compose.yml file with the following content:

services:
  cloudflared:
    image: cloudflare/cloudflared:2026.7.2
    container_name: cloudflared
    restart: unless-stopped
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=__YOUR_TOKEN_HERE__
      - TUNNEL_METRICS=127.0.0.1:2000
    healthcheck:
      test: ["CMD", "cloudflared", "tunnel", "--metrics", "127.0.0.1:2000", "ready"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    tmpfs:
      - /tmp
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 64M
    extra_hosts:
      - "host.docker.internal:host-gateway"

Continue with the setup on your Cloudflare dashboard to create a new tunnel and get the TUNNEL_TOKEN. Replace __YOUR_TOKEN_HERE__ with your actual token.

Post-setup HTTPS configuration

You need to make Shopware trust the reverse proxy. Do the following steps to configure this.

Next, edit the site/.env and site/.env.local files to set the APP_URL and TRUSTED_PROXIES variable to your domain, e.g.:

APP_URL=https://[domain]
TRUSTED_PROXIES="REMOTE_ADDR"

Lastly, create or edit the site/config/packages/framework.yaml:

framework:
    trusted_proxies: '%env(TRUSTED_PROXIES)%'
    trusted_headers:
        - 'x-forwarded-for'
        - 'x-forwarded-host'
        - 'x-forwarded-proto'
        - 'x-forwarded-port'

Then re-apply ownership of the site directory using chown -hR www-data:www-data site and restart the stack using docker compose up caddy php-fpm database. Also reset all caches using the commands in the Useful commands section.

Running a second Shopware instance

You can run multiple Shopware instances on the same server by creating a new directory for each instance.

You need to change all container_name values in the docker-compose.yml file to avoid conflicts. You also need to change the port for the Caddy container.

Post-setup

Before performing these steps:

  1. Make sure you're in the root directory of this repo.
  2. Shut down the stack (unless stated otherwise).
  3. Set up HTTPS as described above.

The following steps are not required, but may help improve security and performance.

Perform the following steps to optimize Shopware for production use:

  1. Disable the admin worker using a new config file.

    nano site/config/packages/shopware.yml

    Add the following:

    shopware:
        admin_worker:
            enable_admin_worker: false

    Clear all caches AND THEN restart the stack to apply the changes!

  2. Use zstd instead of gzip for cache and cart compression. (Read more)

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/shopware.yml

    Add the following under shopware:

    cart:
        compress: true
        compression_method: zstd
    cache:
        cache_compression: true
        cache_compression_method: 'zstd'
  3. Disable App URL external check (Read more)

    Make sure that APP_URL is set correctly, e.g. https://mystore.com in both .env and .env.local.

    nano site/.env

    Add the following:

    APP_URL_CHECK_DISABLED=1
    

    Repeat the same for .env.local.

    Clear all caches AND THEN restart the stack to apply the changes!

  4. Set the log level of monolog to error and limit it's buffer size:

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/monolog.yml

    Add the following:

    monolog:
      handlers:
        main:
          level: error
          buffer_size: 30
        business_event_handler_buffer:
          level: error
  5. Disable Symfony Secrets

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/secrets.yml

    Add the following:

    framework:
      secrets:
        enabled: false
  6. Prevent mail data updates

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/shopware.yml

    Add the following under shopware:

    mail:
      update_mail_variables_on_send: false
  7. Enable sending mails over queue

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/framework.yml

    Add the following:

    framework:
      mailer:
        message_bus: 'messenger.default_bus'
  8. Disable the Increment Storage

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/shopware.yml

    Add the following under shopware:

    increment:
      user_activity:
        type: 'array'
      message_queue:
        type: 'array'
  9. Disable Product Stream Indexing

    You need to clear all caches and then stop the stack before doing this! Run all commands from Reset all caches under the Useful commands section first.

    docker compose down
    nano site/config/packages/shopware.yml

    Add the following under shopware:

    product_stream:
      indexing: false
  10. Set a fixed cache ID

    nano site/.env

    Add the following:

    SHOPWARE_CACHE_ID=mystore
    

    You can replace mystore with any other valid name.

    Repeat the same for .env.local.

    Clear all caches AND THEN restart the stack to apply the changes!

  11. (Not recommended) Enable OPCache preloading.

    This can noticably improve loading times, but it may cause stability issues for unknown reasons.

    Add/Uncomment the following 2 lines in Dockerfile-php's OPCache tuning section:

    RUN echo 'opcache.preload = /app/public/var/cache/opcache-preload.php' >> /usr/local/etc/php/conf.d/docker-php-opcache.ini;
    RUN echo 'opcache.preload_user = www-data' >> /usr/local/etc/php/conf.d/docker-php-opcache.ini;

    Rebuild AND restart the stack after modifying these files!

    Note: This may cause stability issues, however it also noticably improves (loading) performance. If this is unstable for you, undo this change. You may also sometimes see a lot of errors from shopware_sched_task_runner and shopware_messenger_runner during startup. This is normal, and it should be automatically fixed after a few seconds, and if not, undo this change.

  12. Update pm.max_children, pm.max_requests and listen.backlog

    These values allow limiting how much processing can PHP-FPM do. These values have to be adjusted according to your server's hardware.

    Our default values provide a good base for most small instances. For larger stores with more traffic, they may not be adequate.

    Improper configuration of these values can trigger warnings in Shopware (Tools), specifically:

    • PHP FPM max listen queue: This indicates how many times has PHP-FPM reached pm.max_children since it's been started. Ideally, this value should never be reached, therefore the "recommended" value is 0.
    • PHP FPM max children reached: This simply indicates if PHP-FPM has ever reached pm.max_children since it's been started. Ideally, this value should never be true.

    Note: Do not increase these values too much, or it will overload your server. If you can't find values that don't trigger any warnings, then your hardware may not be performant enough.

  13. Enable Redis message queue.

    You need to shut down the stack before doing this!

    nano site/.env.local

    At the end of the file, add the following:

    MESSENGER_TRANSPORT_DSN=redis://redis:6379/messages?auto_setup=false
    

    Next, inside the php-fpm container, install the symfony/redis-messenger package:

    docker compose exec php-fpm bash
    cd /app/public
    ./composer require "symfony/redis-messenger:^7.4" -W

    Next, still inside the php-fpm container, run the following command to clear caches and create the necessary Redis tables:

    ./bin/console cache:clear:all
    ./bin/console messenger:setup-transports

    Finally, restart the stack.

  14. Optimize service limits to your hardware

    Change pids_limit, mem_limit and cpus according to your preference and hardware configuration. The defaults are optimized for a 2 vCore + 4GB RAM server.

Updating Shopware & the stack

Updating Shopware should be done using the Shopware admin panel. Updating PHP can be done by cleaning up the old image and rebuilding it.

Useful commands

Clean up unused Docker containers
docker container prune -f
View containers and their statuses
docker container ls -a
Run a shell inside the PHP-FPM container
docker compose exec php-fpm bash
Run a shell inside the database container
docker compose exec database bash
Use PHP CLI
docker compose exec php-fpm php [COMMAND]

Example:

docker compose exec php-fpm php -v
Use MariaDB CLI
docker compose exec database mariadb -u root --password=shopware -D shopware

Note: If you changed the database name and/or password, you need to adjust the -D and --password arguments.

Dump the database
docker compose exec database mariadb-dump -u root --password=shopware --skip-set-charset --default-character-set=utf8mb4 shopware > database_dump.sql

Note 1: If you changed the database name and/or password, you need to adjust the --password argument and/or replace the database name shopware.

Import an SQL file
docker compose exec database mariadb -u root --password=shopware -D shopware < [SOURCE]

Example:

docker compose exec database mariadb -u root --password=shopware -D shopware < my_backup_file.sql

Note: If you changed the database name and/or password, you need to adjust the -D and --password arguments.

Use Shopware CLI
docker compose exec php-fpm /app/public/bin/console [COMMAND]

Example:

docker compose exec php-fpm /app/public/bin/console about
Run messenger tasks
docker compose exec php-fpm /app/public/bin/console messenger:consume async low_priority --time-limit=60 --memory-limit=512M --no-interaction --no-ansi --quiet
Check scheduled tasks
docker compose exec php-fpm /app/public/bin/console scheduled-task:list
Run scheduled tasks
docker compose exec php-fpm /app/public/bin/console scheduled-task:run --time-limit=60 --memory-limit=512M --no-interaction --no-ansi
Reset all caches
docker compose exec php-fpm /app/public/bin/console cache:clear:all
docker compose exec php-fpm /app/public/bin/console cache:clear
docker compose exec php-fpm /app/public/bin/console cache:warmup
docker compose exec php-fpm /app/public/bin/console theme:compile
chown -hR www-data:www-data site

Note that if your system does not have the www-data user and group created, you can use chown -hR 33:33 site instead. Some of these commands may require root/sudo.

Clean up Docker

⚠️ WARNING ⚠️

This will irrecoverably delete ALL VOLUMES AND IMAGES.

This will NOT detele your database, shopware data, Caddy configuration from this stack.

You can use this to clean up old image layers that are no longer used and free up disk space.

Make sure to shut down the stack before running these commands.

docker builder prune -a -f
docker buildx prune -a -f
docker image prune -a -f
docker container prune -f

You will need to re-pull and rebuild the images after this.

Backing up your stack

To create a backup of your Shopware stack (inc. Shopware data, database and Caddy configuration), simply shut down the stack and archive the data directories mentioned in the compose file.

The commands listed below assume that you are inside the root of this repository on your system:

# Shut down all containers
docker compose down

# Create a tar archive in the parent directory
tar cvzf ../my-shopware-backup.tar.gz .

# Check the contents (remove the pipe to head to see all files)
tar tvf my-shopware-backup.tar.gz | head

Alternatively, if you want to create the smallest possible archive, you can use LZMA2 with maximum compression using the following command. Note that while LZMA2 decompression is fast, compression can be very slow and may require a lot of RAM.

XZ_OPT="-9e -T0" tar cvJf ../my-shopware-backup.tar.xz .

You could also use zip or 7-Zip to create a backup archive.

It is recommended that you use tar, as it keeps track of permissions and ownerships.

Restoring from a backup

If you just want to import a database from a SQL dump file, check the Useful commands section above.

To restore your Shopware stack from a backup, run the following steps:

  1. Extract the backup archive.

    tar xvzf my-shopware-backup.tar.gz
  2. cd into the new directory.

    cd my-shopware-backup
  3. Ensure that the site directory is owned by www-data:

    ls -lh site

    If not, perform step 8 from the Getting started section.

  4. Start the stack.

    docker compose up -d

Troubleshooting

This section is dedicated to issues we encountered over time, with potential fixes.

Shopware tools displays Open Queues warning, but message processing works.

Firstly, check if messages and tasks are actually being executed. If containers shopware_sched_task_runner and shopware_messenger_runner are running, then go to the admin panel, Settings, Caches & indexes and click Update indexes. Now go back to Shopware Tools, open Queue tab and check if the size of the async and default queues is decreasing as you keep refreshing. If the numbers drop to 0, it means that message processing works.

If the Open Queues warning is still displayed, click Reset Queue and confirm. This should clear the warning.

Causes

Unknown, but it could be that if the messenger does not consume a message fast enough, and the message gets somehow dropped or lost from Redis/Doctrine queue, and the database still has that message marked as queued, then Shopware Tools will count that as an unprocessed message. This is likely to happen after an update, not sure why.

Redis configuration is lost after an update

Make sure you configured the Redis queue in the .env.local file, and not .env.

About

Fully pre-configured Shopware 6 stack using Docker.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

Contributors

Languages