Configuring a docker environment for a Magento 2 project
Tags: php, magento2, docker, tutorial
Published: 2023-07-25 19:09:07

This post will demonstrate how to configure a docker environment with the Warden tool for an existing Magento 2 project.

## Table of contents

- [What is Warden?](#what-is-warden)
- [Why Warden?](#why-warden)
- [Quickstart](#quickstart)
- [Requirements](#requirements)
- [Project Stack](#project-stack)
- [Configuring a single website/store Magento 2 project](#configuring-a-single-websitestore-magento-2-project)
    - [Creating the project folder](#1-creating-the-project-folder)
    - [Creating the project folder](#2-enter-the-created-directory)
    - [Clone the Magento 2 code-base into the code-base folder](#3-clone-the-magento-2-codebase-into-the-codebase-folder)
    - [Clone the Warden Magento 2 template](#4-clone-the-warden-magento-2-template)
    - [Update the warden .env file](#5-update-the-warden-env-file)
      - [A brief explanation of the keys in the .env file](#a-brief-explanation-of-the-keys-in-the-env-file)
    - [Run the docker environment](#6-run-the-docker-environment)
    - [Run composer install](#7-run-composer-install)
    - [Copy and rename the env.warden.php file](#8-copy-and-rename-the-raw-envwardenphp-endraw-file)
    - [Import the Magento 2 database](#9-import-the-magento-2-database)
      - [An Example of the content of this set-default-config.sh script](#an-example-of-the-content-of-this-raw-setdefaultconfigsh-endraw-script)
    - [Sign the SSL certificate](#10-sign-the-ssl-certificate)
    - [Update your /etc/hosts file with the store domain](#11-update-your-raw-etchosts-endraw-file-with-the-store-domain)
    - [Installing the sample data (Optional)](#12-installing-the-sample-data-optional)
- [Configuring a multiple website/store view Magento 2 project](#configuring-a-multiple-websitestore-view-magento-2-project)
  - [Create a project folder](#1-create-a-project-folder)
  - [Enter the created multisite directory](#2-enter-the-created-multisite-directory)
  - [Clone the Magento 2 code-base into the multisite code-base folder](#3-clone-the-magento-2-codebase-into-the-multisite-codebase-folder)
  - [Clone the Warden Magento 2 template](#4-clone-the-warden-magento-2-template)
  - [Change the warden .env file](#5-change-the-warden-env-file)
  - [Define custom variables for the store domains](#6-define-custom-variables-for-the-store-domains)
  - [Updates the the defaults config script](#7-updates-the-the-defaults-config-script)
  - [Run the docker environment](#8-run-the-docker-environment)
  - [Composer install](#9-composer-install)
  - [Copy and rename the env.warden.php file into the etc folder](#10-copy-and-rename-the-raw-envwardenphp-endraw-file-into-the-etc-folder)
  - [Import the Magento 2 multisite database](#11-import-the-magento-2-multisite-database)
  - [Sign the SSL certificates for all domains](#12-sign-the-ssl-certificates-for-all-domains)
  - [Append your /etc/hosts file with the store domains](#13-append-your-raw-etchosts-endraw-file-with-the-store-domains)
  - [Configuring the application domains](#14-configuring-the-application-domains)

### What is Warden?
[Warden](https://docs.warden.dev/index.html) is a CLI utility for orchestrating Docker-based developer environments that fully support Magento 1, Magento 2, Laravel, Symfony, and Shopware 6 on macOS, Linux and Windows (via WSL2).

### Why Warden?

- Warden lets you run multiple environments simultaneously without conflicting ports.
- Allows you to configure stack versions easily via .env file configuration.
- Provides the full stack needed for a Magento 2 development environment.
- You can extend it and add new features according to your needs.
- No need to version the docker environment in the project.

### Quickstart
We will configure two Magento 2 projects, the first project will have one website and one store view, and the second project will have multiple websites and store views.

The commands exposed here will work in Linux or macOS environment.

We will use the `~/Sites` directory to place the projects. Feel free to put your project in any path on your computer if you change the commands informed here.

For each project, the following directory structure will be used:
```
📦project-name
 ┣ 📂code-base
 ┗ 📂docker
```

- The `project-name/code-base` directory will contain the Magento 2 project code
- The `project-name/docker` directory will contain the warden template for our docker environment

**Note:** The structure above is just a personal taste to use in my projects, you can structure as you see fit. For example using the `~/.warden` directory

Your Magento 2 project can be versioned alone in the repository, and there is no need to change the directory architecture.

Here we'll use a [fork](https://github.com/cristiano-pacheco/warden-env-magento2) of the [Warden Magento 2 Template](https://github.com/davidalger/warden-env-magento2) that have a Makefile and a few common commands to facilitate the day-to-day work.

### Requirements
All you need is [Docker](https://docs.docker.com/engine/install/), [docker-compose](https://docs.docker.com/compose/install/) and [Warden](https://docs.warden.dev/installing.html) installed on your computer.

### Project Stack:

For a practical example, we will set up the development environment for an existing Magento 2 project with the stack below:

- Magento 2.4.4 open source
- Nginx 1.16
- PHP 8.1
  - Composer 2
  - Xdebug 3
- MariaDB 10.4
- Elastic Search 7.16
- Redis 6.2
- RabbitMQ 3.9

More details about the required stack for Magento 2 [here](https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements.html).

### Configuring a single website/store Magento 2 project

##### 1 Creating the project folder
```
mkdir ~/Sites/magento244
```

##### 2 Enter the created directory
```
cd ~/Sites/magento244
```

##### 3 Clone the Magento 2 code-base into the code-base folder
```
git clone git@github.com:cristiano-pacheco/magento244.git code-base
```

##### 4 Clone the Warden Magento 2 template
```
git clone git@github.com:cristiano-pacheco/warden-env-magento2.git docker
```

##### 5 Update the warden .env file 
Enter the docker directory
```
cd ~/Sites/magento244/docker
```

Update the .env file with the content below:

```
WARDEN_ENV_NAME=magento244
WARDEN_ENV_TYPE=magento2
WARDEN_WEB_ROOT=/../code-base

TRAEFIK_DOMAIN=magento244.test
TRAEFIK_SUBDOMAIN=app

WARDEN_DB=1
WARDEN_ELASTICSEARCH=1
WARDEN_VARNISH=0
WARDEN_RABBITMQ=1
WARDEN_REDIS=1

ELASTICSEARCH_VERSION=7.16
MARIADB_VERSION=10.4
NODE_VERSION=10
PHP_VERSION=8.1
PHP_XDEBUG_3=1
COMPOSER_VERSION=2
RABBITMQ_VERSION=3.9
REDIS_VERSION=6.2
VARNISH_VERSION=7.0
   
MYSQL_USER=magento
MYSQL_PASSWORD=magento
MYSQL_DATABASE=magento

WARDEN_SYNC_IGNORE=

WARDEN_ALLURE=0
WARDEN_SELENIUM=0
WARDEN_SELENIUM_DEBUG=0
WARDEN_BLACKFIRE=0
WARDEN_SPLIT_SALES=0
WARDEN_SPLIT_CHECKOUT=0
WARDEN_TEST_DB=0
WARDEN_MAGEPACK=0

BLACKFIRE_CLIENT_ID=
BLACKFIRE_CLIENT_TOKEN=
BLACKFIRE_SERVER_ID=
BLACKFIRE_SERVER_TOKEN=
```

#### A brief explanation of the keys in the .env file:
- **WARDEN_ENV_NAME**
It will be the prefix of the docker containers name and will also serve to [configure the xdebug](https://docs.warden.dev/configuration/xdebug.html) in your IDE
Example:

![warden-env-name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/an6t9bixxsgitk8sh733.png)


- **WARDEN_ENV_TYPE**
It will define the [docker compose yaml](https://github.com/davidalger/warden/tree/master/environments) files that will be used in the [environment](https://docs.warden.dev/environments.html), which can vary according to the chosen platform.
   
- **WARDEN_WEB_ROOT**
Self explained, you have to inform the root directory of the project.
   

- **TRAEFIK_DOMAIN**
Traefik is used to [route](https://doc.traefik.io/traefik/routing/routers/) the requests to the services (containers) dynamically. For example, when there is the cookie XDEBUG_SESSION with the value PHPSTORM, it will send the requests to the php-debug container that has the xdebug enabled. On the contrary, the php-fpm container will receive the request.
You can set the domain you want, just pay attention to the .test suffix, it you configure a domain with a different value you will lost the [Automatic DNS Resolution](https://docs.warden.dev/configuration/dns-resolver.html) feature.
   

- **TRAEFIK_SUBDOMAIN**
It is used to set a subdomain for your application, in our example the store can be accessed with the address `https://TRAEFIK_SUBDOMAIN.TRAEFIK_DOMAIN` that is: `https://app.magento244.test`
   
- **WARDEN_DB**, **WARDEN_ELASTICSEARCH**, **WARDEN_VARNISH**, **WARDEN_RABBITMQ**, **WARDEN_REDIS**

The keys above you can use 0 to disable and 1 to enable. When the value is 0 the container will not run.

- **_VERSION**
The keys with the suffix `_VERSION` is to set a specific version to the service. For Magento 2.4.3, for example, you may use PHP 7.4. To do it, you can leave the key as: `PHP_VERSION=7.4`

- **PHP_XDEBUG_3**
If you set this key with value `1`, a different [tag](https://hub.docker.com/r/wardenenv/php-fpm/tags) of the container [php-fpm](https://hub.docker.com/r/wardenenv/php-fpm) image will be used. Let's look at the docker-compose yaml generated by warden with the command `warden env config`:

![warden-env-config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/poruttzhwqfj60tmd7rw.png)

- **COMPOSER_VERSION**
If it has the value = 1 or you ommit this key composer in version 1 will be the default executable, however you can run composer in version 2 with the command `composer2`.

Example:
**If you omit or set the value 1 for `COMPOSER_VERSION`**
![composer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yb9lachtmlhc0acul2s2.png)

**If you set the value 2 for `COMPOSER_VERSION`:**
![composer2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j24n5un8pqql0x6fl4b4.png)

I prefer to inform the value 2 and already run composer in version 2 with the `composer` command.

There are more interesting things to configure such as Magento 2 tests, live reload, elastic search and more. You can see this information [here](https://docs.warden.dev/configuration.html).

##### 6 Run the docker environment
Inside the `~/Sites/magento244/docker` directory type:
```
make docker-up
```
##### 7 Run composer install
Inside the `~/Sites/magento244/docker` run the command 
below to access the PHP container
```
warden shell
```

Run the composer install command
```
composer install
```
   
##### 8 Copy and rename the `env.warden.php` file

It will copy the file to the `code-base/etc` directory with the command below:
```
cp ~/Sites/magento244/code-base/app/etc/env.warden.php ~/Sites/magento244/code-base/app/etc/env.php
```

The `env.warden.php` file has the default configuration entries with the warden hosts for the Mysql database, Redis (session and store cache), RabbitMQ, and Elastic Search.

##### 9 Import the Magento 2 database
There is a [sample database](https://github.com/cristiano-pacheco/magento244/blob/main/dump.sql.gz) inside our [Magento](https://github.com/cristiano-pacheco/magento244) project, so copy the `~/Sites/magento244/code-base/dump.sql.gz` file to `~/Sites/magento244/docker/backfill/magento-db.sql.gz` with the command below:
```
cp ~/Sites/magento244/code-base/dump.sql.gz ~/Sites/magento244/docker/backfill/magento-db.sql.gz
```
   
Open a new tab in your terminal and enter the directory `~/Sites/magento244/docker` and type the command below:
```
make db-import
```

The `db-import` command is one of the custom commands inside the Makefile.
   
This command imports the Magento-db.sql.gz database dump to the Magento database in the warden MySQL docker container.
   
In addition to importing the database, the `~/Sites/magento244/docker/tools/set-default-config.sh` script is then executed to define the project's base URL and create a user for the Magento administrative panel.

In the `~/Sites/magento244/docker/tools/set-default-config.sh` file, I usually put all the relevant settings to the Magento 2 environment to avoid errors and also to speed up the restoration of the environment as faithful as possible to the actual project.

Example of settings that are added in this file:

- Project base URLs
- Media and asset URLs
- Payment test credentials
- Changing the Algolia index to the development index, etc.
  
##### An Example of the content of this `set-default-config.sh` script:

```bash
#!/usr/bin/env bash

source $(dirname $0)/common.sh

:: Import the config from files
warden env exec -T php-fpm bin/magento app:config:import

:: Set BASE URL Config
warden env exec -T php-fpm bin/magento config:set web/unsecure/base_url ${URL_FRONT}
warden env exec -T php-fpm bin/magento config:set web/secure/base_url ${URL_FRONT}
warden env exec -T php-fpm bin/magento config:set web/unsecure/base_link_url ${URL_FRONT}
warden env exec -T php-fpm bin/magento config:set web/secure/base_link_url ${URL_FRONT}

:: Create an admin user
warden env exec -T php-fpm bin/magento admin:user:create --admin-user=admin --admin-password=123123q --admin-email=admin@example.com --admin-firstname=Admin --admin-lastname=Admin

```

##### 10 Sign the SSL certificate
Still, inside the `~/Sites/magento244/docker` directory, type the command below:
```
warden sign-certificate app.magento244.test
```

##### 11 Update your `/etc/hosts` file with the store domain:
```
sudo echo '127.0.0.1 app.magento244.test' >> /etc/hosts
```

**Note** Do the step above only if [dnsmasq](https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html) is not being used.
  
##### 12 Installing the sample data (Optional)
Access the php container:
```
warden shell
```

Run the command below to install the sample data:
```
bin/magento sampledata:deploy
```
    
Run the command below to update the project database
```
bin/magento setup:upgrade
```
  
Now you're able to access the store with the URLS \o/: 

**Store Address:** https://app.magento244.test
**Backend admin panel:** https://app.magento244.test/backend

![Store with single domain](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi3oyfrtnwjwt8y1l3ow.png)

### Configuring a multiple website/store view Magento 2 project

This Magento 2 store has been configured with the below structure of websites/stores/store views:


![store views](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izp3b1ixmdpt3lh0k6ao.png)

So, the main difference is how to configure a local warden environment to support multiple websites/store views with different domains.

##### 1 Create a project folder
```
mkdir ~/Sites/magento244-multisite
```

##### 2 Enter the created multisite directory
```
cd ~/Sites/magento244-multisite
```

##### 3 Clone the Magento 2 code-base into the multisite code-base folder
```
git clone git@github.com:cristiano-pacheco/magento244-multisite.git code-base
```

##### 4 Clone the Warden Magento 2 template
```
git clone git@github.com:cristiano-pacheco/warden-env-magento2.git docker
```

##### 5 Change the warden .env file
Enter the docker directory
```
cd ~/Sites/magento244-multisite/docker
```

Update the .env file with the content below:
```
WARDEN_ENV_NAME=magento244-multisite
WARDEN_ENV_TYPE=magento2
WARDEN_WEB_ROOT=/../code-base

TRAEFIK_DOMAIN=magento244-multisite.test
TRAEFIK_SUBDOMAIN=app

WARDEN_DB=1
WARDEN_ELASTICSEARCH=1
WARDEN_VARNISH=0
WARDEN_RABBITMQ=1
WARDEN_REDIS=1

ELASTICSEARCH_VERSION=7.16
MARIADB_VERSION=10.4
NODE_VERSION=10
PHP_VERSION=8.1
PHP_XDEBUG_3=1
COMPOSER_VERSION=2
RABBITMQ_VERSION=3.9
REDIS_VERSION=6.2
VARNISH_VERSION=7.0
   
MYSQL_USER=magento
MYSQL_PASSWORD=magento
MYSQL_DATABASE=magento

WARDEN_SYNC_IGNORE=

WARDEN_ALLURE=0
WARDEN_SELENIUM=0
WARDEN_SELENIUM_DEBUG=0
WARDEN_BLACKFIRE=0
WARDEN_SPLIT_SALES=0
WARDEN_SPLIT_CHECKOUT=0
WARDEN_TEST_DB=0
WARDEN_MAGEPACK=0

BLACKFIRE_CLIENT_ID=
BLACKFIRE_CLIENT_TOKEN=
BLACKFIRE_SERVER_ID=
BLACKFIRE_SERVER_TOKEN=
```

More details about the configuration above was shared in the [step 5](#a-brief-explanation-of-the-keys-in-the-env) of [Configuring a single website/store Magento 2 project](#configuring-a-single-websitestore-Magento-2-project)
   
##### 6 Define custom variables for the store domains

We will define custom variables in `~/Sites/magento244-multisite/docker/tools/common.sh` to be able to reuse them later in our `set-default-configs.sh` file:
```bash
URL_WEBSITE_TWO_FRONT=https://app.magento244-website-two.test/
URL_STORE_VIEW_THREE_US_FRONT=https://app.magento244-store-view-three-us.test/
URL_STORE_VIEW_THREE_DE_FRONT=https://app.magento244-store-view-three-de.test/
```
   
##### 7 Updates the the defaults config script

Add the content of [this file](https://github.com/cristiano-pacheco/warden-env-magento2/blob/multisite/tools/set-default-config.sh) to the `~/Sites/magento244-multisite/docker/tools/set-default-configs.sh` file.

The goal of the `set-default-configs.sh` script was explained [here](#An-Example-of-the-content-of-this-set-default-configsh-script).

##### 8 Run the docker environment
Inside the `~/Sites/magento244-multisite/docker` directory type:
```
make docker-up
```

##### 9 Composer install
Inside the `~/Sites/magento244-multisite/docker` run the command below to access the PHP container
```
warden shell
```

Run the composer install command
```
composer install
```
   
##### 10 Copy and rename the `env.warden.php` file into the etc folder

```
cp ~/Sites/magento244-multisite/code-base/app/etc/env.warden.php ~/Sites/magento244-multisite/code-base/app/etc/env.php
```
    
##### 11 Import the Magento 2 multisite database

There is a [sample database](https://github.com/cristiano-pacheco/magento244-multisite/blob/main/dump.sql.gz) inside our [Magento](https://github.com/cristiano-pacheco/magento244-multisite) project, so copy the `~/Sites/magento244-multisite/code-base/dump.sql.gz` file to `~/Sites/magento244-multisite/docker/backfill/magento-db.sql.gz` with the command below:
```
cp ~/Sites/magento244-multisite/code-base/dump.sql.gz ~/Sites/magento244-multisite/docker/backfill/magento-db.sql.gz
```

Open a new tab in your terminal and enter the directory `~/Sites/magento244-multisite/docker` and type the command below:
```
make DB-import
```
  
##### 12 Sign the SSL certificates for all domains

Still, type the commands below inside the `~/Sites/magento244-multisite/docker` directory.
   
To sign the certificate to the main and the admin store:
```
warden sign-certificate app.magento244-multisite.test
```
     
To sign the certificate to the website-two:
```
warden sign-certificate app.magento244-website-two.test
```
     
To sign the certificate to the Store View Three US:
```
warden sign-certificate app.magento244-store-view-three-us.test
```
     
To sign the certificate to the Store View Three DE:
```
warden sign-certificate app.magento244-store-view-three-de.test
```
     
     
##### 13 Append your `/etc/hosts` file with the store domains
```
127.0.0.1 app.magento244-multisite.test
127.0.0.1 app.magento244-website-two.test
127.0.0.1 app.magento244-store-view-three-us.test
127.0.0.1 app.magento244-store-view-three-de.test
```
**Note** Do the step above only if [dnsmasq](https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html) is not being used.

##### 14 Configuring the application domains:

According to the [Warden documentation](https://docs.warden.dev/configuration/multipledomains.html) we have to create a `warden-env.yml` file inside the `.warden` directory. Type the commands below:
  
Create the `.warden-env.yml` file
```
touch ~/Sites/magento244-multisite/docker/.warden/warden-env.yml
```
   
Put the content below to the `.warden-dev.yml` file:
```ymal
version: "3.5"
services:
  nginx:
    labels:
      - traefik.http.routers.${WARDEN_ENV_NAME}-nginx.rule=
        HostRegexp(`{subdomain:.+}.${TRAEFIK_DOMAIN}`)
        || Host(`${TRAEFIK_DOMAIN}`)
        || HostRegexp(`{subdomain:.+}.magento244-multisite.test`)
        || Host(`magento244-multisite.test`)
        || HostRegexp(`{subdomain:.+}.magento244-website-two.test`)
        || Host(`magento244-website-two.test`)
        || HostRegexp(`{subdomain:.+}.magento244-store-view-three-us.test`)
        || Host(`magento244-store-view-three-us.test`)
        || HostRegexp(`{subdomain:.+}.magento244-store-view-three-de.test`)
        || Host(`magento244-store-view-three-de.test`)
```

You can have a copy of this file [here](https://github.com/cristiano-pacheco/warden-env-magento2/blob/multisite/.warden/warden-env.yml).

When you're done with the settings, look at the [traefik address](https://traefik.warden.test/dashboard/#/http/routers) to see where this mapping ended up. It will be like as:


![traefik](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g09o7z2mum6btyi8f6qb.png)

Create `stores.php` the Add the Magento 2 run params to the project:
```
cd touch ~/Sites/magento244-multisite/code-base/app/etc/stores.php
```
   
Add the content of [this file](https://github.com/cristiano-pacheco/magento244-multisite/blob/main/app/etc/stores.php) in the file above.
    
Add the `app/etc/stores.php` to the `composer.json` file.
  
It should look like the image below after the change:

![multi-store-config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbk07awbxm6enr4ojm8c.png)

It will force composer to load this file on every request. the file then sets up the store for Magento to load based on the domain, passing the `MAGE_RUN_CODE` and `MAGE_RUN_TYPE` variables to Nginx.

Now you're able to access the stores with the URLS \o/: 

**Default Store Address**:
https://app.magento244-multisite.test

**Backend admin panel**:
https://app.magento244-multisite.test/backend

**Website Two Address**:
https://app.magento244-multisite.test

**Store View Three US Address**:
https://app.magento244-store-view-three-us.test

**Store View Three DE Address**:
https://app.magento244-store-view-three-de.test

**Note:** 
Inside the directory `~/Sites/magento244-multisite/code-base`, type the command make, and you will see an output like:

![make-command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/akp6pz2504cgp1jn8cy3.png)

That's it. If you have any questions, please let us know in the comments 👋