# Docker Setup

## Installation on Mac

Start by downloading the latest version of **Docker Desktop** for MAC or **Orbstack** and install it on your system. We have really positive experiences with Orbstack, especially with performance when using bind mounts.

* [https://orbstack.dev](https://orbstack.dev/)
* [https://docs.docker.com/desktop/setup/install/mac-insta](https://docs.docker.com/desktop/setup/install/mac-install/)

## Installation on Linux

Start by downloading the latest version of Docker and install it on your system.

* [Docker for CentOS](https://docs.docker.com/install/linux/docker-ce/centos/)
* [Docker for Debian](https://docs.docker.com/install/linux/docker-ce/debian/)
* [Docker for Fedora](https://docs.docker.com/install/linux/docker-ce/fedora/)
* [Docker for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)

You can find more about Docker [here](https://docs.docker.com/docker-for-windows/install/).

## Installation on Windows

Start by downloading the latest version of Docker Desktop for Windows and install it on your system.

* [Download Docker for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows/)

You can find more about Docker for Windows [here](https://docs.docker.com/docker-for-windows/install/).


# Which Image should I use?

{% hint style="info" %}
First of all, the [website](https://www.dockware.io) contains a **list of all images** with **short descriptions**. So we recommend reading this, to get a basic overview of what is available first.
{% endhint %}

## Pick your Topic

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Build Web Apps</strong></td><td>You want to build applications based on PHP and/or Node.js</td><td><a href="/pages/PGC7BewbkXZLzJwB8SYc">/pages/PGC7BewbkXZLzJwB8SYc</a></td></tr><tr><td><strong>Build Headless Systems</strong></td><td>You want to build a headless setup for Shopware, CMS systems and more</td><td><a href="/pages/94O9ZX1k19GH8wnVgdFj">/pages/94O9ZX1k19GH8wnVgdFj</a></td></tr><tr><td><strong>Build Shopware Plugins</strong></td><td>You want to create awesome Shopware Plugins</td><td><a href="/pages/saVmW9L0JxHCDVrfITWi">/pages/saVmW9L0JxHCDVrfITWi</a></td></tr><tr><td><strong>Build Shopware Apps</strong></td><td>You want to create Apps for Shopware with an easy local environment</td><td><a href="/pages/vWWxnmDvvzxcclQTsSeo">/pages/vWWxnmDvvzxcclQTsSeo</a></td></tr><tr><td><strong>Build Shopware Shops</strong></td><td>You want to create full Shopware shops as a merchant, freelancer or agency.</td><td><a href="/pages/QfUgkKHPw80MKapCN21J">/pages/QfUgkKHPw80MKapCN21J</a></td></tr><tr><td><strong>Explore Shopware</strong></td><td>You want to explore features of Shopware versions</td><td><a href="/pages/le8YVn7j92s0qDWSV90e">/pages/le8YVn7j92s0qDWSV90e</a></td></tr></tbody></table>


# Getting Started

## What is dockware/web?

This image is designed to provide web developers with an **optimized environment** featuring multiple “latest” **PHP** and **Node** versions, along with **essential tools** like Xdebug, Tideways, and more.

Its goal is to streamline development workflows with a clean, up-to-date setup. Simply run the container and start developing PHP, Node, or other web applications—without the hassle of configuring your local environment.

## When to use this image?

This image is a versatile choice for all kinds of web development and should be your go-to option unless you require a specific setup, such as a pre-configured Shopware version.

**Possible use cases:**

• Developing applications with Symfony, Laravel, and more

• Building Vue.js applications or other Node-based projects

• Running tasks in CI/CD pipelines

• Developing Shopware while managing the full environment and database containers yourself

## Starting Containers

You can use either the latest tag or any specific tag version from the image. Please see [Releases and Versions](/dockware-web/releases-and-versions).

You can either start it directly by using `docker run`....

```bash
docker run -p 80:80 dockware/web:latest
```

...or create a **docker-compose.yml** file and start it using `docker-compose up -d`...

```yaml
website:
  image: dockware/web:latest
  ports:
    - 80:80
  volumes:
    - "./src:/var/www/html"
```

{% hint style="success" %}
And that's it.\
After starting your container, you will immediately have a working environment that can be accessed using **<http://localhost>** in your browser.
{% endhint %}


# Features

This image offers a variety of features that can be utilized both at startup and while it’s running. You can configure key settings when launching the container.

Many features can also be adjusted dynamically during runtime.

## PHP Version

We've included multiple PHP versions in this image. So you can easily configure what you need in your specific project, without having to download lots of different images.

### Start with PHP version

If you want to start a container with a specific PHP version, just provide the **environment variable** either in the `docker run` command or within your **docker-compose.yml** file.

```bash
docker run -e PHP_VERSION=8.4 dockware/web:latest
```

```yaml
app:
   image: dockware/web:latest
   ...
   environment:
      - PHP_VERSION=8.4
```

{% hint style="danger" %}
Please keep in mind, if you start a container with an **invalid PHP version**, then it will crash.\
Just run it without a provided PHP version and navigate to **/etc/php** to see what is installed.\
Please see this page for more: [Releases and Versions](/dockware-web/releases-and-versions)
{% endhint %}

### Runtime Switch

You can also switch your PHP version at runtime, while the container is running.\
Navigate to **/var/www**, there we have prepared a **makefile** for you with various commands, such as `switch-php` that you can use in this case.

```bash
cd /var/www && make switch-php version=8.2
```

The command has been designed to be as **robust as possible**. This means, that nothing should break if you switch to the same PHP version, or even a version that is not supported and existing in the current image you use.

{% embed url="<https://www.youtube.com/watch?v=LGukxv72Nm4>" fullWidth="false" %}
Watch our video about switching while using "docker run"
{% endembed %}

{% embed url="<https://www.youtube.com/watch?v=E8tmkLabSBc>" %}
Watch our video about switching with your docker-compose.yml
{% endembed %}

## Node Version

We've included multiple Node versions in this image. So you can easily configure what you need in your specific project, without having to download lots of different images.

### Start with Node version

If you want to start a container with a specific Node version, just provide the **environment variable** either in the `docker run` command or within your **docker-compose.yml** file.

```bash
docker run -e NODE_VERSION=22 dockware/web:latest
```

```yaml
app:
   image: dockware/web:latest
   ...
   environment:
      - NODE_VERSION=22
```

{% hint style="danger" %}
Please keep in mind, if you start a container with an **invalid Node version**, then it will crash.\
Please see this page for more: [Releases and Versions](/dockware-web/releases-and-versions)
{% endhint %}

### Runtime Switch

You can also switch your Node version at runtime, while the container is running.\
Navigate to **/var/www**, there we have prepared a **makefile** for you with various commands, such as `switch-node` that you can use in this case.

```bash
cd /var/www && make switch-node version=22
```

## Supervisor

The image has a built-in Supervisor installed.

Supervisor is a **process control system** that allows you to manage and monitor long-running processes on Unix-based systems. It runs as a daemon, **ensuring** that specified programs **start**, **stop**, and **restart** as needed, making it useful for managing background services in production environments.

You can easily use Supervisor by setting the ENV variable in your `docker run` command or in your **docker-compose.yml** file.

```bash
environment:
    - SUPERVISOR_ENABLED=1
```

Now you only need to mount a configuration file into the following location:

```
/etc/supervisor/supervisord.conf
```

And that's it, if you start your container, Supervisor is already started and ensures the commands provided in your configuration are correctly executed.

We recommend checking out the documentation of Supervisor, but here is a short sample configuration. It makes sure to always start 2 processes that consume your message queue.

```systemd
[program:my-worker-process]
process_name=%(program_name)s_%(process_num)02d
command=bin/console messenger:consume async
directory=/var/www/html
user=www-data
group=www-data
numprocs=2
autostart=true
autorestart=true
stdout_logfile=/var/log/worker.out.log
stderr_logfile=/var/log/worker.err.log
```

## Conjobs

The image includes built-in support for Cronjobs.

Cron is a **time-based job schedule**r in Unix-based systems that allows you to automate tasks by running scripts or commands at **scheduled intervals**. It is commonly used for repetitive tasks like backups, log rotation, or scheduled updates.

The cron service is **already started** in containers. So you just need to **add your scheduled tasks** to it and you're good to go.

You can of course do that manually (please see the cron documentation). But you can also automate setups. Here is a sample for a Shopware command - we create a file **my-project.txt**:

```bash
*/5 * * * * cd /var/www/html && php bin/console scheduled-task:run > /dev/null 2>&1
```

The command runs our scheduled tasks every 5 minutes.

Now we just need to **mount** or **copy** that file into the container and **add it to our cron service**.

```bash
docker exec -it container bash -c 'crontab /var/www/my-project.txt && sudo service cron restart'
```

That's it, all your tasks from my-project.txt are now automatically executed in the container.

## Filebeat

The image includes built-in support for Filebeat.

Filebeat is a **lightweight log shipper** that collects and forwards **log files** to Elasticsearch, Logstash, or other destinations. It is designed to run on servers, monitoring log files in real-time and efficiently transferring the data for analysis.

You can easily use Filebeat by setting the ENV variable in your `docker run` command or in your **docker-compose.yml** file.

```
environment:
    - FILEBEAT_ENABLED=1
```

Now you only need to mount a configuration file into the following location:

```
/etc/filebeat/filebeat.yml
```

And that's it, if you start your container, Filebeat is already started and collecting logs from the watched files according to your configuration.

We recommend checking out the documentation of Filebeat, but here is a short sample configuration. It watches log files in a **directory**, adds a **tag** "shop" to every line and sends the whole line to **logstash:5044**.

```bash
name: "shop"

filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/www/html/var/log/*.log
    tags: ["shop"]

output.logstash:
  hosts: ["logstash:5044"]
```

## Custom SSH/SFTP User

The image comes with a built-in SFTP service.

You can easily create a custom user for SFTP/SSH access by setting the following ENV variables in your `docker run` command or in your **docker-compose.yml** file.

```
environment:
    - SSH_USER=shopware
    - SSH_PWD=mypwd
```

{% hint style="info" %}
If you don't need this, please refer to the default SSH credentials: [Default Credentials](/dockware-web/default-credentials)
{% endhint %}

## Tideways

The image comes with Tideways installed.

Tideways is a **PHP performance monitoring and profiling tool** designed to help developers analyze and optimize application performance. It provides detailed insights into execution times, database queries, and bottlenecks, making it easier to debug slow requests and improve overall efficiency.

Once enabled, Tideways collects real-time performance data and can be integrated with Tideways.io for deeper analytics and monitoring in production environments.

You can easily enable Tideways by setting the following ENV variable in your `docker run` command or in your **docker-compose.yml** file.

<pre><code><strong>environment:
</strong>    - TIDEWAYS_KEY=my-tideways-key
</code></pre>

By default, Tideways is configured with defaults for environment and service names. You can customize these using additional ENV variables:

Required:

* TIDEWAYS\_KEY - Your Tideways API key. Setting this activates Tideways. (Default: not-set)

Optional:

* TIDEWAYS\_ENVIRONMENT - Environment name for web (FPM) requests. (Default: production)
* TIDEWAYS\_SERVICE - Service name for web (FPM) requests. (Default: app)

## Xdebug

This image comes with an easy Xdebug solution.\
As you may know, sometimes Xdebug can be a bit tricky, so follow these simple to get it up and running.

### Step-by-Step

{% stepper %}
{% step %}

#### Enable Xdebug

You can either enable Xdebug initially by setting the **ENV variable** `XDEBUG_ENABLED` to 1 (ON) or 0 (OFF) or by executing the **following command** at runtime:

```bash
# turn ON
cd /var/www && make xdebug-on
# turn OFF
cd /var/www && make xdebug-off
```

{% endstep %}

{% step %}

#### Browser Extension

Install a browser extension, that sets the required headers in requests.\
Here is a Chrome Extension: <https://chromewebstore.google.com/detail/xdebug-chrome-extension/oiofkammbajfehgpleginfomeppgnglk?hl=de>

Install it and activate it in your browser.
{% endstep %}

{% step %}

#### Listen in IDE

In most IDEs, you need to activate Xdebug or enable listening for Xdebug connections. Once activated, the next request from your browser extension should automatically trigger a breakpoint.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
That's it. This is how easy Xdebug can be
{% endhint %}

{% hint style="danger" %}
As Xdebug will slow down your dev environment for every request and also for each command like "cache:clear, watch-storefront" etc, you might not want to enable it all the time.
{% endhint %}

### Xdebug with API Clients

You might want to debug your API requests or other requets in clients without the Xdebug browser extensions.

Simply append `XDEBUG_SESSION_START=PHPSTORM` as a GET parameter to your URL, and Xdebug will attach to the request. Most IDEs listen for incoming sessions regardless of the name, but if needed, adjust the value according to your IDE settings

### Advanced Configuration

We do also have additional environment variables, that you can use for further configuration. Please see our section about [Environment Variables](/dockware-web/environment-variables)for more.

#### Remote Host

Both MAC and Windows have a Docker variable `host.docker.internal` available. This has been used by us as **default value** for the **Xdebug Remote Host.** Because that variable exists, this automatically uses the dynamic internal IP of your containers on MAC and Windows, and therefore it's indeed plug'n'play.

For **Linux** however this does not work! Please use **172.17.0.1** this as ENV variable to make it work! Here is a sample for a docker-compose.yml:

```bash
environment:
    - XDEBUG_REMOTE_HOST=172.17.0.1
```

If you use docker on **Windows with WSL2** you have to set your local ip address from the host in this ENV variable. Here is a sample for a docker-compose.yml:

```bash
environment:
    - XDEBUG_REMOTE_HOST=192.168.178.42
```

## Custom Timezone

You can adjust custom timezones for both the **operating system** as well as **PHP** by setting the following ENV variables. Dockware will automatically adjust settings and PHP configurations accordingly when you boot the image, or when you switch PHP versions.

```bash
environment:
    - TZ=Europe/Berlin
```

## Recovery Mode

If somehow anything goes wrong, and you need to acceess internal files of your existing containers, you can just start them with recovery mode enabled.

This will skip everything in the entrypoint, such as PHP and Node preparations, timezones and more.

```bash
environment:
    - RECOVERY_MODE=1
```

## Custom Apache DocRoot

The default Apache DocRoot is `/var/www/html`.

However, in some cases you might want to change this. You can easily do this by setting a specific configuration using the corresponding ENV variable.

```bash
environment:
    - APACHE_DOCROOT=/var/www/vhosts/my-website/html
```

## Running in CI/CD

If you run containers with `DOCKWARE_CI=1` the containers will automatically **quit** after running your command.

{% hint style="warning" %}
Please note, our containers should usually automatically exit, once a custom command is provided. This is just a fallback if they do not exit as expected. So use this only if it doesn't work for any reason.
{% endhint %}

```bash
environment:
    - DOCKWARE_CI=1
```

## Health Checks

Our images provide a built-in health check since version ≥ 1.3.0 to make life easier for you.\
\
We provide plenty of options in the way how containers are started. Different PHP versions, extensions and way more. This means, sometimes it might take a few seconds longer, until your container is fully launched.

If your workflows (e.g. CI pipelines) rely on a fully launched container, this meant that you needed to add custom **sleep** or **wait** commands in the history. This was not perfect and sometimes a bit fragile.

We now support the **Docker Health Check** feature by providing a custom built-in check, that marks the container as healthy as soon as everything has been completed in the boot scripts.

By using a simple **--wait** in your *docker-compose* command, Docker will automatically wait until your container is healthy. This means, you don't need manual sleeps or other approaches anymore.

```bash
docker compose up -d --wait
```

If you use **docker run**, **--wait** is not supported, but you can use this simple line after starting the container, to get the same results (please adjust your container name).

```bash
until [ "$$(docker inspect -f '{{.State.Health.Status}}' my-container-name)" = "healthy" ]; do sleep 1; done
```


# Customize Image

There can be times when you want to modify your dockware image without really changing the image itself. This can happen if you just need to install an additional package, or maybe adjust a few file permissions or anything else during the launch of the container.

This is possible with 2 different approaches:

* Inject Script in Entrypoint
* Custom Build from Dockware

## Inject Script in Entrypoint

The latest versions of dockware images allow you to inject your custom script in the boot entrypoint of the dockware image.

It's possible to either get yourself into the beginning of the entrypoint, or in the end of the script.

For this, you either need to mount or create a file `/var/www/boot_start.sh` or `/var/www/boot_end.sh` before starting your image. If either of these files exist, they will be executed in the beginning or at the end of the dockware entrypoint script.

Here's an example of a custom boot\_start.sh file:

{% code title="boot\_start.sh" %}

```bash
# change our user to something else than UID 33. 
# this also proves we can use sudo
sudo sed -i 's/dockware:x:33:33:/dockware:x:7788:33:/g' /etc/passwd
```

{% endcode %}

Now mount the file into your container:

{% code title="docker-compose.yml" %}

```yaml
  shop:
    image: dockware/web:latest
    volumes:
      - "./boot_start.sh:/var/www/boot_start.sh"
```

{% endcode %}

If you now start your Docker container, it should execute your custom script before it will continue with the original entrypoint of dockware.

If you want to see what it does, just use the `docker logs` command.

## Custom Build from Dockware

The approach above will execute your script every time the container is being started.\
But what if you want to adjust different packages - do you really want to install them over and over again?

Probably not ;)

In this case, you might want to use the default Docker feature to build a new image on the fly.\
With this, your custom code is executed only once, which leads to a new local image that will be created. When you start your container a second time, it will reuse the built image and immediately start the container.

This is perfect, if you only need a few adjustments of dockware (maybe just for 1 single customer project).

To start, please adjust your `docker-compose.yml` to use **build** instead of an **image** and point to a local directory that we will create next.

{% code title="docker-compose.yml" %}

```yaml
shop:
  build: ./custom
  ....
```

{% endcode %}

Now create a new folder `custom` in the same directory and place a file `Dockerfile` in it.\
This is a plain Dockerfile and can do everything usual Dockerfiles can do.

In this example, we simply inherit from the latest dockware "**web**" image and install a new package to your image:

{% code title="Dockerfile" %}

```bash
FROM dockware/web:latest

sudo apt-get update
sudo apt-get install -y ....my package....
```

{% endcode %}

{% hint style="success" %}
That's it.\
You can now start your docker setup. It will start building your custom image the first time you launch it, and will reuse the built one every other startup.
{% endhint %}

If you ever want to rebuild your image without deleting it before, just use this command:

```
docker-compose build
```

## Samples

### Old Node Version + Yarn

Let's imagine you want to install Node 18. You can easily do this by using the boot\_start.sh script (or also a custom build as described above).

This sample also shows how to install Yarn. This is bound to the selected Node version, so we switch to it, and then install Yarn afterwards.

{% code title="boot\_start.sh" %}

```bash
#!/bin/bash

# this is required to load nvm 
. /var/www/.nvm/nvm.sh

nvm install 18
nvm use 18
npm install -g yarn
```

{% endcode %}

Now simply create your Docker setup, mount the boot\_start.sh and if you prefer, also automatically switch to our new Node version on startups.

{% code title="docker-compose.yml" %}

```yaml
  shop:
    image: dockware/web:latest
    volumes:
      - "./boot_start.sh:/var/www/boot_start.sh"
    environment:
      - NODE_VERSION=18
```

{% endcode %}


# Environment Variables

Here is a full list of all available environment variables.

###

## APACHE\_DOCROOT

{% hint style="success" %}
Default: /var/www/html
{% endhint %}

Sets the default DocRoot of Apache

## DOCKWARE\_CI

If you run containers with DOCKWARE\_CI=1 the containers will automatically quit after running your command. Use this if you use dockware as command runner in your CI/CD system. Please note, your containers should automatically exit once a custom command is provided. This is just fa fallback if they do not exit as expected.

## NODE\_VERSION

Switch to a different Node version (12 | 14 | 16)

## PHP\_VERSION

Switch to any of the installed PHP versions: 8.0, 7.4, 7.3, 7.2

## RECOVERY\_MODE

{% hint style="success" %}
Default: 0
{% endhint %}

If enabled, nothing will be done in the entrypoint when booting dockware. This allows you to access the container on problems.

## TZ

{% hint style="success" %}
Default: Europe/Berlin
{% endhint %}

Provide a custom timezone for the container

This one is used for the operating system, but also for the corresponding PHP configuration.

### Users

| Feature     | Variable    | Default | Description                                                                          |
| ----------- | ----------- | ------- | ------------------------------------------------------------------------------------ |
| SSH USERS   | SSH\_USER   | not-set | Name of the optional new SSH user that replaces the existing one from dockware       |
|             | SSH\_PWD    | not-set | Password of the optional new SSH user that replaces the existing one from dockware   |
| MYSQL USERS | MYSQL\_USER | not-set | Optional variable to create a separate MySQL user. This is the name of the user.     |
|             | MYSQL\_PWD  | not-set | Optional variable to create a separate MySQL user. This is the password of the user. |

### Debugging

| Feature  | Variable             | Default              | Description                                                                                                                                           |
| -------- | -------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| XDEBUG   | XDEBUG\_ENABLED      | 0                    | Enable or disable XDebug with either 1 or 0 as value.                                                                                                 |
|          | XDEBUG\_REMOTE\_HOST | host.docker.internal | Use default value for MAC + Windows, and 172.17.0.1 for Linux                                                                                         |
|          | XDEBUG\_CONFIG       | idekey=PHPSTORM      | IDE Key identifier for XDebug                                                                                                                         |
|          | PHP\_IDE\_CONFIG     | serverName=localhost | used for the serverName export for XDebug usage on CLI                                                                                                |
| TIDEWAYS | TIDEWAYS\_KEY        | not-set              | API Key of the Tideways project                                                                                                                       |
|          | TIDEWAYS\_ENV        | production           | Optional identifier of the environment                                                                                                                |
|          | TIDEWAYS\_SERVICE    | web                  | Optional identifier of the service                                                                                                                    |
| FILEBEAT | FILEBEAT\_ENABLED    | 0                    | Activates the Filebeat daemon service (value 1). For this please provide a manual filebeat.yml for the container. You can do this with bind-mounting. |


# Default Credentials

## SSH/SFTP

User: **dockware**\
Password: **dockware**\
Port: **22**\
\
Please note, that you need to make the port available to your host machine.

##


# Releases and Versions

## Releases and Versions

This image has two main types of releases:

1. **Nightly Builds**: Available with the tag `dev-main`.
2. **Stable Versions**: Versioned releases like `2.0.0`, `2.0.1`, etc.

Check the `CHANGELOG.md` file for details on all changes and updates.


# Getting Started


# Environment Variables


# Versions and Releases


# Getting Started

It's finally time to start your first Shopware 6 with dockware.\
For this we use the **dockware/shopware** image, which brings everything you need to simply start and explore Shopware 6.

{% hint style="warning" %}
Please keep in mind, that we only (for now) build Shopware versions starting from 6.7 with the new dockware/shopware image. For old versions please use the dockware/dev or dockware/play images. They will continue to work.
{% endhint %}

\
**Run Shopware 6 with latest version**

```bash
docker run --rm -p 80:80 dockware/shopware:latest
```

The dockware image will be downloaded the first time you run this command. Upcoming starts will not download it again, and will be much faster.

As soon as dockware is ready, you will see an output that shows you all available URLs.

That's it - give it a try!

```bash
** DOCKWARE IMAGE: dockware/shopware
** Tag: 6.7.2.1
** Built: Tue Jan  5 13:17:36 UTC 2021
** Copyright 2025 dasistweb GmbH
*******************************************************

launching dockware...please wait...

DOCKWARE: setting timezone to Europe/Berlin...

Current default time zone: 'Europe/Berlin'
Local time is now:      Fri Jan 29 07:39:40 CET 2021.
Universal Time is now:  Fri Jan 29 06:39:40 UTC 2021.

-----------------------------------------------------------
DOCKWARE: starting MySQL....
 * Starting MySQL database server mysqld
   ...done.
-----------------------------------------------------------
DOCKWARE: starting mailcatcher....
Starting MailCatcher
==> smtp://0.0.0.0:1025
==> http://0.0.0.0:1080/
*** MailCatcher runs as a daemon by default. Go to the web interface to quit.
-----------------------------------------------------------
DOCKWARE: starting cron service....
 * Starting periodic command scheduler cron
   ...done.
-----------------------------------------------------------
DOCKWARE: switching to PHP 8.4...
-----------------------------------------------------------
DOCKWARE: testing and starting Apache...
Syntax OK
 * Restarting Apache httpd web server apache2
   ...done.
-----------------------------------------------------------

WOHOOO, dockware/play:6.7.2.1 IS READY :) - let's get started
-----------------------------------------------------
DOCKWARE CHANGELOG: /var/www/CHANGELOG.md
PHP: PHP 8.4 (cli) (built: Nov 28 2020 06:24:43) ( NTS )
Apache DocRoot: /var/www/html/public
ADMINER URL: http://localhost/adminer.php
MAILCATCHER URL: http://localhost/mailcatcher
PIMPMYLOG URL: http://localhost/logs
SHOP URL: http://localhost
ADMIN URL: http://localhost/admin

What's new in this version? see the changelog for further details
https://www.shopware.com/de/changelog/

```

{% hint style="warning" %}
Attention!\
If you use a https connection and chrome as browser, it might block your connection to <https://localhost>. This can be easily changed by following [these steps](broken://pages/-MSBsEoJvwJfXf3GtnGc) from our FAQ.
{% endhint %}

There are also other ways to start a Shopware 6 shop.

**Run Shopware 6 with specific version**

```bash
docker run --rm -p 80:80 dockware/shopware:6.7.2.1
```

**Run Shopware 6 with another PHP version**

```bash
docker run --rm -p 80:80 --env PHP_VERSION=8.3 dockware/shopware:latest
```

{% hint style="success" %}
If you are looking for passwords and default credentials of Shopware and dockware, please take a look at this page: [Default Credentials](/dockware-shopware/default-credentials)
{% endhint %}

### Tutorial Video available

Watch our short video about starting and exploring [Shopware 6 with dockware.](https://youtu.be/2gb8KHdGI6s)

![Shopware 6 with dockware video](/files/-MSBuBK7AZHr3IQrSIFX)

<br>


# Features

This image offers a variety of features that can be utilized both at startup and while it’s running. You can configure key settings when launching the container.

Many features can also be adjusted dynamically during runtime.

## PHP Version

We've included multiple PHP versions in this image. So you can easily configure what you need in your specific project, without having to download lots of different images.

### Start with PHP version

If you want to start a container with a specific PHP version, just provide the **environment variable** either in the `docker run` command or within your **docker-compose.yml** file.

```bash
docker run -e PHP_VERSION=8.4 dockware/shopware:latest
```

```yaml
app:
   image: dockware/shopware:latest
   ...
   environment:
      - PHP_VERSION=8.4
```

{% hint style="danger" %}
Please keep in mind, if you start a container with an **invalid PHP version**, then it will crash.\
Just run it without a provided PHP version and navigate to **/etc/php** to see what is installed.\
Please see this page for more: [Releases and Versions](/dockware-web/releases-and-versions)
{% endhint %}

### Runtime Switch

You can also switch your PHP version at runtime, while the container is running.\
Navigate to **/var/www**, there we have prepared a **makefile** for you with various commands, such as `switch-php` that you can use in this case.

```bash
cd /var/www && make switch-php version=8.2
```

The command has been designed to be as **robust as possible**. This means, that nothing should break if you switch to the same PHP version, or even a version that is not supported and existing in the current image you use.

{% embed url="<https://www.youtube.com/watch?v=LGukxv72Nm4>" fullWidth="false" %}
Watch our video about switching while using "docker run"
{% endembed %}

{% embed url="<https://www.youtube.com/watch?v=E8tmkLabSBc>" %}
Watch our video about switching with your docker-compose.yml
{% endembed %}

## Node Version

We've included multiple Node versions in this image. So you can easily configure what you need in your specific project, without having to download lots of different images.

### Start with Node version

If you want to start a container with a specific Node version, just provide the **environment variable** either in the `docker run` command or within your **docker-compose.yml** file.

```bash
docker run -e NODE_VERSION=22 dockware/shopware:latest
```

```yaml
app:
   image: dockware/shopware:latest
   ...
   environment:
      - NODE_VERSION=22
```

{% hint style="danger" %}
Please keep in mind, if you start a container with an **invalid Node version**, then it will crash.\
Please see this page for more: [Releases and Versions](/dockware-web/releases-and-versions)
{% endhint %}

### Runtime Switch

You can also switch your Node version at runtime, while the container is running.\
Navigate to **/var/www**, there we have prepared a **makefile** for you with various commands, such as `switch-node` that you can use in this case.

```bash
cd /var/www && make switch-node version=22
```

## Supervisor

The image has a built-in Supervisor installed.

Supervisor is a **process control system** that allows you to manage and monitor long-running processes on Unix-based systems. It runs as a daemon, **ensuring** that specified programs **start**, **stop**, and **restart** as needed, making it useful for managing background services in production environments.

You can easily use Supervisor by setting the ENV variable in your `docker run` command or in your **docker-compose.yml** file.

```bash
environment:
    - SUPERVISOR_ENABLED=1
```

Now you only need to mount a configuration file into the following location:

```
/etc/supervisor/supervisord.conf
```

And that's it, if you start your container, Supervisor is already started and ensures the commands provided in your configuration are correctly executed.

We recommend checking out the documentation of Supervisor, but here is a short sample configuration. It makes sure to always start 2 processes that consume your message queue.

```systemd
[program:my-worker-process]
process_name=%(program_name)s_%(process_num)02d
command=bin/console messenger:consume async
directory=/var/www/html
user=www-data
group=www-data
numprocs=2
autostart=true
autorestart=true
stdout_logfile=/var/log/worker.out.log
stderr_logfile=/var/log/worker.err.log
```

## Conjobs

The image includes built-in support for Cronjobs.

Cron is a **time-based job schedule**r in Unix-based systems that allows you to automate tasks by running scripts or commands at **scheduled intervals**. It is commonly used for repetitive tasks like backups, log rotation, or scheduled updates.

The cron service is **already started** in containers. So you just need to **add your scheduled tasks** to it and you're good to go.

You can of course do that manually (please see the cron documentation). But you can also automate setups. Here is a sample for a Shopware command - we create a file **my-project.txt**:

```bash
*/5 * * * * cd /var/www/html && php bin/console scheduled-task:run > /dev/null 2>&1
```

The command runs our scheduled tasks every 5 minutes.

Now we just need to **mount** or **copy** that file into the container and **add it to our cron service**.

```bash
docker exec -it container bash -c 'crontab /var/www/my-project.txt && sudo service cron restart'
```

That's it, all your tasks from my-project.txt are now automatically executed in the container.

## Filebeat

The image includes built-in support for Filebeat.

Filebeat is a **lightweight log shipper** that collects and forwards **log files** to Elasticsearch, Logstash, or other destinations. It is designed to run on servers, monitoring log files in real-time and efficiently transferring the data for analysis.

You can easily use Filebeat by setting the ENV variable in your `docker run` command or in your **docker-compose.yml** file.

```
environment:
    - FILEBEAT_ENABLED=1
```

Now you only need to mount a configuration file into the following location:

```
/etc/filebeat/filebeat.yml
```

And that's it, if you start your container, Filebeat is already started and collecting logs from the watched files according to your configuration.

We recommend checking out the documentation of Filebeat, but here is a short sample configuration. It watches log files in a **directory**, adds a **tag** "shop" to every line and sends the whole line to **logstash:5044**.

```bash
name: "shop"

filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/www/html/var/log/*.log
    tags: ["shop"]

output.logstash:
  hosts: ["logstash:5044"]
```

## Custom SSH/SFTP User

The image comes with a built-in SFTP service.

You can easily create a custom user for SFTP/SSH access by setting the following ENV variables in your `docker run` command or in your **docker-compose.yml** file.

```
environment:
    - SSH_USER=shopware
    - SSH_PWD=mypwd
```

{% hint style="info" %}
If you don't need this, please refer to the default SSH credentials: [Default Credentials](/dockware-web/default-credentials)
{% endhint %}

## Tideways

The image comes with Tideways installed.

Tideways is a **PHP performance monitoring and profiling tool** designed to help developers analyze and optimize application performance. It provides detailed insights into execution times, database queries, and bottlenecks, making it easier to debug slow requests and improve overall efficiency.

Once enabled, Tideways collects real-time performance data and can be integrated with Tideways.io for deeper analytics and monitoring in production environments.

You can easily enable Tideways by setting the following ENV variable in your `docker run` command or in your **docker-compose.yml** file.

<pre><code><strong>environment:
</strong>    - TIDEWAYS_KEY=my-tideways-key
</code></pre>

## Xdebug

This image comes with an easy Xdebug solution.\
As you may know, sometimes Xdebug can be a bit tricky, so follow these simple to get it up and running.

### Step-by-Step

{% stepper %}
{% step %}

#### Enable Xdebug

You can either enable Xdebug initially by setting the **ENV variable** `XDEBUG_ENABLED` to 1 (ON) or 0 (OFF) or by executing the **following command** at runtime:

```bash
# turn ON
cd /var/www && make xdebug-on
# turn OFF
cd /var/www && make xdebug-off
```

{% endstep %}

{% step %}

#### Browser Extension

Install a browser extension, that sets the required headers in requests.\
Here is a Chrome Extension: <https://chromewebstore.google.com/detail/xdebug-chrome-extension/oiofkammbajfehgpleginfomeppgnglk?hl=de>

Install it and activate it in your browser.
{% endstep %}

{% step %}

#### Listen in IDE

In most IDEs, you need to activate Xdebug or enable listening for Xdebug connections. Once activated, the next request from your browser extension should automatically trigger a breakpoint.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
That's it. This is how easy Xdebug can be
{% endhint %}

{% hint style="danger" %}
As Xdebug will slow down your dev environment for every request and also for each command like "cache:clear, watch-storefront" etc, you might not want to enable it all the time.
{% endhint %}

### Xdebug with API Clients

You might want to debug your API requests or other requets in clients without the Xdebug browser extensions.

Simply append `XDEBUG_SESSION_START=PHPSTORM` as a GET parameter to your URL, and Xdebug will attach to the request. Most IDEs listen for incoming sessions regardless of the name, but if needed, adjust the value according to your IDE settings

### Advanced Configuration

We do also have additional environment variables, that you can use for further configuration. Please see our section about [Environment Variables](/dockware-web/environment-variables)for more.

#### Remote Host

Both MAC and Windows have a Docker variable `host.docker.internal` available. This has been used by us as **default value** for the **Xdebug Remote Host.** Because that variable exists, this automatically uses the dynamic internal IP of your containers on MAC and Windows, and therefore it's indeed plug'n'play.

For **Linux** however this does not work! Please use **172.17.0.1** this as ENV variable to make it work! Here is a sample for a docker-compose.yml:

```bash
environment:
    - XDEBUG_REMOTE_HOST=172.17.0.1
```

If you use docker on **Windows with WSL2** you have to set your local ip address from the host in this ENV variable. Here is a sample for a docker-compose.yml:

```bash
environment:
    - XDEBUG_REMOTE_HOST=192.168.178.42
```

## Custom Timezone

You can adjust custom timezones for both the **operating system** as well as **PHP** by setting the following ENV variables. Dockware will automatically adjust settings and PHP configurations accordingly when you boot the image, or when you switch PHP versions.

```bash
environment:
    - TZ=Europe/Berlin
```

## Recovery Mode

If somehow anything goes wrong, and you need to acceess internal files of your existing containers, you can just start them with recovery mode enabled.

This will skip everything in the entrypoint, such as PHP and Node preparations, timezones and more.

```bash
environment:
    - RECOVERY_MODE=1
```

## Custom Apache DocRoot

The default Apache DocRoot is `/var/www/html`.

However, in some cases you might want to change this. You can easily do this by setting a specific configuration using the corresponding ENV variable.

```bash
environment:
    - APACHE_DOCROOT=/var/www/vhosts/my-website/html
```

## Running in CI/CD

If you run containers with `DOCKWARE_CI=1` the containers will automatically **quit** after running your command.

{% hint style="warning" %}
Please note, our containers should usually automatically exit, once a custom command is provided. This is just a fallback if they do not exit as expected. So use this only if it doesn't work for any reason.
{% endhint %}

```bash
environment:
    - DOCKWARE_CI=1
```

## Inject Bootstrap Script

You can inject a custom script that will be executed on **container boot**. This can either be at the **start** or the **end** of the boot process.

Mount any Shell script to the following paths:

* `/var/www/boot_start.sh`
* `/var/www/boot_end.sh`

If dockware detects a script at these paths, it will execute them accordingly.

## Shopware Currency

The default currency of a Shopware installation is EUR.\
This can only be changed when running the installation wizard of Shopware.

With dockware we provide a way to switch the default currency also for existing Shopware 6 shops.

Use the ENV variable **SW\_CURRENCY** with an existing ISO currency value.

```yaml
environment:
   - SW_CURRENCY=GBP
```

This will not only change the default currency for the system to the selected currency, but also recalculate the factors. Your new default currency gets the base factor 1.0, and all other currencies will be calculated based on the new default.

Thanks to [Shyim](https://github.com/shyim) for helping with this ;)

## Health Checks

Our images provide a built-in health check since version ≥ 1.3.0 to make life easier for you.\
\
We provide plenty of options in the way how containers are started. Different PHP versions, extensions and way more. This means, sometimes it might take a few seconds longer, until your container is fully launched.

If your workflows (e.g. CI pipelines) rely on a fully launched container, this meant that you needed to add custom **sleep** or **wait** commands in the history. This was not perfect and sometimes a bit fragile.

We now support the **Docker Health Check** feature by providing a custom built-in check, that marks the container as healthy as soon as everything has been completed in the boot scripts.

By using a simple **--wait** in your *docker-compose* command, Docker will automatically wait until your container is healthy. This means, you don't need manual sleeps or other approaches anymore.

```bash
docker compose up -d --wait
```

If you use **docker run**, **--wait** is not supported, but you can use this simple line after starting the container, to get the same results (please adjust your container name).

```bash
until [ "$$(docker inspect -f '{{.State.Health.Status}}' my-container-name)" = "healthy" ]; do sleep 1; done
```


# Watchers

If you are either working on the storefront or the administration you might want to use the watchers for it.\
These will make sure to compile everything as soon as new changes and file modifications have been recognized.\
You only need to reload your browser and all changes are visible immediately.\
\
Because the watchers are not very dev-friendly sometimes, we've prepared a small little makefile for you.\
It's outside the DocRoot in the directory **/var/www**

```bash
cd /var/www
make
```

```bash
watch-storefront               #Starts watcher for storefront at http://localhost:9998
        
watch-admin                    #Starts watcher for admin at http://localhost:5173
```

### **Admin Watcher**

* **Ports**\
  You need to expose the correct ports of your Docker container.\
  Please expose the port "**5173**"".<br>
* **Start Make Command**\
  Connect into your container and navigate to the folder "/var/www".\
  This prepared makefile contains a command to start the admin watcher.<br>
* **Open Browser**\
  If the make command has finished, your watcher should be ready.\
  Just open the URL in your browser and you should see the administration.\
  Please keep in mind, that different Shopware versions require different URLs to be used.\
  [http://localhost:5173](http://localhost:5173/)

\
As soon as you modify any files in the administration and upload them to the container, the watcher will recognize the changes, and compile the app again. In addition to this, it will also automatically refresh your browser (Hot Module Replacement).\
\
To stop the watcher, simply cancel the command / process.

### **Storefront Watcher**

The watcher for the storefront requires a few things to be set.\
Follow this simple guide to get started.

1. **Ports**\
   You need to expose the correct ports of your Docker container.\
   Please expose the ports "**9999**" and "**9998**".\
   The easiest way is to just expose them directly with "9999:9999" and "9998:9998" in your Docker setup.<br>
2. **Start Make Command**\
   Connect into your container and navigate to the folder "/var/www".\
   This prepared makefile contains a command to start the storefront watcher.<br>
3. **Open Browser**\
   If the make command has finished, your watcher should be ready.\
   Just open the URL in your browser and you should see that the CSS styles are loaded in a lazy way. That means it is working.\
   Please keep in mind, that different Shopware versions require different URLs to be used.\
   <http://localhost:9998>

<br>


# Environment Variables


# Default Credentials

## SSH/SFTP

User: **dockware**\
Password: **dockware**\
Port: **22**\
\
Please note, that you need to make the port available to your host machine.

## Shopware 6 Admin

User: **admin**\
Password: **shopware**

## MySQL

These work for SQL clients as well as for the built-in Adminer application.

User: **root**\
Password: **root**\
Host: **127.0.0.1** (not localhost)\
Port: **3306**\
\
Please note, that you need to make the port available to your host machine.

## Mailcatcher

Host: **localhost**\
Port: **1025**

##


# Releases and Versions

### Releases and Versions

This project follows two different approaches for versioning:

* **dockware/shopware:**

  Instead of semantic versioning, this image uses the Docker tag to represent the Shopware version. This allows you to simply pull any supported Shopware 6 version as a tag, and you will always get the correct image with the correct Shopware release.\
  Pushed images are not modified anymore. If, for some reason, we might need to fix existing Shopware images, a suffix is appended to the tag.

```
dockware/shopware:6.7.2.1
dockware/shopware:6.7.2.1-v2
```

* **dockware/shopware-essentials:**

  This base image uses semantic versioning. It will be updated whenever relevant changes are made in the operating system or packages. Any Shopware versions built afterward will automatically include these updates.

```
dockware/shopware-essentials:1.0.0
```

***

### Essentials-First Strategy

As outlined in the **CHANGELOG.md**, the primary focus is on the *shopware-essentials* image.

Every change in its features or setup results in a new changelog entry. The bundled Shopware installation is treated as an addon on top of this essentials image.


# Getting Started

If you bring your own Shopware source code, you can either use this single image, or (of course) use the dockware/web container and additional containers for MySQL and more.

The benefit with this image is, that it brings a full environment for Shopware, in a single image.

```bash
docker run --rm -p 80:80 dockware/shopware-essentials:latest
```

**Run Shopware 6 with another PHP version**

You can of course use different features such as PHP version switching, Node version switching and more.

```bash
docker run --rm -p 80:80 --env PHP_VERSION=8.3 dockware/shopware:latest
```

{% hint style="success" %}
If you are looking for passwords and default credentials of Shopware and dockware, please take a look at this page: [Default Credentials](/dockware-shopware-essentials/default-credentials)
{% endhint %}

![Shopware 6 with dockware video](/files/-MSBuBK7AZHr3IQrSIFX)

<br>


# Features

This image offers a variety of features that can be utilized both at startup and while it’s running. You can configure key settings when launching the container.

Many features can also be adjusted dynamically during runtime.

## PHP Version

We've included multiple PHP versions in this image. So you can easily configure what you need in your specific project, without having to download lots of different images.

### Start with PHP version

If you want to start a container with a specific PHP version, just provide the **environment variable** either in the `docker run` command or within your **docker-compose.yml** file.

```bash
docker run -e PHP_VERSION=8.4 dockware/shopware:latest
```

```yaml
app:
   image: dockware/shopware:latest
   ...
   environment:
      - PHP_VERSION=8.4
```

{% hint style="danger" %}
Please keep in mind, if you start a container with an **invalid PHP version**, then it will crash.\
Just run it without a provided PHP version and navigate to **/etc/php** to see what is installed.\
Please see this page for more: [Releases and Versions](/dockware-web/releases-and-versions)
{% endhint %}

### Runtime Switch

You can also switch your PHP version at runtime, while the container is running.\
Navigate to **/var/www**, there we have prepared a **makefile** for you with various commands, such as `switch-php` that you can use in this case.

```bash
cd /var/www && make switch-php version=8.2
```

The command has been designed to be as **robust as possible**. This means, that nothing should break if you switch to the same PHP version, or even a version that is not supported and existing in the current image you use.

{% embed url="<https://www.youtube.com/watch?v=LGukxv72Nm4>" fullWidth="false" %}
Watch our video about switching while using "docker run"
{% endembed %}

{% embed url="<https://www.youtube.com/watch?v=E8tmkLabSBc>" %}
Watch our video about switching with your docker-compose.yml
{% endembed %}

## Node Version

We've included multiple Node versions in this image. So you can easily configure what you need in your specific project, without having to download lots of different images.

### Start with Node version

If you want to start a container with a specific Node version, just provide the **environment variable** either in the `docker run` command or within your **docker-compose.yml** file.

```bash
docker run -e NODE_VERSION=22 dockware/shopware:latest
```

```yaml
app:
   image: dockware/shopware:latest
   ...
   environment:
      - NODE_VERSION=22
```

{% hint style="danger" %}
Please keep in mind, if you start a container with an **invalid Node version**, then it will crash.\
Please see this page for more: [Releases and Versions](/dockware-web/releases-and-versions)
{% endhint %}

### Runtime Switch

You can also switch your Node version at runtime, while the container is running.\
Navigate to **/var/www**, there we have prepared a **makefile** for you with various commands, such as `switch-node` that you can use in this case.

```bash
cd /var/www && make switch-node version=22
```

## Supervisor

The image has a built-in Supervisor installed.

Supervisor is a **process control system** that allows you to manage and monitor long-running processes on Unix-based systems. It runs as a daemon, **ensuring** that specified programs **start**, **stop**, and **restart** as needed, making it useful for managing background services in production environments.

You can easily use Supervisor by setting the ENV variable in your `docker run` command or in your **docker-compose.yml** file.

```bash
environment:
    - SUPERVISOR_ENABLED=1
```

Now you only need to mount a configuration file into the following location:

```
/etc/supervisor/supervisord.conf
```

And that's it, if you start your container, Supervisor is already started and ensures the commands provided in your configuration are correctly executed.

We recommend checking out the documentation of Supervisor, but here is a short sample configuration. It makes sure to always start 2 processes that consume your message queue.

```systemd
[program:my-worker-process]
process_name=%(program_name)s_%(process_num)02d
command=bin/console messenger:consume async
directory=/var/www/html
user=www-data
group=www-data
numprocs=2
autostart=true
autorestart=true
stdout_logfile=/var/log/worker.out.log
stderr_logfile=/var/log/worker.err.log
```

## Conjobs

The image includes built-in support for Cronjobs.

Cron is a **time-based job schedule**r in Unix-based systems that allows you to automate tasks by running scripts or commands at **scheduled intervals**. It is commonly used for repetitive tasks like backups, log rotation, or scheduled updates.

The cron service is **already started** in containers. So you just need to **add your scheduled tasks** to it and you're good to go.

You can of course do that manually (please see the cron documentation). But you can also automate setups. Here is a sample for a Shopware command - we create a file **my-project.txt**:

```bash
*/5 * * * * cd /var/www/html && php bin/console scheduled-task:run > /dev/null 2>&1
```

The command runs our scheduled tasks every 5 minutes.

Now we just need to **mount** or **copy** that file into the container and **add it to our cron service**.

```bash
docker exec -it container bash -c 'crontab /var/www/my-project.txt && sudo service cron restart'
```

That's it, all your tasks from my-project.txt are now automatically executed in the container.

## Filebeat

The image includes built-in support for Filebeat.

Filebeat is a **lightweight log shipper** that collects and forwards **log files** to Elasticsearch, Logstash, or other destinations. It is designed to run on servers, monitoring log files in real-time and efficiently transferring the data for analysis.

You can easily use Filebeat by setting the ENV variable in your `docker run` command or in your **docker-compose.yml** file.

```
environment:
    - FILEBEAT_ENABLED=1
```

Now you only need to mount a configuration file into the following location:

```
/etc/filebeat/filebeat.yml
```

And that's it, if you start your container, Filebeat is already started and collecting logs from the watched files according to your configuration.

We recommend checking out the documentation of Filebeat, but here is a short sample configuration. It watches log files in a **directory**, adds a **tag** "shop" to every line and sends the whole line to **logstash:5044**.

```bash
name: "shop"

filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/www/html/var/log/*.log
    tags: ["shop"]

output.logstash:
  hosts: ["logstash:5044"]
```

## Custom SSH/SFTP User

The image comes with a built-in SFTP service.

You can easily create a custom user for SFTP/SSH access by setting the following ENV variables in your `docker run` command or in your **docker-compose.yml** file.

```
environment:
    - SSH_USER=shopware
    - SSH_PWD=mypwd
```

{% hint style="info" %}
If you don't need this, please refer to the default SSH credentials: [Default Credentials](/dockware-web/default-credentials)
{% endhint %}

## Tideways

The image comes with Tideways installed.

Tideways is a **PHP performance monitoring and profiling tool** designed to help developers analyze and optimize application performance. It provides detailed insights into execution times, database queries, and bottlenecks, making it easier to debug slow requests and improve overall efficiency.

Once enabled, Tideways collects real-time performance data and can be integrated with Tideways.io for deeper analytics and monitoring in production environments.

You can easily enable Tideways by setting the following ENV variable in your `docker run` command or in your **docker-compose.yml** file.

<pre><code><strong>environment:
</strong>    - TIDEWAYS_KEY=my-tideways-key
</code></pre>

## Xdebug

This image comes with an easy Xdebug solution.\
As you may know, sometimes Xdebug can be a bit tricky, so follow these simple to get it up and running.

### Step-by-Step

{% stepper %}
{% step %}

#### Enable Xdebug

You can either enable Xdebug initially by setting the **ENV variable** `XDEBUG_ENABLED` to 1 (ON) or 0 (OFF) or by executing the **following command** at runtime:

```bash
# turn ON
cd /var/www && make xdebug-on
# turn OFF
cd /var/www && make xdebug-off
```

{% endstep %}

{% step %}

#### Browser Extension

Install a browser extension, that sets the required headers in requests.\
Here is a Chrome Extension: <https://chromewebstore.google.com/detail/xdebug-chrome-extension/oiofkammbajfehgpleginfomeppgnglk?hl=de>

Install it and activate it in your browser.
{% endstep %}

{% step %}

#### Listen in IDE

In most IDEs, you need to activate Xdebug or enable listening for Xdebug connections. Once activated, the next request from your browser extension should automatically trigger a breakpoint.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
That's it. This is how easy Xdebug can be
{% endhint %}

{% hint style="danger" %}
As Xdebug will slow down your dev environment for every request and also for each command like "cache:clear, watch-storefront" etc, you might not want to enable it all the time.
{% endhint %}

### Xdebug with API Clients

You might want to debug your API requests or other requets in clients without the Xdebug browser extensions.

Simply append `XDEBUG_SESSION_START=PHPSTORM` as a GET parameter to your URL, and Xdebug will attach to the request. Most IDEs listen for incoming sessions regardless of the name, but if needed, adjust the value according to your IDE settings

### Advanced Configuration

We do also have additional environment variables, that you can use for further configuration. Please see our section about [Environment Variables](/dockware-web/environment-variables)for more.

#### Remote Host

Both MAC and Windows have a Docker variable `host.docker.internal` available. This has been used by us as **default value** for the **Xdebug Remote Host.** Because that variable exists, this automatically uses the dynamic internal IP of your containers on MAC and Windows, and therefore it's indeed plug'n'play.

For **Linux** however this does not work! Please use **172.17.0.1** this as ENV variable to make it work! Here is a sample for a docker-compose.yml:

```bash
environment:
    - XDEBUG_REMOTE_HOST=172.17.0.1
```

If you use docker on **Windows with WSL2** you have to set your local ip address from the host in this ENV variable. Here is a sample for a docker-compose.yml:

```bash
environment:
    - XDEBUG_REMOTE_HOST=192.168.178.42
```

## Custom Timezone

You can adjust custom timezones for both the **operating system** as well as **PHP** by setting the following ENV variables. Dockware will automatically adjust settings and PHP configurations accordingly when you boot the image, or when you switch PHP versions.

```bash
environment:
    - TZ=Europe/Berlin
```

## Recovery Mode

If somehow anything goes wrong, and you need to acceess internal files of your existing containers, you can just start them with recovery mode enabled.

This will skip everything in the entrypoint, such as PHP and Node preparations, timezones and more.

```bash
environment:
    - RECOVERY_MODE=1
```

## Custom Apache DocRoot

The default Apache DocRoot is `/var/www/html`.

However, in some cases you might want to change this. You can easily do this by setting a specific configuration using the corresponding ENV variable.

```bash
environment:
    - APACHE_DOCROOT=/var/www/vhosts/my-website/html
```

## Running in CI/CD

If you run containers with `DOCKWARE_CI=1` the containers will automatically **quit** after running your command.

{% hint style="warning" %}
Please note, our containers should usually automatically exit, once a custom command is provided. This is just a fallback if they do not exit as expected. So use this only if it doesn't work for any reason.
{% endhint %}

```bash
environment:
    - DOCKWARE_CI=1
```

## Inject Bootstrap Script

You can inject a custom script that will be executed on **container boot**. This can either be at the **start** or the **end** of the boot process.

Mount any Shell script to the following paths:

* `/var/www/boot_start.sh`
* `/var/www/boot_end.sh`

If dockware detects a script at these paths, it will execute them accordingly.

## Health Checks

Our images provide a built-in health check since version ≥ 1.3.0 to make life easier for you.\
\
We provide plenty of options in the way how containers are started. Different PHP versions, extensions and way more. This means, sometimes it might take a few seconds longer, until your container is fully launched.

If your workflows (e.g. CI pipelines) rely on a fully launched container, this meant that you needed to add custom **sleep** or **wait** commands in the history. This was not perfect and sometimes a bit fragile.

We now support the **Docker Health Check** feature by providing a custom built-in check, that marks the container as healthy as soon as everything has been completed in the boot scripts.

By using a simple **--wait** in your *docker-compose* command, Docker will automatically wait until your container is healthy. This means, you don't need manual sleeps or other approaches anymore.

```bash
docker compose up -d --wait
```

If you use **docker run**, **--wait** is not supported, but you can use this simple line after starting the container, to get the same results (please adjust your container name).

```bash
until [ "$$(docker inspect -f '{{.State.Health.Status}}' my-container-name)" = "healthy" ]; do sleep 1; done
```


# Watchers


# Environment Variables


# Default Credentials

## SSH/SFTP

User: **dockware**\
Password: **dockware**\
Port: **22**\
\
Please note, that you need to make the port available to your host machine.

## MySQL

These work for SQL clients as well as for the built-in Adminer application.

User: **root**\
Password: **root**\
Host: **127.0.0.1** (not localhost)\
Port: **3306**\
\
Please note, that you need to make the port available to your host machine.

## Mailcatcher

Host: **localhost**\
Port: **1025**

##


# Versions and Releases


# Getting Started

This is the official Shopware 6 Crowdin Docker image, powered by dockware.io.

It helps you to start the latest available Shopware 6 version with a prepared Crowdin installion for a seamlessly integrated translation experience.

Just start your Docker container, login to your existing Crowdin account and start translating Shopware 6 directly within your browser.

## Requirements

* You need to have Docker installed on your machine
* You need to have a Crowdin account provided by Shopware

## Using the image

### Start container

Start the container with the following command. This will automatically download the latest **dockware/crowdin** image from Docker Hub if not already existing locally.

```
docker run --name crowdin -p 80:80 -p 443:443 dockware/crowdin:latest
```

Congratulations, you can now open the Storefront at [http://localhost](http://localhost/) or the Administration at <http://localhost/admin>.

Sign in to Crowdin, select the language you want to translate and start translating. You can always change languages using the Crowdin overlay you see in your browser.

### Update and restart container

Every night a new image is being built. This means, you need to manually search and download the latest image from Docker Hub. Please note, you might not always need this. Only if new Shopware versions are released.

Run this command to update the image.

```
docker pull dockware/crowdin:latest 
```

If you have the container already running, you need to stop and remove it first. Just paste these 3 commands and it should all work automatically for you.

```
docker pull dockware/crowdin:latest
docker rm -f crowdin || true
docker run --name crowdin -p 80:80 -p 443:443 dockware/crowdin:latest
```

### Update translations in running container

If you have a running container and just want to get the latest translations from Shopware Github, just use the built-in CLI command. It will fetch the latest data and rebuild Shopware for you.

```
# connect into container
docker exec -it crowdin bash

# update translations
php bin/console crowdin:translations:update
```

## Troubleshoot

### Remove Container

Every code above makes sure the name "crowdin" is used for the container. This is to easily remove containers again. If names somehow get mixed on your machine, you can still easily remove containers. Just output a list of all existing containers and either remove them by **name** or **id**.

```
docker ps -a
```

Now you can remove the container by name or id.

```
# name
docker rm -f (name)
# ...or id
docker rm -f (id)
```


# Versions and Releases


# Quick Start Tutorials


# Developing Web Apps

Dockware can be used to easily develop any PHP or Node.js based applications.\
No matter if it's Symfony, Laravel, Vue.js and more.

The **dockware/web** image is available as a fully working environment for all these required technologies.

## Create Environment

Let's create a folder for our local project and place a **docker-compose.yml** file inside

```yaml
app:
  image: dockware/web:latest
  container_name: app
  ports:
    - 80:80
  volumes:
    - "./src:/var/www/html"
  environment:
    - PHP_VERSION=8.4
    - NODE_VERSION=20
```

This file will create a new **container** based on the latest version of dockware/web.\
It will mount a relative **src** folder to the **Apache DocRoot** directory inside the container.

We will use PHP 8.4 and Node 20. Please keep in mind, that availability of the versions is subject to change, (see changelogs for more).

After running the following command, we are able to access <http://localhost> with our empty application:

```bash
docker-compose up -d
```

## Create Application

It's now time to create your application. Just connect into the container and start with the installation and setup routine.

```bash
docker exec -it app bash
```

You should be automatically connected into the **/var/www/html** folder of the container.

Whatever you install there, is automatically available on your host thanks to the bind-mounting.\
Here is an example of installing Symfony

```bash
composer create-project symfony/skeleton my_project_name
```

If you have applications such as Vue.js and others, you might need an **additional port** after starting the dev server inside the container. Just append this to the **docker-compose.yml** entry and **restart** your environment.

{% hint style="success" %}
That's it, you now have a working development environment with a simple container
{% endhint %}

## Where to go from here?

Depending to the complexity of your project, you might require additional things such as new **containers**, **installation scripts** to automatically install dependencies and more.

Just imagine, you can also create 1 container based on dockware/web for your Vue.js application and another dockware/web container for your PHP backend system, and maybe an addtional MySQL container for the database.

This is not really part of dockware, because it's really bound to your special needs.

The great thing is, it is all **just plain Docker**, so you can basically build and connect everything you need.

Here are a few typical things you usually want in your projects

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>HTTP and SSL</td><td>Use HTTPS instead of HTTP for your projects</td><td><a href="/pages/u6j9fTimha4NnRdNC7Py">/pages/u6j9fTimha4NnRdNC7Py</a></td></tr><tr><td>Improve Bind-Mounting</td><td>Optimize performance and structure when it comes to bind-mounting your source code</td><td><a href="/pages/p79QVB8iURwBf0VE2BWH">/pages/p79QVB8iURwBf0VE2BWH</a></td></tr><tr><td>Web Image Features</td><td>Explore the features of dockware/web to improve your development envrionment.</td><td><a href="/pages/6hZc2kOPxRLZR0uNKXTc">/pages/6hZc2kOPxRLZR0uNKXTc</a></td></tr></tbody></table>


# Developing Headless Systems

Headless systems are everywhere nowadays. This could mean an integration of your headless CMS system, or even a full headless E-Commerce shop.

The power in development setups lies within the system architecture, so what containers you have and how they communicate with each other.

The following dockware images can help you:

<table><thead><tr><th width="265.65625">Image</th><th>Why</th></tr></thead><tbody><tr><td>dockware/web</td><td>simple easy image for PHP and Node based applications. You can install your headless frontend, or even your CMS or Shopware shop inside.</td></tr><tr><td>dockware/shopware</td><td>if you just need a "self-managed" simple Shopware version, you can use this as Shopware instance. You can also easily upgrade to a different Shopware version by changing the image tag.<br>In the end, you want to focus on your headless storefront and not on Shopware right ;)</td></tr><tr><td>dockware/shopware-essentials</td><td>This is like the Shopware image, but you have to bring the source code of your own Shopware (version). The benefit is only, that you don't need an additional MySQL and other services for the shop in your setup, because it's all in 1 container.</td></tr><tr><td>dockware/proxy</td><td>A simple NGINX proxy. You probably want to use this, if you want to use those beautiful domains for your systems instead of ports.</td></tr></tbody></table>

## Create Environment

Let's create a folder for our local project and place a **docker-compose.yml** file inside.

Please keep in mind, you can use any Docker images (also different ones than from the list above).\
This sample shows you how to build a headless application with Shopware as backend system.

```yaml
proxy:
  image: dockware/proxy:latest
  container_name: proxy
  ports:
    - 80:80
    - 443:443
  volumes:
    - "../proxy/frontend.conf:/etc/nginx/conf.d/frontend.conf:ro"
    - "../proxy/shopware.conf:/etc/nginx/conf.d/shopware.conf:ro"
    - "../proxy/tcp.conf:/etc/nginx/conf.stream.d/tcp.conf:ro"
  
frontend:
  image: dockware/web:latest
  container_name: frontend
  volumes:
    - "./src:/var/www/html"
  environment:
    - NODE_VERSION=22
    
shopware:
  image: dockware/shopware:6.6.10.2
  container_name: shopware
```

This will launch 3 containers.\
A NGINX proxy that forwards our domains and TCP requests (MySQL clients) to the corresponding containers, a plain environment container with Node 22 for our Vue.js Storefront, as well as a simple pre-installed Shopware 6.6.10.2.

The only thing that is left, before we can start our environment is the 3 NGINX configuration files.

{% tabs %}
{% tab title="frontend.conf" %}

```nginx
server {
    listen        80;
    server_name   shop.my-domain.com;
    return 301    https://$host$uri$is_args$args;
}

server {
    listen        443 ssl;
    server_name   shop.my-domain.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    location / {
        proxy_pass https://frontend;
   }
}
```

{% endtab %}

{% tab title="shopware.conf" %}

```nginx
server {
    listen        80;
    server_name   shopware.my-domain.com;
    return 301    https://$host$uri$is_args$args;
}

server {
    listen        443 ssl;
    server_name   shopware.my-domain.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    location / {
        proxy_pass https://shopware;
    }
}
```

{% endtab %}

{% tab title="tcp.conf" %}

```nginx
server {
    listen 3306;
    proxy_pass shopware:3306;
}
```

{% endtab %}
{% endtabs %}

Now just edit your local **/etc/hosts** file and add entries for your domains

```
127.0.0.1     shop.my-domain.com
127.0.0.1.    shopware.my-domain.com
```

{% hint style="success" %}
If you want to use a more dynamic way instead of using /etc/hosts, this blog post could be interesting for you: <https://www.boxblinkracer.com/blog/docker-dnsmasq>
{% endhint %}

And that's it.\
Start your Docker environment and you should be able to access **<https://shop.my-domain.com>** and **<https://shopware.my-domain.com/admin>**

```bash
docker-compose up -d
```

{% hint style="info" %}
If your browser shows invalid certificates, just continue (in Chrome just type "thisisunsafe").\
With Shopware, keep in mind, your Storefront is only available if you create a dedicated domain entry in your sales channel - but you actually just need the Administration anyway.
{% endhint %}

## Create Frontend Application

It's time to create your Vue.js Storefront application.\
This tutorial will not cover this in detail.

Just connect into the container and start the installation. The files will be automatically available in your **src** folder on your host system.

```bash
docker exec -it frontend bash
```

The only thing you need to build your application in a headless way, is the domains how to connect to Shopware. There are 2 options for this.

If you need to **access from the client side**, just use the domain **<https://shopware.my-domain.com>** as you would do to access Shopware directly.

If you need to **access it from the server side**, use the **key** value from the **docker-compose.yml** in combination with **HTTP** (SSL is too much for this tutorial), which is **<http://shopware>** in our sample.

{% hint style="success" %}
That's it, you now have a working development environment with a simple headless setup.
{% endhint %}

## Where to go from here?

Depending to the complexity of your project, you might require additional things such as new **containers**, **installation scripts** to automatically install dependencies and more.

Instead of Shopware you might need another system like a headless CRM, or even a custom application where you could also use another dockware/web container and maybe an additional MySQL container.

This is not really part of dockware, because it's really bound to your special needs.

The great thing is, it is all **just plain Docker**, so you can basically build and connect everything you need.

Here are a few typical things you usually want in your projects

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>HTTP and SSL</td><td>Use HTTPS instead of HTTP for your projects</td><td><a href="/pages/u6j9fTimha4NnRdNC7Py">/pages/u6j9fTimha4NnRdNC7Py</a></td></tr><tr><td>Improve Bind-Mounting</td><td>Optimize performance and structure when it comes to bind-mounting your source code</td><td><a href="/pages/p79QVB8iURwBf0VE2BWH">/pages/p79QVB8iURwBf0VE2BWH</a></td></tr><tr><td>Web Image Features</td><td>Explore the features of dockware/web to improve your development envrionment.</td><td><a href="/pages/6hZc2kOPxRLZR0uNKXTc">/pages/6hZc2kOPxRLZR0uNKXTc</a></td></tr></tbody></table>


# Developing Shopware Shops

Building full Shopware shops is really easy with Docker and dockware images.\
Here are a few easy steps to get started.

## Environment Strategy

The first thing you want to clarify is, what **type of infrastructure** your project needs.\
Are you happy with a **single container**, or do you want to **reproduce the production system** which usually consists of **multiple services**, or (at least) a separate database instance.

If you are happy with a single container, we recommend using the **dockware/shopware-essentials** image, which brings all tools such as MySQL out of the box. You only need to connect into the container and install your preferred Shopware version.

If you have more serious setups, we recommend using the plain **dockware/web** image.\
This one is made to be a pure and easy development environment for PHP and Node based applications. Compared to the shopware-essentials image, this one does not come with any additional toolings and is a clean container only.

## Create Environment

We decided on using a more complex setup with additional services.\
So start by creating a **docker-compose.yml** file.

We build a container for our **Shopware shop**, an additional **MySQL container** including persisting of the data, and a separate container for a **Symfony based application** that moves data from the ERP system to Shopware by using the Shopware API (just a fictional sample).

To use domains, we add an additional **NGINX based proxy**. We use it to forward HTTP requests, but also TCP requests to the database (could be done directly by exposing the port of the MySQL container, but maybe you can learn something haha).

```yaml
proxy:
  image: dockware/proxy:latest
  container_name: proxy
  ports:
    - 80:80
    - 443:443
    - 3306:3306
  volumes:
    - "../proxy/shopware.conf:/etc/nginx/conf.d/shopware.conf:ro"
    - "../proxy/middleware.conf:/etc/nginx/conf.d/middleware.conf:ro"
    - "../proxy/tcp.conf:/etc/nginx/conf.stream.d/tcp.conf:ro"
  
shopware:
  image: dockware/web:latest
  container_name: shopware
  volumes:
    - "./shop/src:/var/www/html"
 
middleware:
  image: dockware/web:latest
  container_name: middleware
  volumes:
    - "./middleware/src:/var/www/html"
    
db:
  image: mysql:8.4.0
  container_name: mysql
  volumes:
    - "db_vol:/var/lib/mysql"
  environment:
    - MYSQL_ROOT_PASSWORD=xxx
    - MYSQL_PASSWORD=xxx
    - MYSQL_DATABASE=shopware
    - TZ=Europe/Berlin
      
volumes:
  db_volume:
    driver: local
```

The only thing that is left, before we can start our environment is the 3 NGINX configuration files.

{% tabs %}
{% tab title="shopware.conf" %}

```nginx
server {
    listen        80;
    server_name   shopware.my-domain.com;
    return 301    https://$host$uri$is_args$args;
}

server {
    listen        443 ssl;
    server_name   shopware.my-domain.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    location / {
        proxy_pass https://shopware;
    }
}
```

{% endtab %}

{% tab title="frontend.conf" %}

```nginx
server {
    listen        80;
    server_name   middleware.my-domain.com;
    return 301    https://$host$uri$is_args$args;
}

server {
    listen        443 ssl;
    server_name   middleware.my-domain.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    location / {
        proxy_pass https://middleware;
   }
}
```

{% endtab %}

{% tab title="tcp.conf" %}

```nginx
server {
    listen 3306;
    proxy_pass db:3306;
}
```

{% endtab %}
{% endtabs %}

Now just edit your local **/etc/hosts** file and add entries for your domains.

```
127.0.0.1     middleware.my-domain.com
127.0.0.1.    shopware.my-domain.com
```

{% hint style="success" %}
If you want to use a more dynamic way instead of using /etc/hosts, this blog post could be interesting for you: <https://www.boxblinkracer.com/blog/docker-dnsmasq>
{% endhint %}

And that's it.\
Start your Docker environment and you should be able to access **<https://middleware.my-domain.com>** and **<https://shopware.my-domain.com>.** Of course, these will lead to empty web directories.

```bash
docker-compose up -d
```

{% hint style="info" %}
If your browser shows invalid certificates, just continue (in Chrome just type "thisisunsafe").\
With Shopware, keep in mind, your Storefront is only available if you create a dedicated domain entry in your sales channel - but you actually just need the Administration anyway.
{% endhint %}

## Create Shopware and Middleware

It's time to start with our projects.\
This tutorial will not cover that in detail.

Just connect into the container and start the installation. The files will be automatically available in your **src** folders on your host system.

```bash
docker exec -it shopware bash
```

When you need to access either the MySQL database internally in the Docker network, or another container such as Shopware, please keep in mind to use the key names of the yaml files.

The database connection string would look like this

```bash
DATABASE_URL=mysql://root:root@db:3306/shopware
```

{% hint style="success" %}
That's it, you now have a working development environment with a pretty cool infrastructure that can easily be improved with way more containers and features.
{% endhint %}

## Taking care of the database

We have a database being **persisted by using Docker volumes**.\
This means, whenever we restart our environment, the database is existing again, as long as we have not pruned our Docker volumes.

Why do we do this?

When we create full Shopware shops, the demo data is not sufficient because our clients’ shops need to be **tailored to their specific requirements**, which means extensive configuration in the **database**.\
In addition to this, we usually work together as a team, which means everyone need to have access to the same kind of data(base).

There are different ways to tackle this problem. In theory, you could use **migrations** or **bash scripts** to configure everything—either via Shopware’s **bin/console commands** for system settings or directly through **MySQL queries**. This approach works, and best of all, it’s reproducible.

A different approach is, to share a (pseudo-anonymized) database across your team.\
Let's imagine you have a **shopware.sql.tar backup** in your Docker folder (GIT excluded!!!)

You could easily have a **setup script** or **makefile** with a target like `make run` that imports the database in your running enviroment. If it takes too long, maybe you don't need to import it on every startup - it's persisted anyway - so let the developers just import it on demand, etc.

Here is a script that copies the backup into the container, unzips it and imports it into MySQL.

```bash
# copy into container and unzip
docker cp ./shopware.sql.tar db:/tmp/shopware.sql.tar
docker exec -i db bash -c "cd /tmp && tar xfv shopware.sql.tar"
# -------------------------------------------------------------------------
# disable checks and import
docker exec -i db bash -c "mysql -uroot -proot -e \"SET AUTOCOMMIT = 0; SET UNIQUE_CHECKS = 0; SET FOREIGN_KEY_CHECKS = 0;\""
docker exec -i db bash -c "mysql -uroot -proot --max_allowed_packet=1GB -e \"use shopware; source /tmp/shopware.sql;\""
docker exec -i db bash -c "mysql -uroot -proot -e \"SET FOREIGN_KEY_CHECKS = 1; SET UNIQUE_CHECKS = 1; SET AUTOCOMMIT = 1; COMMIT;\""
# -------------------------------------------------------------------------
# delete raw file again in container
docker exec -it db bash -c "rm -rf /tmp/shopware.sql"
```

These steps give you a powerful approach to collaborate with a combination of source code and database, to create the best Shopware shops for your clients.

## Where to go from here?

Depending to the complexity of your project, you might require additional things such as new **containers**, **installation scripts** to automatically install dependencies and more.

This is not really part of dockware, because it's really bound to your special needs.\
The great thing is, it is all **just plain Docker**, so you can basically build and connect everything you need.

Here are a few typical things you usually want in your projects

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>HTTP and SSL</td><td>Use HTTPS instead of HTTP for your projects</td><td><a href="/pages/u6j9fTimha4NnRdNC7Py">/pages/u6j9fTimha4NnRdNC7Py</a></td></tr><tr><td>Improve Bind-Mounting</td><td>Optimize performance and structure when it comes to bind-mounting your source code</td><td><a href="/pages/p79QVB8iURwBf0VE2BWH">/pages/p79QVB8iURwBf0VE2BWH</a></td></tr><tr><td>Web Image Features</td><td>Explore the features of dockware/web to improve your development envrionment.</td><td><a href="/pages/6hZc2kOPxRLZR0uNKXTc">/pages/6hZc2kOPxRLZR0uNKXTc</a></td></tr></tbody></table>


# Developing Shopware Plugins

The Shopware images of dockware are a perfect fit if you want to develop Shopware plugins.

\
Every image comes with an **installed** and **prepared Shopware**, so you can **immediately start coding**. Depending on your environment strategy, you can even **switch** to a different Shopware version by just changing one single version number. Sounds good? Let's discover more.

## Environment Strategy

The first thing you want to clarify is, what **type of infrastructure** your project needs.

You can always create custom installations of Shopware by using the plain **dockware/we**b image, additional database containes or more.

But we usually **recommend** using the **dockware/shopware** image and just bind mount your plugin to the demo installation of Shopware. This allows you to easily switch Shopware versions without a lot of hazzle.

The next thing to decide, is, if you need the full source code of Shopware **locally in your IDE** to use code completion and more.

Our sample in this tutorial, will use exactly this approach.\
We will only mount our plugin, but also prepare the source code of Shopware locally for a better developer experience.

## Create Environment

We start by creating a **docker-compose.yml** file.

This will typically only contain 1 single container. However, depending on your needs, you can always add more, such as ELK stacks for logging and other useful and required services for your developer experience.

```yaml
shop:
    image: dockware/shopware:6.7.2.2
    container_name: shop
    volumes:
      # ----------------------------------------------------------------------------------------------------------------------------------
      # PLUGINS
      # our plugin GIT repository is in a sub folder custom/plugins
      - "./custom/plugins/MyPlugin:/var/www/html/custom/plugins/MyPlugin"
      # ----------------------------------------------------------------------------------------------------------------------------------
      # exclude some folders for better performance
      # this uses anonymous volumes that leads to container/host decoupling for these folders
      # therefore less bind-mount -> better performance
      - "/var/www/html/custom/plugins/MyPlugin/.git/"
      - "plugin_vendor:/var/www/html/custom/plugins/MyPlugin/vendor/"
      - "plugin_node_admin:/var/www/html/custom/plugins/MyPlugin/src/Resources/app/administration/node_modules/"
      - "plugin_node_storefront:/var/www/html/custom/plugins/MyPlugin/src/Resources/app/storefront/node_modules/"
    ports: 
      - "80:80"
      - "443:443"
      - "3306:3306"
    environment:
      - XDEBUG_ENABLED=1
```

And that's it.\
Start your Docker environment and you should be able to access **http(s)://localhost** to access your Shopware.

```bash
docker-compose up -d
```

{% hint style="info" %}
If you need to use domains instead of localhost, please see this page [Domains with HTTPS](/tutorials/docker-tutorials/domains-with-https)
{% endhint %}

{% hint style="info" %}
If your browser shows invalid certificates, just continue (in Chrome just type "thisisunsafe").\
With Shopware, keep in mind, your Storefront is only available if you create a dedicated domain entry in your sales channel - but you actually just need the Administration anyway.
{% endhint %}

## Prepare Local Shopware

When you either **initially** start your project, or after **switching** to a different Shopware version by changing the docker-compose.yml file, you might want to download the source code to use **code completion in your IDE**.

Why do we need this? Because we have only mounted our plugin for a better performance but also decoupling of the used Shopware version.

So all we need now, is a **small script** that just downloads the files from the container to your host.\
This is not needed all the time, just initially or after changing Shopware versions.

Here is a sample based on a **makefile** with the command make `download-src`. It first cleans our local vendor folder of Shopware, and then just downloads everything. Feel free to improve it for you.

```makefile
download-src: 
    rm -rf ./vendor/* || true
    docker cp shop:/var/www/html/. ./
```

{% hint style="success" %}
And that's it, you now have everything locally with a wonderful developer experience!
{% endhint %}

## Where to go from here?

Depending to the complexity of your project, you might require additional things such as new **containers**, **installation scripts** to automatically install dependencies and more.

This is not really part of dockware, because it's really bound to your special needs.\
The great thing is, it is all **just plain Docker**, so you can basically build and connect everything you need.

Here are a few typical things you usually want in your projects

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>HTTP and SSL</td><td>Use HTTPS instead of HTTP for your projects</td><td><a href="/pages/u6j9fTimha4NnRdNC7Py">/pages/u6j9fTimha4NnRdNC7Py</a></td></tr><tr><td>Improve Bind-Mounting</td><td>Optimize performance and structure when it comes to bind-mounting your source code</td><td><a href="/pages/p79QVB8iURwBf0VE2BWH">/pages/p79QVB8iURwBf0VE2BWH</a></td></tr><tr><td>Shopware Image Features</td><td>Explore the features of dockware/shopware to improve your development envrionment.</td><td><a href="/pages/U3cYa2RcxjgYIRSuMEvm">/pages/U3cYa2RcxjgYIRSuMEvm</a></td></tr></tbody></table>


# Developing Shopware Apps

Since a while, Shopware allows the development of apps instead of plugins.

The basic difference between an app and a plugin is, that apps do not directly run within the Shopware shop that has installed it. Only a small layer is really existing in the shop, while the actual source code and logic is running on another server, you're so called backend-server.

This lightweight approach is the way to go when developing for Shopware SaaS, but also a great thing if you want to use another development language instead of PHP. Indeed it's a perfect chance to have a central place of logic and even bring your Shopware SaaS and Shopware On-Premise customers together into 1 single technology.

## Create Environment <a href="#developing-with-dockware" id="developing-with-dockware"></a>

Please make sure to learn the basics about app development from the official [Shopware documentation](https://developer.shopware.com/docs/guides/plugins/apps/app-base-guide).

Developing Apps require an **additional backend system** next to your Shopware shop.\
This is the server that runs your actual code.

Both platforms (Shopware and your backend service) need to be able to communicate with each other, depending on what your app should do. This is easy when developing on live systems with domains that really exist, but could be a bit tricky if your are just working offline within Docker.

So we've created a possible solution for you to easily start with app development and dockware.

Please keep in mind, this is just 1 single solution that could work.

Depending on your setups and wishes, you can of course use other approaches and fully enjoy the power of Docker! In the end, both endpoints just need to be able to talk to each other.

We start by creating 2 containers in our **docker-compose.yml** file. Both of them use a bind-mount for the source code, but you can handle this in your preferred way.

Copy

```yaml
version: "3.0"

services:

    shopware:
      container_name: shopware
      image: dockware/shopware:6.7.2.2
      ports:
        - "80:80"
      networks:
        - web
      volumes:
        - "./.env:/var/www/html/.env"
        - "./YourApp:/var/www/html/custom/apps/YourApp"

    server:
      container_name: server
      image: dockware/web:latest
      ports:
        - "1000:80"
      networks:
        - web
      volumes:
        - "./service:/var/www/html"
      links:
        - shopware:my.app.dev

networks:
  web:
    external: false
```

The 2 containers can communicate with each other, using the key names for the YAML file **shopware** and **server**. So our goal is, to ensure that during the initial handshake and exchange when installing a plugin, the containers use their correct internal Docker hostname when registering.

## **Connect Shopware to Backend Service**

This is really easy. For development purpose, you can just use the Docker host name within the **manifest.xml** file of the Shopware App.

Copy

```
<setup>
   ...
   <registrationUrl>http://server/.....</registrationUrl>
</setup>
```

Don't forget about that dynamic confirmation URL that is sent from your backend service during the setup process. That would also need to use this host!

## **Connect Backend Service to Shopware**

Some use cases might require your backend service to connect to a shop and retrieve data using the Shopware API.

Unfortuantely, Shopware might always send **localhost** as shop URL during our registration, which means, that the backend server would call localhost when trying to communicate with the shop, which obviously results in **communicating with himself**.

So we have to learn Shopware to use another host when registering, while still being available as **<http://localhost>** for us and our browser.

This might be different, depending on your setup and usage of <http://localhost> when developing.

Changing the shop URL can be done by adjusting the **.env** file of Shopware. Just use any domain name that you want. It does not need to even exist. Not even in your /etc/hosts file.

Copy

```
...
APP_URL=http://my.app.dev
...
```

Now Shopware would automatically send this domain to the backend service when registering the shop. The only problem left is, that our backend service does not know whom to contact with that domain.

The solution is quite simple.

We use a **link** and an **alias** in the docker-compose.yml where we just learn the container to call our Shopware host when using this domain. And therefore the backend service will automatically connect to our our Shopware container when trying to reach it.

Copy

```
links:
   - shopware:my.app.dev
```

Congratulations!

You have a Shopware app environment where your backend service just gets a dynamic shop URL and data, and can connect to it without any additional troubles.

Now it's up to you, to create the purpose and logic of your software!

## Logging <a href="#logging" id="logging"></a>

Logging is always important, but even more if you have decentralized systems such as with developing app systems for Shopware.

We recommend using systems like ELK (Elastic Logstash Kibana) for such setups. But if you need a quick start and easy solution, then we have a guide on that using the built-in Pimp my Log of dockware. [Read more here](https://docs.dockware.io/features/pimp-my-log).

## Video <a href="#video" id="video"></a>

Need more explanation? Just watch the video where we demonstrate the setup, connection as well as our example application in more detail.

{% embed url="<https://www.youtube.com/watch?v=4vZ8V_IIjck>" %}


# Exploring Shopware

You can explore any Shopware 6, and even supported Shopware 5 versions, even if you are not a technical person. Just follow these easy steps to get started.

This page does also explain you a bit more about the technology and troubleshooting.

{% stepper %}
{% step %}

#### Install Docker

Install Docker on your system. Please see this page: [Docker Setup](/)
{% endstep %}

{% step %}

#### Start Dockware Image

Now that you have Docker installed and running, it's time to start a new **container**.\
Containers are **running instances** of an **image** in Docker.

A single image contains multiple versions, which is called **tags**. You need the image **dockware/shopware**. The tag is the Shopware version.\
\
Enter the following line in your **terminal** to start a new Shopware 6.6.10.2, that exposes port 80. **Port 80** is the HTTP port. Because of this, you can then open Shopware with **<http://localhost>** in your browser.

```bash
docker run -p 80:80 dockware/shopware:6.7.2.2
```

Image versions are first downloaded to your local computer before they are started. This might take a bit the first time, but once downloaded, it's really super fast the next time.

{% hint style="success" %}
Congratulations, you now have a Shopware running. Please see this page for default credentials, in case you need it: [Default Credentials](/dockware-shopware/default-credentials)
{% endhint %}

{% hint style="warning" %}
Please note, that for installing older Shopware versions (< 6.6.x) you need to use our old images. This means if you were prompted that the image was not found, you try using either a non-existing image (like 6.5.9.13). In this case, please use dockware/**play**:x.x.x.x.
{% endhint %}
{% endstep %}

{% step %}

#### Delete Dockware Image

If you want to delete the docker container, be it for a fresh installation or just cleaning up your machine, there is another **easy command** to do so.\
Because we have started the Docker container in an synchronous way, we have to **cancel your terminal command**, usually by using something like `CTRL+C`, to be able to enter a new command. Or we can just add a new terminanl window or tab.

Use these commands to easily and manually **delete** (any) running containers.\
Keep in mind, if you ever get something like "**port already used**" when starting a container, it also means an old container is still blocking the port. Just delete all containers.

```bash
// show all containers
docker ps -a
// now pick the ID of the container you want to remove
docker rm -f (id)
```

{% hint style="success" %}
That's it, your container is now successfully removed.
{% endhint %}
{% endstep %}
{% endstepper %}


# Docker Tutorials


# Correct Bind-Mounting

Since the Docker engine is getting better, the performance losses especially on MACs are not as big as they used to be when using bind-mounting in projects such as Symfony or Shopware.

Some of you know, that we like the SFTP way, as it's the best controllable and platform independent way to handle the project and file permissions.

**But it's not the only approach of dockware and us! It's a fallback that always works!**

{% hint style="warning" %}
Bind-Mounting is a plain Docker feature and has nothing to do with dockware itself.\
Thus, all related things, including issues such as file permission problems do not have to do anything with dockware. Please keep that in mind when searching for answers to problems.
{% endhint %}

{% hint style="info" %}
**WINDOWS Users:**\
Please see also this page for now, until we had time to integrate it in this page.\
Thank you for your understanding:\
<https://github.com/dockware/docs/issues/3>
{% endhint %}

## New Project

If you are not a plugin developer, but have a full shop instead, please make sure to read our guide about [creating a new project](broken://pages/jdKYDGvijXICe2gDarbT).

This is required, because starting a new project immediately with bind-mount would lead to an empty folder, and thus no Shopware.<br>

So **with bind-mounting, you first need your source code on your host machine.**

## MAC

If you are working on a MAC, then bind-mounting works really good.\
You only need to exclude a few folders from your container, and it works blazing fast.

Below are 2 use cases with samples of folders that should usually be excluded.\
Feel free to improve these for your custom projects.

> We recommend excluding every large folder that you don't need locally\
> (logs, caches, node\_modules, ...)

The excluded folders will be based on **anonymous volumes**.\
It's like a a persistent volume...only without a name and known destination.

This means, that if you have a *node\_modules* folder as an anonymous volume, it only exists in Docker, but not on your host, which is the solution to speed up things. But this also means that Docker is the **owner** of those folders, which brings a small disadvantage.

If you want to delete those folders in your scripts (like the vendor), then you get an error "Device is busy". The solution is to simply delete the contents of that folder, instead of the folder itself.

```bash
rm -rf ...../vendor/*
```

To continue using all your scripts and commands as usual, you have to set permissions on these folders after starting your container. **You can set these individually per folder, or just use this command and all is good:**

```bash
docker exec -it shop bash -c 'sudo chown www-data:www-data /var/www/html -R'
```

{% hint style="success" %}
That's it!\
You now have a bind-mounted Shopware on a MAC with a good performance.
{% endhint %}

### Plugin Developer

{% code title="docker-compose.yml" %}

```yaml
shop:
  image: dockware/shopware:6.7.2.1
  container_name: my_shop
  volumes:
    - "./src/custom/plugins/MyPlugin:/var/www/html/custom/plugins/MyPlugin"
    # exclude by using anonymous volumes
    - "/var/www/html/custom/plugins/MyPlugin/.git/"
    - "/var/www/html/custom/plugins/MyPlugin/vendor/"
    - "/var/www/html/custom/plugins/MyPlugin/src/Resources/app/administration/node_modules/"
    - "/var/www/html/custom/plugins/MyPlugin/src/Resources/app/storefront/node_modules/"
    - "/var/www/html/custom/plugins/MyPlugin/tests/Cypress/"
   ...rest of docker-compose...
```

{% endcode %}

### Shop Developer

{% code title="docker-compose.yml" %}

```yaml
shop:
  image: dockware/shopware-essentials:latest
  container_name: my_shop
  volumes:
    - "./src:/var/www/html/"
    # ...excluding shopware default directories
    - "/var/www/html/.git/"
    - "/var/www/html/public/build"
    - "/var/www/html/var/cache"
    - "/var/www/html/vendor"
    # ...additional project specific excludes...
    - "/var/www/html/custom/plugins/MyPlugin/src/Resources/app/administration/node_modules/"
    - "/var/www/html/custom/plugins/MyPlugin/src/Resources/app/storefront/node_modules/"
    - "/var/www/html/custom/plugins/MyPlugin/tests/Cypress/"
   ...rest of docker-compose...
```

{% endcode %}

## Linux

Bind-Mounting on Linux works great!\
You can simply mount the whole DocRoot without any performance loss.

However, if you are a plugin developer, we would still recommend only mounting your custom plugin. This allows you to easily switch the Shopware version around your plugin.

Here are 2 samples for plugin developers and developers who are in charge of full shops.

### Plugin Developer

```bash
shop:
  image: dockware/shopware:6.7.2.1
  container_name: my_shop
  volumes:
    - "./src/custom/plugins/MyPlugin:/var/www/html/custom/plugins/MyPlugin"
   ...rest of docker-compose...
```

### Shop Developer

{% code title="docker-compose.yml" %}

```yaml
shop:
  image: dockware/shopware-essentials:latest
  container_name: my_shop
  volumes:
    - "./src:/var/www/html/"
   ...rest of docker-compose...
```

{% endcode %}

Linux has some great options for permissions.\
If you face any troubles while developing, you can do the following:

Make sure that both your host (and users) as well as the Docker container work with the same permission group. We recommend **ID** **33**, which is also known as "**www-data**".

Then simply change the permissions of your source folder

```bash
# change basic permissions (you might need sudo)
chgrp -R 33 ./src
# write permissions for cache/log folder required
chmod a+w ./src/var/*
```

Another approach would be to run this command in your container after starting it.\
It should fix all permissions if something is broken

```bash
sudo chown www-data:www-data /var/www/html -R
```

There would also be an easy make command to fix permissions in /var/[www](http://www).

{% hint style="info" %}
Please keep in mind, this guide is meant for development.\
When it comes to a hosted installation on a Linux server, we have more instructions about strategies and permissions on [this page.](broken://pages/-MeePhWBXBcE0SV5oKYp)
{% endhint %}

## Important Notices

{% hint style="danger" %}
Keep in mind, when you upload with SFTP while having an active bind-mount, that will remove thecontent of the files! Do not mix both ways!
{% endhint %}


# Domains with HTTPS

Dockware images come already with installed self-signed certificates.\
You can even overwrite those certificates and install your certificates with Bind-Mounting (or any other way).

These are the used default locations:

```bash
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
```

Using HTTPS locally or on a hosted machine is very easy.\
Just make sure to **expose port 443** in your Docker container.

Afterwards it should already work using *<https://localhost>* for example.

{% hint style="info" %}
If your Chrome warns you about the self signed certificate, just continue to the website or simply type **thisisunsafe** as a magic word.
{% endhint %}

If you want to use a different domain instead of <https://localhost>, you only need to login to the Shopware Administration and configure the domain in your sales channel. (maybe also clear your caches).

Then you only need to tell your host that this domain exists and that it should just map to your localhost IP address. For this, edit your local */etc/hosts* file and add a new entry like below. This only needs to be done once on your machine.

```bash
127.0.0.1    local.shop.com
```

{% hint style="info" %}
Please avoid domains like **\*.dev** and **\*.local**, because these usually bring some troubles with them. They have indeed special handlings in some browsers.
{% endhint %}


# Setup Filebeat

The [Filebeat](https://www.elastic.co/beats/filebeat) integration allows you to automatically send log data and files to your [Logstash](https://www.elastic.co/logstash) instance if you use an [ELK](https://www.elastic.co/elastic-stack) stack.\
\ <br>

**How to configure filebeat?**

If you want to use Filebeat in dockware, you do not only need to turn ON the feature, but also provide a valid filebeat configuration.\
\
The easiest way to do this, is to mount that single file into **/etc/filebeat/filebeat.yml**.\
\
In addition to this, your Docker container must have access to your logstash container by either using the links or networks in Docker. This needs to be done only if you also have your Logstash within your Docker network :)\
\
Here is an example of a filebeat.yml configuration:

```yaml
name: "shop"

filebeat.inputs:
  - type: log
    enabled: true
    paths:
        - /var/log/apache2/error.log
    tags: ["server", "apache"]

  - type: log
    enabled: true
    paths:
        - /var/www/html/var/log/*.log
    tags: ["shop"]

output.logstash:
    hosts: ["logstash:5044"]
```

Please see our section about [Environment Variables](broken://pages/-MRt9LTzK3wKAq64g9e8) for more detail about the required configuration settings.\
\
\
Now that we have all single parts, we can combine them and create our configuration for our docker container.

```yaml
dockware:
      image: dockware/dev:latest
      ...
      volumes:
        - ./elk/my_shop/filebeat.yml:/etc/filebeat/filebeat.yml
      environment:
         - FILEBEAT_ENABLED=1
```

If you start your container, the "docker logs (container\_name)" output should show you that Filebeat is now being used.


# Online Servers

Dockware can also be used on online servers and not only on local developer machines.\
A perfect use case would be a test environment for your QA department!

{% hint style="warning" %}
Please note, we do **not recommend** or encourage you to use dockware for production!\
In theory it's possible, but it requires way more knowledge in Docker, hosting and also backup strategies! So please don't do it (unless you may know what you are doing).
{% endhint %}

## Hosting Strategy

When running dockware, or any other Docker container on an online server, you need to think about the strategy you are going to use to rollout new updates for your application.

Most of these scenarios depend on how you use your containers - either **with** bind-mounting or **without** bind mounting.

Docker containers are used as virtual servers on your hosting system.\
It's indeed possible to expose access to a container and deploy your application directly to it, exactly like you would do with a "real" server. So a pretty good and stable thing.\
But Docker containers might also run into problems - so you need to think about the case when you need to restart them. You don't want to lose any data in the end!

This could mean, that it might be a better solution, to keep the deployment to the host system and use Docker only for running and providing your application.

All these different scenarios are listed below, including pros/cons, as well as some instructions to get you started.

* **Scenario 1**: No Bind-Mount / Deployment to Container
* **Scenario 2**: No Bind-Mount / Deployment to Host
* **Scenario 3**: Bind-Mount / Deployment to Host **(Recommended)**
* **Scenario 4**: Dockerized Application

{% hint style="info" %}
We recommend Linux systems when using Docker for your online server....just saying ;)
{% endhint %}

## Reverse Proxy

Besides the hosting strategy, we suggest that you use a **reverse** **proxy** to manage the exposed ports.

It can be very dangerous if you expose port in your containers directly!\
\
A compose setup can have lots of containers, and it can easily happen that a container is suddenly available public with an accidentally exposed port!\
We recommend that you have your **ports only exposed through your proxy** where you can manage what should be available and what must not be exposed!

{% hint style="success" %}
We've created [dockware/proxy](https://hub.docker.com/r/dockware/proxy) as easy to use Docker image.\
It's based on NGINX and comes with some nice setups and features.
{% endhint %}

## Hosting Strategies

### Scenario 1: No Bind-Mount / Deployment to Container <a href="#scenario-1" id="scenario-1"></a>

| PROs                                                                   | CONs                                                                                                                                                                                                                            |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No Permission Problems                                                 | <p>Files are only in your container or Docker volume.<br>Once restarted or pruned, all files might be gone</p>                                                                                                                  |
| Grant externals access to only your container but not the host system. | <p>One might easily forget about security concepts when using Docker images that are meant for development.</p><p>Default strategies on the host system (users, port restrictions, SSH keys) might just feel better, right?</p> |

This scenario is a good way if you need temporary access to your container (easy and fast), or if you need access for external people, while trying to avoid that they can acess your host system.

Dockware allows you to set **custom SSH/SFTP users** for your container.\
Configure one with a good password strength, open **port 22** of your container, and you should be able to easily connect into your container from a remote machine.\
When exposing your port with "22:22", it could be that your host system already uses that port.\
In that case, you might want to switch to something else like "1022:22" (or any other port).\
Changing the SSH port to something else isn't a bad idea anyway (Security through obscurity).

In fact, the users, who will gain access from you, might not even notice that they work in a container and not on the host system.

The problem with this approach however is, that you rely on the built-in (open source) dockware project that everyone has access. We tried to build the security concept as good as possible, but still, people could find some weaker spots. And also things like "breakouts" from a Docker container would be possible...at least in theory.

{% hint style="success" %}
You should now have a running dockware container, that allows you to directly access it remotely using SSH/SFTP.
{% endhint %}

### Scenario 2: No Bind-Mount / Deployment to Host <a href="#scenario-2" id="scenario-2"></a>

| PROs                                                                                                       | CONs                                                                                                                                                                                                                                                                                                   |
| ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| No Permission Problems                                                                                     | You alway s need to make sure to upload your files into the container after a deployment.                                                                                                                                                                                                              |
| Files are on your host and can be easily reuploaded if you have to restart or prune your Docker system.    | <p>When using "docker cp", you do not delete outdated files in your container. You need to either remove the source folders before using "docker cp" or use something like "rsync" into your local container.</p><p>This means keeping both directory in sync might not be easy for some projects.</p> |
| You can use the host system security for user access and deployments (users, port restrictions, SSH keys). |                                                                                                                                                                                                                                                                                                        |

A deployment with this scenario is split into 2 parts:

* Deployment to Host
* Upload to Docker

You can **deploy your files** to any of your folder on your **host system**.\
There should not be any big file problems if you setup your server without any special configurations.\
Once your files have been deployed, you need to **start a script** (or just execute the commands), to **upload your changes into your Docker container**.

Please note, that files, that would have been removed, will not be removed using the "docker cp" command. This means you need to **manually remove files** or folders that could have changed, or use something like **Rsync** from your host machine into Docker.

After our upload with "docker cp", we need to **adjust the file permissions**.\
Our Apache user "www-data" needs correct access to all these files. These permissions are unfortunately broken after using "docker cp", so we just fix them with a simple command.

Here you will find 2 options with either a full cleanup, or a cleanup of a specific folder before uploading your changes. Please adjust them for your needs.

{% tabs %}
{% tab title="Full Cleanup" %}

```bash
# remove all old files just to be sure
# this is a complete and full cleanup of the previous data
docker exec shop bash -c 'cd /var/www/html && rm -rf *.* && rm -rf *'

# upload new files and fix permissions
docker cp ./src/. shop:/var/www/html
docker exec shop bash -c 'sudo chown www-data:www-data -R /var/www'
```

{% endtab %}

{% tab title="Partial Cleanup" %}

```bash
# remove only the source folder and keep other
# things like "media", ...
docker exec shop bash -c 'cd /var/www/html && rm -rf src'

# upload new files and fix permissions
docker cp ./src/. shop:/var/www/html
docker exec shop bash -c 'sudo chown www-data:www-data -R /var/www'
```

{% endtab %}
{% endtabs %}

###

### Scenario 3: Bind-Mount / Deployment to Host (Recommended) <a href="#scenario-3" id="scenario-3"></a>

| PROs                                                                                              | CONs                                                                                               |
| ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Easy deployment to your host system -> it's immediately synchronized in your container.           | Permission problems can occur if you don't configure both, your Docker and your Host system.       |
| Files are on your host system and are usually not lost when your Docker system is being restarted | Bind-Mounting might impact performance (depends on host operating system / Linux is great though). |
| Use host security concepts for users, port restrictions, SSH keys, ....feels good right?          |                                                                                                    |

For this scenario, we have to configure a few things before we start.

{% hint style="warning" %}
The most important thing for this setup is, that both, our **user on the host system**, as well as the **Apache user in dockware** belong to the **same user group "www-data"**.\
This is the foundation for everything.
{% endhint %}

Now we need to configure, that all our files and folders in our bind-mounted folder can be **accessed and written** by any user who **belongs to this group**.

This means, that both, our host users, and our Docker user, can modify all files without permission problems. So we can easily deploy files to our host server using one of our host users, and also dockware can use those files with all its required permissions.

To configure this scenario, please follow these 3 steps:

#### 1. Host User

Create a user on your host system, setup SSH keys or whatever you want to use for deployments, and finally add him to the "www-data" group.

```bash
usermod -a -G www-data myUser
```

#### 2. Default Permissions

We configure our "my-src-folder" to grant full file access to the user who created it, as well as the group he belongs to. The rest ("others") will not get write access.

```bash
setfacl -R -d -m u::rwx -m g::rwx -m o::r-x /.../.../my-src-folder
```

#### 3. Update Existing Files

If your directory is not empty, you might want to adjust the existing files.\
Just set the owner to "www-data" and the group permissions to 775.

```bash
chown www-data:www-data -R /.../.../my-src-folder
chmod 775 -R /.../.../my-src-folder
```

#### 4. Execute Commands in Container

Please keep in mind, to use the **correct group** of your user, when executing commands in your container. Just use the www-data user/group, and every command you run, will use the same group, and thus everyone has the same access to your files.

```
docker exec -u www-data:www-data myContainer bash -c '...my...command'
```

{% hint style="success" %}
That's it!\
If you now start dockware, it should all work.\
And if you deploy any files to the host system using your host user, there should not be any permission problems, and the changes should be immediately available in your Docker container.
{% endhint %}

###

### Scenario 4: Dockerized Application <a href="#scenario-4" id="scenario-4"></a>

| PROs                                                                                                | CONs                                                                                          |
| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| Easy deployment by pulling docker image updates and restarting it                                   | No easy and simple rollout of your latest source changes                                      |
| Always stable (or at least the version you've published)                                            | Requires Docker Image "Tag Management" and might be better if you have real version releases. |
| Docker layers allow you to see changes (by you or intruders) compared to your original Docker image |                                                                                               |

This scenario gives you the best option to handle releases and also rollbacks of those deployments.\
When "dockerizing" your application, you basically embed your application into a Docker image and freeze it with the current release of your application. You usually tag your Docker image with anything that relates to your application version, such as "company/myapplication:1.5.2".

When rolling out a new version of your image, you just build a new image version, tag it, and then simply pull your new Docker image on your server and start it, instead of the previous one. That's it!

Dockware is also shipped in that way to give you a fast and reliable plug'n'play Docker image of any Shopware version.

If you want to dockerize your own shop or application with dockware or other Docker images, you might want to dig deeper into building Docker images and manage their releases and tags.

{% hint style="info" %}
Please understand, that we cannot explain this here. Feel free to see the official Docker documentation and guides.
{% endhint %}

## Security Concerns

Please note, that hosting a Docker container on an online server requires some thoughts about security concepts. Thus we do not recommend using it for production unless you really know what you are doing.

If you have a staging or test system, we recommend to secure access to your server as good as possible!

This is a list of things that you may want to think about, before hosting your dockware container on an online server.

* [ ] Is the **access to your host system** secured as good as possible?\
  \&#xNAN;*(port restrictions, users with pub key authentication, firewall rules, ...)*<br>
* [ ] Did you **change** the easy (*developer*) **credentials** of your dockware systems?\
  \&#xNAN;*(SSH/SFTP users, MySQL users, Shopware admin ...)*<br>
* [ ] Is the **access** to your **Adminer** and **PimpMyLog** from dockware restricted or turned off?\
  \&#xNAN;*We recommend using a plain dockware image if possible (dockware/flex) that does not come with any Adminer or anything else. These additional services (MySQL, Adminer, ...) should be hosted on a separate container if needed and possible, based on your architecture and knowledge.*<br>
* [ ] Did you use a **reverse proxy** to secure and manage traffic and routings to your containers?\
  *Try to avoid direct port exposing in containers. Docker will automatically expose whatever you tell it to do and simply override your firewall by appending additional entries in your iptables!*\
  *That means, if you have a firewall restriction of port "x" but expose that one in your container - then it will NOT BE RESTRICTED!*

{% hint style="info" %}
Did we forget anything?!\
**Help to improve** our dockware universe with your knowledge and drop us a line in the Shopware Slack channel!
{% endhint %}


# Security Approaches

Security is always important!\
Please keep in mind, that dockware is primary made for local development!\
\
This does not mean you cannot use it for a server that is available on the internet.\
But please consider a few security related things.

**Don't expose ports like you would do locally**

In our docker-compose.yaml samples, you see all kinds of ports being exposed.\
This is great for local development - but not for a server - even it's "just" a staging system.\
\
Our recommendation is to only expose ports that are really necessary to use your app.\
And this should only be done through 1 single docker container, probably a proxy like NGINX.\
This helps you to avoid losing control over what is exposed throughout your (bigger) yaml file.\
\
If you expose a port, make sure to add an additional restriction if possible.\
\
This sample would only expose the port 3306 MySQL for connections from the localhost (host system).\
So you can do a default SSH connection to your host, and then a connection from there to your MySQL container. This is pretty much the basic workflow of such a scenario - only with Docker ;).

{% code title="docker-compose.yaml (partial)" %}

```
127.0.0.1:3306:3306
```

{% endcode %}

{% hint style="danger" %}
**Attention**

Please do never expose port 22 from dockware on an online server if you do not know what you are doing! Pay attention to the weak default credentials - and consider using a firewall.
{% endhint %}


# Shopware Tutorials


# Create new Shopware Project

This page is for everyone who develops a custom shop as a merchant or as an agency.

At the end of this page, you have a custom Shopware 6 installation, and also the full source code and database backup locally, so you can start developing.

## 1. Start Container

We first have to decide how we want to get our project source code.\
We can either use a prepared **dockware/shopware** image with an existing Shopware version and download the source code, or use a **dockware/shopware-essentials** and start right away with mounting.

We usually recommend dockware/essentials or dockware/flex for custom projects.

\
Let's use dockware/essentials, because we can immediately install everything with our single container, thanks to the built-in MySQL service.

We create a docker-compose, which need anyway sooner or later.

```yaml
version: '3'
services:
  shop:
    image: dockware/shopware-essentials:latest
    container_name: shop
    ports:
      - "80:80"
      - "3306:3306"
```

After the container has been started, we connect into it with our terminal.

```bash
docker exec -it shop bash
```

## 2. Install Shopware

The installation of Shopware is very easy.\
We use the prepared makefile command to download any Shopware version from the Shopware website and prepare it, so it can be easily installed in our browser.

```bash
cd /var/www
make download url=https://www.shopware.com/en/...
```

{% hint style="info" %}
You can use any Shopware version as URL from this page: <https://www.shopware.com/en/changelog/>

Just right click on any install/download button and copy the URL.
{% endhint %}

The makefile will now download the ZIP file and extract into the DocRoot of the dockware container. Now simply open your browser and **install your Shopware 6** version.

## 3. Export Database

After we have initially installed and prepared our shop, let's just export the database, so that we can use it later on.

\
Connect into your container and run the following command with your database name.

```bash
mysqldump -u root -proot (dbName) > /var/www/html/database.sql
```

The full database is now exported as a backup file in the Docroot.

## 4. Download Source Code

Our final step is to download everything to our host machine.\
We need the source code as well as the database backup.

What you do with those files is totally up to you.\
One would usually add the source code to a GIT repository and the database to an internal sharing system within your company.

Let's just run these 2 commands on your host machine.

```
mkdir ./src
docker cp (containerName):/var/www/html/. ./src
```

{% hint style="success" %}
Congratulations, you have a fully local source code and database backup for your custom Shopware shop.
{% endhint %}

## 5. Restart Project

Now to the fun part when restarting your project.\
Just imagine if you start your containers again later on, you might have a source code available, but no database. This leads to problems.

So depending on how you work, there are different approaches.\
You can have your custom MySQL container that is persisted....or even persisted in dockware, all good. But what if you need to really restore our MySQL dump from above?\
Just use this either manually, or in your project "run" script automatically.

It will create a Shopware database and import your dump.

```
docker exec -i shopware bash -c "mysql -uroot -proot -e \"DROP DATABASE IF EXISTS shopware;\""
docker exec -i shopware bash -c "mysql -uroot -proot -e \"create database shopware CHARACTER SET utf8 COLLATE utf8_general_ci;\""
docker exec -i shopware mysql -uroot -proot shopware < ./database.sql
```

That's everything, you should now have your shop available again.


# Custom Shop Domains

We have prepared everything for a smooth launch using <http://localhost!>\
But it's of course possible to use your custom domain.

There are only 3 things to configure:

1. **Change Shopware Domain** Configure your custom domain either in the Shopware administration (Sales Channel) or directly in your database. Make sure to enter the correct HTTP protocol along with your custom domain, such as "<http://dockware-local.com>".... You can also use a custom port in here by appending it to your domain like in this example "<http://localhost:1000>". (please note that this port needs to be exposed in Docker!)
2. **Clear Caches** Make sure to clear the caches of your Shopware shop. Otherwise, you will get an error in the storefront.
3. **Edit your .env** Make sure you enter the new domain in your .env in APP\_URL to ensure also extensions installations will work propper with licenses.
4. **Configure Domain on Host** We need to tell your host that requests to this new domain are being forward to your localhost. This can be by modifying the local `/etc/hosts` file. Just open it and add your new domain along with the localhost IP address like here:

{% code title="/etc/hosts" %}

```
127.0.0.1        dockware-local.com
```

{% endcode %}

{% hint style="success" %}
Congratulations!\
Your Shopware shop is now accessible under your custom domain!
{% endhint %}

## Proxies, Load Balancers and Ports

If you use any kind of proxy before the container, or if you use a custom port, please note that you might need to adjust a few things here.

So your proxies obviously need to listen to that domain too and forward it to the Shopware container.

Also, if you use a custom port, please make sure that this port is also accessible by exposing it within your Docker infrastructure like in this example

```
image: dockware/shopware:latest
ports:
    - "80:80"
    - "1000:1000" # new 1000 port that is used in sales channel
```

{% hint style="info" %}
If you change the port, you have to edit your saleschannel domains in the database, otherwise shopware will not find a matching saleschannel.

For the example above you would have to do something like:

<http://my.fancy-shop.com:1000>
{% endhint %}


# Shopware and MySQL

**Can I use dockware in combination with other images?**

Dockware is a Docker image like every other image. You can combine it with 3rd party services such as Redis, Elasticsearch, a separate MySQL, Percona or anything else.

Make sure they are on the same Docker network and use the key names of the containers as host addresses.

Here's an example:

{% code title="docker-compose.yml" %}

```yaml
version: "3"

services:

    shopware:
      image: dockware/shopware:latest
      container_name: shopware
      ports:
         - "80:80"
      networks:
         - web

    db:
      image: mysql:5.7
      container_name: mysql
      networks:
        - web
      environment:
        - MYSQL_ROOT_PASSWORD=hidden
        - MYSQL_USER=shopuser
        - MYSQL_PASSWORD=secret
        - MYSQL_DATABASE=shopware

networks:
  web:
    external: false
```

{% endcode %}

To access the standalone MySQL instance you need to set the **correct host**.

{% hint style="info" %}
The host is the **name of your container** (here -> "db")
{% endhint %}

Different systems have different options to configure a database connection string.\
In Shopware 6, it would be inside the **.env** file as DATABASE\_URL.\
In Shopware 5, it is in the **config.php** file.

{% code title="SHOPWARE 6 (.env file inside docker)" %}

```yaml
DATABASE_URL=mysql://shopuser:secret@db:3306/shopware
```

{% endcode %}


# Shopware and REDIS

## **How to use a Redis container?**

Redis is a Key/Value storage that allows you to save data outside your database with blazing fast access.\
Shopware supports the usage of Redis for session and cache handling.\
\
Here is a sample of a docker setup that adds a new Redis instance to your Docker network. Just add the container and make sure its on the same network.

{% code title="docker-compose.yml" %}

```yaml
version: "3"

services:
        
    shopware:
      image: dockware/shopware:latest
      container_name: shopware
      ports:
         - "80:80"
      networks:
         - web
      
    redis:
      image: redis:5.0.6
      container_name: redis
      networks:
        - web

networks:
  web:
    external: false
```

{% endcode %}

## **Shopware Configuration**

### **Connection**

Now make sure you configure the Redis instance to be used either for session handling, cache handling or both.

Add the following to your ".env" file:

{% code title=".env (partial)" %}

```yaml
REDIS_SESSION_HOST=redis
REDIS_SESSION_PORT=6379
REDIS_CACHE_HOST=redis
REDIS_CACHE_PORT=6379
```

{% endcode %}

### Use Redis Caches

Please note, that you also need to use it for specific parts in Shopware.

See this page for more: <https://developer.shopware.com/docs/guides/hosting/performance/caches#example-replace-some-cache-with-redis>


# Shopware and Elasticsearch

**How to use Elasticsearch?**

Elasticsearch is a full-text, distributed NoSQL database for big data.\
It has amazing options for real-time searching and data analyzing.\
\
Shopware recommends the usage of Elasticsearch for large data sets of products.\
They also support in its search engine for better search results.\
\
Here is a sample of a docker setup that adds a new Elasticsearch instance to your Docker network. Just add the container and make sure its on the same network.

{% code title="docker-compose.yml" %}

```yaml
version: "3"

services:
        
    shopware:
      image: dockware/shopware:latest
      container_name: shopware
      ports:
         - "80:80"
      networks:
         - web
      
    elasticsearch:
      image: elasticsearch:7.5.2
      container_name: elasticsearch
      networks:
        - web
      environment:
        - "EA_JAVA_OPTS=-Xms512m -Xms512m"
        - discovery.type=single-node

networks:
  web:
    external: false
```

{% endcode %}

Now make sure you configure the Elasticsearch instance to be used.

Add the following to your ".env" file:

{% code title=".env (partial)" %}

```yaml
SHOPWARE_ES_HOSTS=elasticsearch:9200
SHOPWARE_ES_ENABLED=1
SHOPWARE_ES_INDEXING_ENABLED=1
SHOPWARE_ES_INDEX_PREFIX=abc
```

{% endcode %}


# Import MySQL Dump

Sometimes you just want to import your own MySQL backup file.

This can be done in a very easy way, even without bind-mounting or copying the file into the container. It also does not have to do with dockware, so it would also work in a plain MySQL container.

## Import using Terminal

Run this command, and it will automatically import the **backup.sql** file from your **database** folder into your MySQL instance.

```bash
docker exec -i shop mysql -uroot -proot shopware < ./database/backup.sql
```

## Import using Adminer

Copy the backup file into your container. Make sure to place it in the folder **/usr/share/adminer**

```bash
docker cp adminer.sql.gz containerName:/usr/share/adminer/adminer.sql.gz

```

Now open Adminer in your web browser.

Open the section where you can import a databse dump.

You should now be able to seelct your dump directly in your browser and have Adminer importing it.

{% hint style="warning" %}
Please keep in mind to adjust your database credentials, if you have a custom configuration for that.
{% endhint %}


# Disable the Admin Worker

**It is not required to create custom Cron/Systemd tasks to replace the** [**Shopware admin worker**](https://docs.shopware.com/de/shopware-6-de/tutorials-und-faq/message-queue-und-scheduled-tasks).\
The dockware images have Cron tasks included that can be [activated by the flag](broken://pages/-MRt9LTzK3wKAq64g9e8).

## 1. Create a Shopware config file

E.g. `docker/sw-config/shopware.yaml`\
If you already have a Shopware config file, you should just add the admin worker config block.

```
# Map to: /var/www/html/config/packages/shopware.yaml
shopware:
    admin_worker:
        enable_admin_worker: false
```

## 2. Mount this file in your docker-compose.yaml

```
version: "3"

services:

   shopware:
      image: dockware/shopware:latest
      container_name: shopware_app
      volumes:
         - ./docker/sw-config/shopware.yaml:/var/www/html/config/packages/shopware.yaml:ro
```

## 3. Add the environment variable SW\_TASKS\_ENABLED to enable the integrated Cron tasks

```
version: "3"

services:

   shopware:
      image: dockware/shopware:latest
      container_name: shopware_app
      volumes:
         - ./docker/sw-config/shopware.yaml:/var/www/html/config/packages/shopware.yaml:ro
      environment:
         - SW_TASKS_ENABLED=1
```

## 4. Restart & activate

Restart your containers to apply the new config.

This can be done gracefully using docker-compose down && docker-compose up.

You can verify the enabled Cron tasks in the Docker logs:

```
shopware_app_DEV | -----------------------------------------------------------
shopware_app_DEV | DOCKWARE: starting cron service....
shopware_app_DEV |  * Starting periodic command scheduler cron
shopware_app_DEV |    ...done.
shopware_app_DEV | -----------------------------------------------------------
```

## 5. Make Shopware use the updated config

It is required to disable and enable any plugin to force Shopware to use the new shopware.yaml config.

You can check if the admin worker is disabled by using the open source [Tools Plugin from Friends of Shopware.](https://store.shopware.com/en/frosh12599847132f/tools.html)


# Multi-Environment Setups

Environments with multiple shops are indeed easy.\
In fact, the only important thing you need to take care of, is the correct routing.

Docker is routing based on the **domain** and **port** that you configure.\
You can either use different ports for your shops or use a full reverse proxy to make it even easier to use it.

{% hint style="info" %}
This tutorial will use a NGINX proxy for the routing, but always remember, you can also just use different ports like "1000:80", "1001:80" for your containers, or things like <https://traefik.io/>....
{% endhint %}

## Important to know

You can of course combine this approach with all other Docker images.\
So maybe you want a single MySQL image for all shop databases, or an Elasticsearch that all containers share? Feel free to build whatever you need!

That is the part where dockware is nothing more than a super cool Docker image with everything installed that you need to run Shopware. In that case you might even want to go with a **dockware/essentials** or **dockware/flex**.

The tutorial below will however focus on using the **dockware/dev** images that come with a full Shopware already installed. This means that we only need a single container for every shop that should be running. For a lot of people, this might be an easier approach, but still keep in mind - **only your creativity limits your setups**.

Both examples can be found in our[ example Github repository](https://github.com/dockware/examples):

| Example                      | Description                                                        | Link                                                                             |
| ---------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
| dockware/shopware            | Pre-Installed Shopware 6, ready to be used                         | <https://github.com/dockware/examples/tree/master/multi-environments/dev>        |
| dockware/shopware-essentials | 2 shops with custom installation and slimmer architecture (images) | <https://github.com/dockware/examples/tree/master/multi-environments/essentials> |

## Example with dockware/dev

### 1. docker-compose.yml

We start with our docker-compose.yml file.\
It contains a **dockware/proxy** image as well as **2 dockware/dev** images.\
\
While the main ports are only exposed through our proxy, both Shopware instances allow you to access their data with custom ports (SFTP + MySQL).\
\&#xNAN;*You can of course use bind-mounting and other approaches for this.*

The proxy has 2 configuration files that will be available with bind-mounting.\
These contain the full logic for the routings to our containers. (see next section).

<details>

<summary>Template: docker-compose.yml</summary>

```ruby
version: "3.8"

services:

  proxy:
    container_name: proxy
    image: dockware/proxy:latest
    ports:
      - "80:80"
      - "443:443"
      - "8888:8888"
      - "9999:9999"
      - "9998:9998"
    depends_on:
      - shop1
      - shop2
    volumes:
      - "./proxy/shop-1.conf:/etc/nginx/conf.d/shop-1.conf"
      - "./proxy/shop-2.conf:/etc/nginx/conf.d/shop-2.conf"
  # -----------------------------------------------------------------------
  shop1:
    image: dockware/dev:6.4.11.1
    container_name: shop1
    ports:
      - "2001:22"
      - "3001:3306"
  shop2:
    image: dockware/dev:6.4.11.1
    container_name: shop2
    ports:
      - "2002:22"
      - "3002:3306"
```

</details>

### 2. NGINX Configuration

Both shops get custom NGINX configuration file that are available in our proxy thanks to bind-mounting. You can do all kinds of fancy things in here.\
\
Below is a sample that ensures that **all traffic for shop1.shopware.com is routed though HTTPS 443 to your container**. It will also use the embedded self-signed certificates for SSL.

In addition to this, the sections below that routing help you to make the **watchers** work with your custom domain. You only need them if you want to use the watchers.

The watcher for the **administration** needs a few location settings that mainly focus on the port that is used for forwarding (8888 or 80).

The **storefront** watcher only listens to the required port 9998 and passes it on.\
At the moment, the pre-configured storefront watcher does only work with **LOCALHOST**.\
I haven't had any time to changes this in Shopware/dockware, so all requests will come in as localhost within your shop container (**proxy\_*****set*****\_header**). This means you only need to have **<http://localhost> in your Sales Channel** and you're good to go :)

{% hint style="warning" %}
The most important thing here, don't forget the correct **proxy\_pass** setting.\
This needs to be your Docker container name, like http(s)://{containerName}}.\
That will forward the traffic to this container.
{% endhint %}

<details>

<summary>Template: NGINX Configuration Shop 1</summary>

```bash
server {
    listen        80;
    server_name   shop1.shopware.com;
    return 301    https://$host$uri$is_args$args;
}

server {
    listen        443 ssl;
    server_name   shop1.shopware.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    location / {
        proxy_pass https://shop1;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    }
}

server {
    listen                    8888 ssl;
    server_name               shop1.shopware.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    location /admin {
        proxy_pass            http://shop1:8888;
        proxy_next_upstream   error timeout invalid_header http_500 http_502 http_503 http_504;
    }
    location /static {
        proxy_pass            http://shop1:8888;
        proxy_next_upstream   error timeout invalid_header http_500 http_502 http_503 http_504;
    }
    location /api {
        proxy_pass            http://shop1;
        proxy_next_upstream   error timeout invalid_header http_500 http_502 http_503 http_504;
    }
    location / {
        proxy_pass            http://shop1:8888;
        proxy_next_upstream   error timeout invalid_header http_500 http_502 http_503 http_504;
    }
}

server {
    listen                    9998;
    server_name               shop1.shopware.com;

    location / {
        proxy_set_header      Host    localhost;
        proxy_pass            http://shop1:9998;
        proxy_next_upstream   error timeout invalid_header http_500 http_502 http_503 http_504;
    }
}
```

</details>

### 3. /etc/hosts File

To tell your host system that shop1.shopware.com and shop2.shopware.com do indeed exist, please modify your **/etc/hosts** file on your host.

*This needs only been done once.*

Just use this snippet to configure, that all lookups for these 2 domains are resolved by simply pointing to localhost.

```
127.0.0.1     shop1.shopware.com
127.0.0.1     shop2.shopware.com
```

### 4. It's a wrap

That's it. If you now start your Docker containers, it should all work.

The only thing you need to configure, is the correct domains in your Sales Channels of both shops. Just head to **<https://shop1.shopware.com/admin>** and set the **domain for your Storefront Sales Channel**. Do this for both shops.

Our Github example shows you how to do this automatically within a makefile :)

{% hint style="success" %}
If you want to see a more convenient plug'n'play way with our makefiles, head to this page for more: <https://github.com/dockware/examples/tree/master/multi-environments/dev>
{% endhint %}


# CI/CD Tutorials


# Github

This page should give you instructions and some ideas on how to use dockware images in Github workflows and pipelines.

Please keep in mind, these might not always be 100% accurate samples, because some things like installing dependencies and so on, might work different in your project. In fact, some of these things are only related to projects, but you should get the idea.

{% hint style="info" %}
Are we missing something? Just let us know and we'd be happy to add it here!
{% endhint %}

## Cypress Tests

This is a perfect usage for dockware and its pre-installed Shopware version including demo data.\
Let's assume we have a plugin where we already have some Cypress tests that need a Shopware instance.

We want to run all these tests of our plugin in **mutliple Shopware versions** within Github.

We start by creating a job with a **matrix strategy**, where just provide the Shopware versions that we need. In addition to this, we want to test it with different PHP versions.

To avoid a combination of all possibilities, we just create a static list in here, but please feel free to use your own strategy configuration of Github actions!

The real pipeline is started by downloading the correct dockware version of our matrix value.\
Afterwards we start it with the `docker run` command and use the HTTPS port 443 as well as our correct PHP version. You can also use any other supported ENV variable in here.

Once started, we just give the container a bit **time to launch** MySQL and all its services. Usually you use a `waitFor` approach here, but this does also work really good.\
In addition to this, we imagine that we must not use `https://localhost` for our tests, due to some restrictions. So we even have the option to configure a different domain to be used locally within the Github Runner.

{% hint style="success" %}
Congratulations, your Docker infrastructure with dockware is done!
{% endhint %}

All we have to do now is to upload the files into our container, and intall and build our plugin as we would usually do.

Once completed, we can install Cypress and start to **run the tests against our domain** that we have just created for this pipeline.

If everything is done, we make sure to **always** download the logs and store those within our pipeline. By including the correct name of our shopware version from the matrix, we end up with a single ZIP file with logs and screenshots for all our Shopware versions.

{% hint style="info" %}
**Pro Tip:**\
\
If you want to see **all results** of all Shopware versions to detect patterns on problems in specific versions, then it might be a good thing to turn off "fail-fast" in the strategy.\
The full pipeline will still go on and takes longer even if problems occur, but you'll be rewarded with full results in the end!<br>

*strategy:*

*fail-fast: false*
{% endhint %}

```yaml
name: CI Pipeline

on:
  push:
    branches:
      - master

jobs:

  e2e:
    name: E2E Tests | Shopware ${{ matrix.shopware }}, PHP ${{ matrix.php }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - shopware: '6.7.2.2'
            php: '8.4'
          - shopware: '6.7.2.2'
            php: '8.3'
          - shopware: '6.7.2.1'
            php: '8.4'
    steps:

      - name: Clone Code
        uses: actions/checkout@v2

      - name: Download Docker
        run: |
          # attention, new shopware versions are in dockware/shopware
          # old versions might still be in dockware/play:x.y.z 
          docker pull dockware/shopware:${{ matrix.shopware }}
    
      - name: Start Docker
        run: |
          docker run --rm -p 80:80 -p 443:443 --name shop --env PHP_VERSION=${{ matrix.php }} -d dockware/shopware:${{ matrix.shopware }}
          sleep 30
          docker logs shop
          # now change the domain of our shop if required
          sudo echo "127.0.0.1 local.shopware.shop" | sudo tee -a /etc/hosts
          docker exec shop bash -c "mysql -u root -proot shopware -e \"UPDATE sales_channel_domain SET url='https://local.shopware.shop' WHERE url NOT LIKE 'default.%';\""
    
      - name: Upload into Docker
        run: |
          docker cp $(pwd)/. shop:/var/www/html/custom/plugins/MyPlugin
          docker exec shop bash -c 'sudo chown www-data:www-data /var/www/html/custom/plugins -R'
     
      - name: Install and Build Artifacts
        run: |
          docker exec shop bash -c 'cd /var/www/html/custom/plugins/MyPlugin && make install -B'
          docker exec shop bash -c 'cd /var/www/html/custom/plugins/MyPlugin && make build -B'
    
      - name: Install/Configure Plugin
        run: |
          docker exec shop bash -c 'php bin/console plugin:refresh'
          docker exec shop bash -c 'php bin/console plugin:install MyPlugin --activate'
          docker exec shop bash -c 'php bin/console system:config:set MyPlugin.config.MyKey ${{ secrets.MYKEY_TEST }}'
          docker exec shop bash -c 'php bin/console cache:clear'
   
      - name: Install Cypress
        run: cd tests/Cypress && make install -B

      - name: Start Cypress
        run: cd tests/Cypress && CYPRESS_BASE_URL=http://local.shopware.shop CYPRESS_SHOPWARE=${{ matrix.shopware }} ./node_modules/.bin/cypress run --headless

      - name: Download Logs
        if: ${{ always() }}
        run: |
          mkdir -p $(pwd)/Tests/Cypress/cypress/logs/shopware
          mkdir -p $(pwd)/Tests/Cypress/cypress/logs/apache
          docker cp shop:/var/www/html/var/log/. $(pwd)/Tests/Cypress/cypress/logs/shopware
          docker cp shop:/var/log/php/. $(pwd)/Tests/Cypress/cypress/logs/apache
      
      - name: Store Cypress Results
        if: ${{ always() }}
        uses: actions/upload-artifact@v2
        with:
          name: cypress_results_sw_v${{ matrix.shopware }}
          retention-days: 1
          path: |
            Tests/Cypress/cypress/logs
            Tests/Cypress/cypress/videos
            Tests/Cypress/cypress/screenshots
            
```

### Plugin Compatibility Checks

If you are a plugin developer, you may need to **approve plugin versions for new Shopware versions**. This means you need to test all plugins versions in the latest Shopware version, right?

Here's a pipeline that tests all your existing (hardcoded) plugin releases in a custom Shopware version.

The steps clone the plugin releases based on **Github Tags**. These tags are then used for the **matrix strategy**, and all use the same provided Shopware version.

This should give you an idea on what is possible.

You can of course change the way how plugin versions are cloned, if you do not use tags, but something else in Github.

```yaml
name: Compatibility Pipeline

on:
  workflow_dispatch:
    inputs:
      swVersion:
        description: 'Shopware Version'
        required: true
      phpVersion:
        description: 'PHP Version'
        required: true
        options:
          - 7.4
          - 8.0
          - 8.1

jobs:

  e2e:
    name: Plugin v${{ matrix.plugin }} | Shopware ${{ github.event.inputs.swVersion }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        plugin: [ '1.2', '1.1', '1.0' ]
    steps:

      - name: Clone Code
        uses: actions/checkout@v2
        with:
          ref: refs/tags/v${{ matrix.plugin }}

      - name: Download Docker
        run: |
          docker pull dockware/shopware:${{ github.event.inputs.swVersion }}

      - name: Upload into Docker
        run: |
          docker cp $(pwd)/. shop:/var/www/html/custom/plugins/MyPlugin
          docker exec shop bash -c 'sudo chown www-data:www-data /var/www/html/custom/plugins -R'
     
      - name: Install and Build Artifacts
        run: |
          docker exec shop bash -c 'cd /var/www/html/custom/plugins/MyPlugin && make install -B'
          docker exec shop bash -c 'cd /var/www/html/custom/plugins/MyPlugin && make build -B'
    
      - name: Install/Configure Plugin
        run: |
          docker exec shop bash -c 'php bin/console plugin:refresh'
          docker exec shop bash -c 'php bin/console plugin:install MyPlugin --activate'
          docker exec shop bash -c 'php bin/console system:config:set MyPlugin.config.MyKey ${{ secrets.MYKEY_TEST }}'
          docker exec shop bash -c 'php bin/console cache:clear'

      - name: Install Cypress
        run: cd tests/Cypress && make install -B

      - name: Start Cypress
        run: cd tests/Cypress && CYPRESS_BASE_URL=http://local.shopware.shop CYPRESS_SHOPWARE=${{ github.event.inputs.swVersion }} ./node_modules/.bin/cypress run --headless
        
```


# Gitlab

This page should give you instructions and some ideas on how to use dockware images in Gitlab workflows and pipelines.

Please keep in mind, these might not always be 100% accurate samples, because some things like installing dependencies and so on, might work different in your project. In fact, some of these things are only related to projects, but you should get the idea.

{% hint style="info" %}
Are we missing something? Just let us know and we'd be happy to add it here!
{% endhint %}

## Building and Testing

Dockware has been built to have everything on board that you need for a smooth Shopware developer experience.

You can of course use those images in your build pipeline for whatever task you need to do. This can range from simple dependency installation, on to building of storefront and administration as well as unit testing, execution of static analyzers and more. Everything you usually need should be already installed (of course no project dependent dependencies and tools haha).

To use dockware for your actions, just add a new step and provide any of the available dockware images. Then within your scripts, do whatever you want :)

{% hint style="info" %}
Please note, to keep it simple, we've removed caching options of vendors, artifacts and more in the sample below. Let us know, if you need it :)

Also, our new dockware/shopware images focus on new Shopware versions. But you can of course use the old dockware/play (or dev) images. They are still existing and working
{% endhint %}

```yaml
phpstan:
    image: "dockware/shopware:6.7.2.2"
    script:
        - cd /var/www/html/custom/plugins/MyPlugin && composer install
        - cd /var/www/html/custom/plugins/MyPlugin && php vendor/bin/phpstan analyse -c phpstan.neon .
        
phpunit:
    image: "dockware/shopware:6.7.2.2"
    script:
        - cd /var/www/html/custom/plugins/MyPlugin && composer install
        - cd /var/www/html/custom/plugins/MyPlugin && php vendor/bin/phpunit --configuration phpunit.xml.dist

install:
    image: "dockware/shopware:${SW_VERSION}"
    parallel:
        matrix:
            -   PHP_VERSION: [ "7.4", "8.0" ]
                SW_VERSION: [ "6.7.2.2", "6.7.2.1", "latest" ]
    script:
        - cd /var/www/html/custom/plugins/MyPlugin && composer install
        - cd /var/www/html && php bin/console plugin:refresh
        - cd /var/www/html && php bin/console plugin:install --clearCache --activate MyPlugin
        - cd /var/www/html && php bin/console plugin:list

        
```

{% hint style="success" %}
Thank you to Uwe (Kellerkinder) and Jonas (Basecom) for providing some great Gitlab examples for us!
{% endhint %}


# Bitbucket

This page should give you instructions and some ideas on how to use dockware images in Bitbucket workflows and pipelines.

Please keep in mind, these might not always be 100% accurate samples, because some things like installing dependencies and so on, might work different in your project. In fact, some of these things are only related to projects, but you should get the idea.

{% hint style="info" %}
Are we missing something? Just let us know and we'd be happy to add it here!
{% endhint %}

## Pipeline image vs. Steps with containers

You have 2 different options to use dockware (or any other image) within a Bitbucket pipeline.

You can either run your **full pipeline inside a dockware image**, or use dockware as a **standalone container** that hosts your Shopware (or other app) just like you would do it locally.

When do you need what? That is totally up to you, but we still have a few words on that.

Let's assume there are different commands, next to each other, that you usually also do within your container while developing your system. It would indeed make sense to just use a single image for your pipeline, and run all your commands in it. That just feels...tight..right?

On the other hand, as soon as you start to interact with your system from an "external point of view"...maybe with Cypress, then it would indeed make more sense, to launch a new container within your steps. You can even mount your source code into your container by using this variable **$BITBUCKET\_CLONE\_DIR.**

Here are short snippets for both ways.

### Pipeline Image

```yaml
image: dockware/web:latest

pipelines:
  default:
    - step:
        name: PHPUnit
        script:
          - composer install
          - php vendor/bin/phpunit --configuration phpunit.xml
```

### Containers in Pipeline

```yaml
clone:
  depth: 1
options:
  max-time: 10

pipelines:
  default:
    - step:
        name: Check Code
        services:
          - docker
        caches:
          - docker
        script:
          - docker run --rm -p 80:80 --name=shopware -e PHP_VERSION=8.1 -v $BITBUCKET_CLONE_DIR:/var/www/html -d dockware/web:latest
          - docker exec shopware bash -c 'make dev'
          - docker exec shopware bash -c 'make phpunit -B'
          - docker exec shopware bash -c 'make stan -B'
```

{% hint style="info" %}
Please keep in mind, the samples below work with both ways. But we cannot always show both of them! Please consider this!
{% endhint %}

## Building and Testing

Dockware has been built to have everything on board that you need for a smooth Shopware developer experience.

You can of course use those images in your build pipeline for whatever task you need to do. This can range from simple dependency installation, on to building of storefront and administration as well as unit testing, execution of static analyzers and more. Everything you usually need should be already installed (of course no project dependent dependencies and tools haha).

To use dockware for your actions, just add a new step and provide any of the available dockware images. Then within your scripts, do whatever you want :)

```yaml
image: dockware/web:latest

clone:
  depth: 1
options:
  max-time: 10

pipelines:
  default:
    - step:
        name: PHPUnit
        caches:
          - dockware-composer
          - node
        script:
          - composer install
          - php vendor/bin/phpunit --configuration phpunit.xml.dist

definitions:
  caches:
    dockware-composer: /var/www/.cache/composer
    node: /var/www/.npm    
```


# Buddy

Buddy ([https://app.buddy.works](https://app.buddy.works/)) is a great CI/CD tool that can be used as SaaS or OnPremise version. This page gives you instructions and some ideas on how to use dockware images in Buddy pipelines.

Please keep in mind, these might not always be 100% accurate samples, because some things like installing dependencies and so on, might work different in your project. In fact, some of these things are only related to projects, but you should get the idea.

{% hint style="info" %}
Are we missing something? Just let us know and we'd be happy to add it here!
{% endhint %}

## Building, Testing, ...

Dockware has been built to have everything on board that you need for a smooth Shopware developer experience.

You can of course use those images in your build pipeline for whatever task you need to do. This can range from simple dependency installation, on to building of storefront and administration as well as unit testing, execution of static analyzers and more. Everything you usually need should be already installed (of course no project dependent dependencies and tools haha).

To use dockware for your actions, just add a new **Custom Build** action, open the **Environment** tab and select the dockware image and version that you want to use.

![](/files/CfCWgQWzCxKFHngVtyrt)

This will automatically start a new dockware container and run the commands your action in this container.

### Entrypoint

When dockware images are launched in the "Command Runner" mode (so just to execute things), then we also execute our entrypoint script. This script makes sure to switch to your requested PHP version, start MySQL and more.

If you want to speed up things, and do not need anything special from what is being done there, you could also turn off this behaviour by simply checking the option "**Reset the default entrypoint set by the image**" in the Buddy environment setting of this action.

Please note that some features might not work if you turn this off.

![Reset the default dockware entrypoint](/files/9Ha0xS7tE9LtsKxcvZcB)

### Permissions

There is one thing to keep in mind!\
We try to be as strict as possible in dockware with our approach on simulating a real server where you probably dont have "root" access in lots of cases.

Unfortunately this interfers with Buddy when it comes to public keys.\
Buddy automatically mounts the "id\_rsa" into your container, so it can be used out of the box.\
That could lead to permission problems.

**The solution is easy.** You can just run the container in Buddy as "**root**". That's it.\
This user has the most permissions anyway, so there's no reason why anything might not work.

![](/files/GtCFNoZvFiMuzHA2BhAa)

{% hint style="success" %}
Aweseome, you should now be able to run almost anything that might be important for your Shopware shop pipeline or action!
{% endhint %}

## Cypress Tests

This is a perfect usage for dockware and its pre-installed Shopware version including demo data.\
Let's assume we have a plugin where we already have some Cypress tests that need a Shopware instance.

We have to decide where we want to run our tests against. These might be some options for you.

* Run tests against a **Shopware instance inside Buddy**\
  (we'll cover this below).<br>
* Run tests against a **Shopware instance on a server**\
  (Buddy would only run Cypress in an action. Your Cypress tests (aka the BASE\_URL) should then run against your server domain).

As already mentioned, we go with the first approach, to run the tests against a Shopware instance, that we launch directly **within Buddy** (on the fly).

This can be done in various ways.

The most familiar one (if we face your current local setup) might be the [**Docker CLI action**](https://buddy.works/docs/docker/docker-cli) in Buddy. This allows you to launch a plain Ubuntu with Docker and do whatever you want to do with it.

A different approach might be to use [Additional Services](https://buddy.works/docs/pipelines/services/services-and-databases) next to your pipeline.

But for today we keep it as straight forward and flexible as possible and go with the Docker CLI.

### Add Action

Add a new action in Buddy and select the Docker CLI.

<figure><img src="/files/cp5mctyR7yqh58FOqNJW" alt=""><figcaption></figcaption></figure>

Once created, open the **Run** tab.

This gives you access to the simple text editor section, where you can add separate commands line per line.

<figure><img src="/files/BnnZvRhWhqDOwMJv78Fx" alt=""><figcaption></figcaption></figure>

The commands we add to this area will start by downloading the correct dockware version that we need. This can either be done statically, or through Buddy variables (or whatever you come up with).

Afterwards we start it with the `docker run` command and use the HTTP port 80 as well as our required PHP version. You can also use any other supported ENV variable in here.

Once started, we just give the container a bit **time to launch** MySQL and all its services.

{% hint style="success" %}
Congratulations, your Docker infrastructure with dockware is done!
{% endhint %}

All we have to do now is to upload the files into our container, and intall / build our plugin as we would usually do.

Once completed, we can install Cypress and start to **run the tests against our domain** that we have just created for this pipeline. We use a separate Cypress image that has everything prepared. Please note that our host is already a Docker container, so you might get errors when trying to launch Cypress on your own (Error: spawn Xvfb ENOENT). So just use the [official Cypress images](https://hub.docker.com/r/cypress/included).

To give the Cypress container access to your dockware container, just reuse the network of your hosting system (Ubuntu VM).

{% hint style="success" %}
That's it, your Cypress tests should now run!
{% endhint %}

### Cache Docker Images

To speed up your execution the next time your pipeline runs, we recommend attaching the cache driver to the VM. This will also cache the pulled docker images, so that they can be reused the next time this action runs.

<figure><img src="/files/mYmSgUw1PX5SIilE6Cce" alt=""><figcaption></figcaption></figure>

### Full Script

Here is the full script that you can use as a template for your custom setup.

```bash
docker run --rm -p 80:80 --name shop -d dockware/shopware:6.6.10.2
sleep 30
docker logs shop

docker cp ./plugin/. shop:/var/www/html/custom/plugins/DockwareSamplePlugin
docker exec shop bash -c 'sudo chown www-data:www-data /var/www/html/custom/plugins -R'

docker exec shop bash -c "php bin/console plugin:refresh"
docker exec shop bash -c "php bin/console plugin:install DockwareSamplePlugin --activate"
docker exec shop bash -c "php bin/console cache:clear"

cd ./plugin/tests/Cypress 
docker run --network host -v $PWD:/e2e -w /e2e -e CYPRESS_BASE_URL=http://localhost cypress/included:10.8.0
```


# Error Port not available

If you start your container and you get an error such as this one, then it does only mean that you already have a service (or another Docker container) running on that port.

```bash
Ports are not available: listen tcp 0.0.0.0:80: bind: An attempt was made to access a socket 
in a way forbidden by its access permissions
```

"Localhost" along with the port of a container are the unique identifier in Docker.\
This means, that a container cannot be started if the port is already blocked.

To fix this please use these steps.

### 1. Verify Docker Containers

Check all your existing Docker containers and remove the one, that uses the port that you need for your new container.

```bash
# show ALL containers
docker ps -a

# remove our old container
docker rm -f (container_name)
```

### 2. Verify other services

If no Docker container uses your port, it might be a native service or another application.\
For example, a locally installed MySQL instance might already block our Port 3306, so Docker cannot use it.

```bash
#find port 80 usage on mac or linux
sudo lsof -i -n -P | grep :80
```

exmaple output:\
`com.docke 743 myusername 77u IPv6 0xa05aaf696f157485 0t0 TCP *:80 (LISTEN)`

In that case, make sure to either disable these services, or maybe use a different port for your Docker container if possible.


# Xdebug not working

We love rock solid debugging tools and so do you!

XDebug is by far one of the most important debugging tools for PHP developers out there.\
That's why our dockware #dev images come with a plug'n'play solution out of the box.

All you need is the recommended Chrome Extension for XDebug.

Download the extension here:\
<https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc?hl=en>

## Configure Xdebug in Dockware

As soon as you start your dockware container with the environment variable **XDEBUG\_ENABLED=1**, you're ready to go.\
This environment variable helps you to turn ON or OFF XDebug in case you want to switch over to a production similar environment for some tests.

```yaml
shopware:
      image: dockware/shopware:latest
      ...
      environment:
         - XDEBUG_ENABLED=1 // 1|0 for ON|OFF
```

## **Use Xdebug**

### **Use with Browser (Chrome)**

Enable Xdebug in your Chrome extension by clicking on the option "Debug".\
Now start your XDebug listener in your IDE and start debugging.

![enable Xdebug in Google Chrome](/files/-MSBuBK7AZHr3IQrSIFX)

### **Use with API clients**

You might want to debug your API requests or other requets in clients without the Xdebug Helper Tool. In this case you can simply append *`XDEBUG_SESSION_START=PHPSTORM`* as a get parameter to your Url, and it will also debug this request.

**Toggling Xdebug**

{% hint style="danger" %}
As Xdebug will slow down your dev environment for every request and also for each command like "cache:clear, watch-storefront" etc. You might not want to enable it all the time. For this we have built another useful command.
{% endhint %}

In our global makefile in /var/www we provide the commands for instantly enabling and disabling Xdebug.

`cd /var/www && make xdebug-on`

`cd /var/www && make xdebug-off`

## **Advanced Configuration**

We do also have additional environment variables, that you can use for further configuration.\
Please see our section about [Environment Variables](broken://pages/-MRt9LTzK3wKAq64g9e8) for more.

{% hint style="warning" %}
**XDEBUG and LINUX**\
Both MAC and Windows have the Docker variable "host.docker.internal" as default value, which should work great as Loopback IP to automatically recognize the host IP.

For Linux however this does not work! Please use **172.17.0.1** this as ENV variable to make it work!\
\
Here is a sample for a docker-compose.yml:

```
environment:
    - XDEBUG_REMOTE_HOST=172.17.0.1
```

{% endhint %}

{% hint style="warning" %}
**XDEBUG and WSL2**\
If you use docker on Windows with WSL2 you have to set your local ip address from the host in this env variable.

Here is a sample for a docker-compose.yml:

```
environment:
    - XDEBUG_REMOTE_HOST=192.168.178.42
```

{% endhint %}

## Troubleshooting

Here are a few things you can do, if its not yet working.

#### 1. Is XDebug activated?

See the startup output of your dockware container.\
It should show an output for PHP which should also display an activated XDebug.

```bash
docker logs (container_name)
```

#### 2. PHP Storm / IDE Configuration

Make sure that you have a correct mount configuration.\
This means that the root of your project should match the set root of your container.\
Also make sure that you have started the XDebug listener in PHPStorm for example.

#### 3. Chrome Extension

Do you have the correct chrome extension in the latest version installed?\
(see link above)

#### 4. Local PHP that blocks Port?

Do you have a local PHP installation on your host machine that might block the required port 9000?\
Make sure to kill this process. You can use the following snippet to find out if anything blocks your port.

```bash
lsof -i TCP:9000
```


# Troubles in Chrome

> **Google Chrome shows "Your connection is not private"**
>
> This can happen if you use localhost in combination with https. Please open this URL in your Chrome Browser to access the chrome settings:\
> \
> \&#xNAN;*\*\**<chrome://flags/#allow-insecure-localhost>\
> \
> Then set `"Allow invalid certificates for resources loaded from localhost."` to be enabled.

<figure><img src="/files/RCf7eFBK7eWkzDMDYY5o" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/4MlzwYA5mZ7hZrJmCA7o" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If Google Chrome don't show you the "Proceed to ... (unsafe) link, you can just type "thisisunsecure" and chrome will go ahead.\
Just focus the chrome main window with the mouse, and start typing, you won't see any input, but it will work.
{% endhint %}


# Container hangs in Pipeline

Previous images had a bug in the way how the entrypoint was implemented.

This led to the issue, that the whole **entrypoint was not executed** at all, when executing a custom command.

So a code like this actually used PHP 7.4 instead of PHP 8.0:

```bash
docker run -e PHP_VERSION=8.0 dockware/web:latest bash -c 'php -v'
```

We were able to fix the way how the entrypoint was called.\
This means, that it's now always called, also when providing a custom argument.

While doing this, we figured out that the container was then frozen after executing the command.\
The reason is the way how dockware should work. It should be an **everlasting container** that hosts your Apache / Shopware and should not immediately exit.

Unfortunately this is not what you want to have, when using dockware as plain **command runner**.

Again, we found a way.

\
If you now provide a custom argument like above, the entrypoint is executed, then your command is executed and afterwards the container should exit.\
If you do not provide a custom command, then it should be in a blocking mode, so that you can use it as before.

If for some reason, the container is not existing after executing your custom command, use the DOCKWARE\_CI variable either as ENV. If you Docker runner cannot provide environment variables, then it's also possible to set it within your custom command.

```bash
docker run -e DOCKWARE_CI=1 dockware/web:latest bash -c 'php -v'

docker run dockware/flex:latest bash -c 'export DOCKWARE_CI=1 && php -v'
```

{% hint style="warning" %}
Remember: It should not be required to use the DOCKWARE\_CI variable, but if you need to, there are different ways to allow all kinds of Docker runners.
{% endhint %}


# Troubles on Windows

**Can't connect into container on Windows**

If your terminal says that you don't have a tty or interactive terminal, you might want to prefix **winpty** which should work for you:

{% code title="ON HOST" %}

```
winpty docker exec -it shopware bash
```

{% endcode %}

**System cannot find the path specified in "docker cp".**

Some directories and paths are long in Shopware...really long :).\
Unfortunately Windows might tell you this too. The good thing is, there's a fix for long file names.

Please try these things:

* Move your project to **C:\\** which might shorten things automatically if you've had a deeper directory before.
* If you are on Windows 10, you can enable long paths. Open the Computer Configuration > Administrative Templates > System -> Filesystem > **Enable NTFS long paths**. You can also modify the corresponding registry entry **HKLM\SYSTEM\CurrentControlSet\Control\FileSystem** to **LongPathsEnabled** (Type: REG\_DWORD) to remove most of the MAX\_PATH limitations.

## Problems with log path via docker cp

{% hint style="info" %}
As this is a problem in combination with\
1\. docker\
2\. shopware file structure\
3\. Windows\
we can't fix this for you, but we can work a bit around it
{% endhint %}

1. you have to open your terminal "cmd" with admin rights.
2. it's possible that also long paths does not work so there will be some folder which can't be downloaded. In this case we recommend zipping the content within the container, copy and unzip:

   2.1 `docker exec -it CONTAINERNAME zip -r dockware.zip ./`

   2.2 `docker cp CONTAINERNAME:/var/www/html/dockware.zip C:\my\path\dockware.zip`
3. right click zip file -> unzip

the unzip process will show you some notifications that file XY can't be extracted as of path length, please skip this files to get all others to your local path.


# Shopware Version not found

With "dockware - the next generation", we have restructured all our images.\
A better transparency, improved maintainability and way smaller Docker image sizes.

Therefore we had to do a "cut" and build a new repository.

We have decided to start with the new Shopware 6.7.x.x versions that are supported by these new images. This means, that older Shopware versions are not part of this.

### When is a new version available?

We are usually very fast when it comes to rollouts of new Shopware versions.\
Mostly a new version is available within a day or even hours, after the official release of Shopware.

If you want to speed up things and help, we are happy to have Pull Requests being made.

### How to access old versions?

If you need older Shopware versions, you can of course use them by using the previous Docker images **dockware/dev** and **dockware/play**. These will continue to work and all these Shopware versions can of course be used again.

### I need an old Shopware version in the next-generation image

If you need old Shopware versions in the new image dockware/shopware, then just let us know.\
We are open to add these if requested.

We just wanted to skip adding so many Shopware versions, that might not even be needed anymore (6.1, 6.2 and more).


# Shopware Services

> Dockware is open-source and free. If you need someone who builds the Shopware shop itself — migration, B2B logic, plugins, performance, full rebuild — that's what we do at [dasistweb](https://dasistweb.de).

***

## When People Reach Out

Most developers land on Dockware because they need a local Shopware environment that just works. Some of them end up asking a different question later: "We've got this Shopware project and we need actual help with it. Can you do that too?"

Yes. That's the other half of what we do at [dasistweb](https://dasistweb.de) — the [Shopware agency](https://dasistweb.de/technologien/shopware) behind Dockware.

***

## What We Typically Work On

### Shopware migrations and replatforming

Moving from Shopware 5 to 6. Moving from Magento, OXID, custom legacy systems or other platforms to Shopware. Data migration, plugin rebuilds, frontend rework, launch planning without downtime. We've done this at GMV levels from 5 to 150 million EUR.

→ [Replatforming & migration](https://dasistweb.de/leistungen/replatforming)

### B2B Commerce

B2B is where Shopware gets complicated fast. Pricing tiers per customer group, approval workflows, quotes, credit limits, order pads, ERP integrations, user portals. We build B2B portals that handle real business logic, not just a "B2B toggle" in the admin.

→ [B2B Commerce](https://dasistweb.de/leistungen/b2b-commerce)

### Custom Shopware plugins

Standard plugins don't cut it? We build custom plugins for shops and, separately, for technology providers who want a proper Shopware plugin in the Store. Shopware-best-practice code, tested, maintained.

→ [Custom plugin development](https://dasistweb.de/leistungen/plugin-entwicklung)

### Integrations and APIs

ERP, PIM, CRM, warehouse, marketplace, shipping, payment, tax, analytics. We connect Shopware to whatever system already runs the business. Microservice architecture, clean API contracts, proper error handling.

### Shopware project takeovers

Your current agency isn't delivering anymore? Project stuck? Code quality issues piling up? We take over running projects, clean them up, bring structure back in. No drama, no finger-pointing.

***

## Why dasistweb

* [Shopware partner](https://dasistweb.de/technologien/shopware) since 2012, moved up through every partnership tier, currently at Gold level
* Shopware 6 co-developer since 2018
* 56+ Shopware platform certifications
* 25+ specialists, 80 percent at senior level
* Average client relationship of 5+ years
* Based in Kolbermoor near Munich, Germany

We care about [engineering depth](https://dasistweb.de/leistungen), not buzzwords. We say no when a project doesn't fit. We write honest estimates. We stay after go-live.

***

## How to Start

There's no gatekeeping. Send a short message describing what you have and what you want. We'll reply with an honest take — including "this doesn't fit us" if that's the right answer.

* **E-mail:** <hello@dockware.io> (Dockware-related) or via [dasistweb.de/kontakt](https://dasistweb.de/kontakt) (Shopware projects)
* **Website:** [dasistweb.de](https://dasistweb.de)

If you just want to browse what we do first, the [Shopware page at dasistweb](https://dasistweb.de/technologien/shopware) has the full picture.


# Founders

> Dockware is built and maintained by [dasistweb](https://dasistweb.de), a Shopware partner since 2012 (currently at Gold level) and co-developer of Shopware 6 since 2018. We've been shipping Shopware projects for 14+ years. Dockware is the dev setup we built for ourselves first, then for the community.

***

## The People Behind Dockware

### Martin Weinmayr

**Founder, Developer, CEO of dasistweb GmbH**

Martin wrote the first version of Dockware. He shaped the architecture and solved most of the hard problems along the way. The reason Dockware "just works" for so many Shopware devs is usually that Martin already had a strong opinion on how it should work, long before the first Docker image was pushed.

He still writes code in the core of Dockware today. He also runs [dasistweb](https://dasistweb.de), the [Shopware agency](https://dasistweb.de/technologien/shopware) behind the project. Long-time Shopware developer, Shopware 6 co-developer since 2018.

* LinkedIn: [martin-weinmayr](https://www.linkedin.com/in/martin-weinmayr/)

> "We built Dockware because spinning up a fresh Shopware environment on a Monday morning shouldn't cost you two coffees and your good mood."

***

### Christian Dangl

**Founder, Core Contributor**

Christian is a well-known name in the Shopware community. Conference speaker, PHP developer, and a solid contributor to Dockware v2. If you've opened an issue on GitHub in the last couple of years, there's a good chance you've talked to him.

* GitHub: [boxblinkracer](https://github.com/boxblinkracer)
* LinkedIn: [cdangl](https://www.linkedin.com/in/cdangl/)

***

## Why Dockware Exists

Before Dockware, every new Shopware developer we onboarded lost two or three days on environment setup. Wrong PHP version, broken permissions, MySQL not talking to Elasticsearch, that one colleague's laptop where it "just works" for reasons nobody can explain.

We got tired of it. So we built our own Docker images. Opinionated, pre-installed with demo data, versioned per Shopware release. First just for us. Then the Shopware community asked us to open-source it. So we did.

Today Dockware is used by freelancers, agencies, and in-house dev teams across the Shopware ecosystem. It stays free, open, and actively maintained because we use it ourselves, every day, on real client projects.

***

## Built and Maintained by dasistweb

Dockware is a product of [**dasistweb GmbH**](https://dasistweb.de), based in Kolbermoor near Munich. We're a team of 25+ specialists, 80 percent on senior level, with an average team tenure of 6+ years.

**What we do at dasistweb:**

* [E-commerce platforms](https://dasistweb.de/leistungen) on Shopware, Shopify and commercetools
* [B2B Commerce](https://dasistweb.de/leistungen/b2b-commerce) with pricing logic, approval flows, and portals
* [Replatforming & migration](https://dasistweb.de/leistungen/replatforming), including Shopware 5 to 6
* [Custom plugin development](https://dasistweb.de/leistungen/plugin-entwicklung) for shops and providers
* APIs, integrations, and data architecture behind it all

**Our Shopware track record:**

* [Shopware partner](https://dasistweb.de/technologien/shopware) since 2012, worked our way up through every partnership tier, currently on Gold level
* Shopware 6 co-developer since 2018
* 56+ Shopware platform certifications
* GMV range of our clients: 5 to 150 million EUR

If you need help with a real Shopware setup, a migration, a custom integration, or a full rebuild: that's what we do every day. [Get in touch](https://dasistweb.de/kontakt).

***

## Get in Touch

* **Bug or feature request:** open an [issue on GitHub](https://github.com/dockware)
* **Community chat:** our [Slack channel](https://slack.com/app_redirect?channel=C014X8HE8U8)
* **Docker images:** [hub.docker.com/u/dockware](https://hub.docker.com/u/dockware)
* **Commercial Shopware help:** [dasistweb.de/kontakt](https://dasistweb.de/kontakt)

***

*Dockware is free and open-source software, maintained by* [*dasistweb GmbH*](https://dasistweb.de/ueber-uns/team)*, a* [*Shopware agency*](https://dasistweb.de/technologien/shopware) *based in Kolbermoor, Germany.*


