Technical Documentation

How to Setup a Docker-based Magento 2.3 Local Development Environment on Ubuntu 20.04 LTS in no time.

By July 14, 2021 August 11th, 2021 No Comments

Ever wondered how much time the average Magento 2 developer spends just setting up a reliable local development environment? The answer definitely varies from organization to organization, the stack in question, and the level of documentation available, and often takes longer than it should in a lot of cases.

This article is hopefully just one in a series of articles that will make using Docker less intimidating and help other Magento and Non-Magento developers get up and running quickly. The configurations shared are what we use at www.phpstudios.com but your specific requirements may differ, nonetheless, we think this article can help you get to where you want to be in less time. The ins and outs of Docker will be discussed in later articles since including all of that in this one post would probably be information overload.

Instructions

1. Install docker

sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io

To install a specific version of docker or if you run into any issues, review the documentation at this link https://docs.docker.com/engine/install/ubuntu/

2. Create a new working directory

mkdir magento-local-env && cd magento-local-env

3. Add a new domain to your /etc/hosts file, this domain will be used to navigate to your local Magento 2 instance

sudo su echo “127.0.0.1 local.magento.com” >> /etc/hostsexit

4. Create a docker-compose.yaml file and paste the configurations below into it.

vi docker-compose.yamlornano docker-compose.yaml

Docker-compose.yaml’s contents should be as follows:

version: ‘2.1’ services: db: hostname: db.magento2.docker image: ‘mariadb:10.1’ environment: – MYSQL_ROOT_PASSWORD=magento2 – MYSQL_DATABASE=magento2 – MYSQL_USER=magento2 – MYSQL_PASSWORD=magento2 ports: – ‘3306’ volumes: – ‘mymagento-magento-sync:/app:delegated’ – ‘mymagento-magento-db:/var/lib/mysql’ healthcheck: test: ‘mysqladmin ping -h localhost’ interval: 30s timeout: 30s retries: 3 networks: magento: aliases: – db.magento2.docker redis: hostname: redis.magento2.docker image: ‘redis:5.0’ volumes: – ‘mymagento-magento-sync:/app:delegated’ ports: – 6379 healthcheck: test: ‘redis-cli ping || exit 1’ interval: 30s timeout: 30s retries: 3 networks: magento: aliases: – redis.magento2.docker elasticsearch: hostname: elasticsearch.magento2.docker image: ‘magento/magento-cloud-docker-elasticsearch:6.5-1.1’ networks: magento: aliases: – elasticsearch.magento2.docker fpm: hostname: fpm.magento2.docker #image: ‘magento/magento-cloud-docker-php:7.3-fpm-1.1’ build: ‘.docker/PHP/’ extends: generic volumes: – ‘mymagento-magento-sync:/app:delegated’ networks: magento: aliases: – fpm.magento2.docker depends_on: db: condition: service_healthy web: hostname: web.magento2.docker image: ‘magento/magento-cloud-docker-nginx:latest-1.1′ extends: generic ports: – ’80:80’ volumes: – ‘mymagento-magento-sync:/app:delegated’ environment: – VIRTUAL_HOST=magento2.docker – VIRTUAL_PORT=80 – HTTPS_METHOD=noredirect – WITH_XDEBUG=1 networks: magento: aliases: – web.magento2.docker depends_on: fpm: condition: service_started varnish: hostname: varnish.magento2.docker image: ‘magento/magento-cloud-docker-varnish:6.2’ networks: magento: aliases: – magento2.docker depends_on: web: condition: service_healthy tls: hostname: tls.magento2.docker image: ‘magento/magento-cloud-docker-tls:latest-1.1’ ports: – ‘443:443’ environment: HTTPS_UPSTREAM_SERVER_ADDRESS: varnish networks: magento: aliases: – tls.magento2.docker depends_on: varnish: condition: service_started generic: hostname: generic.magento2.docker image: ‘alpine:latest’ env_file: ./.docker/config.env environment: – MAGENTO_RUN_MODE=developer – ‘PHP_EXTENSIONS=bcmath bz2 calendar exif gd gettext intl mysqli pcntl pdo_mysql soap sockets sysvmsg sysvsem sysvshm opcache zip sodium redis xsl blackfire’ build: hostname: build.magento2.docker image: ‘magento/magento-cloud-docker-php:7.3-cli-1.1’ extends: generic volumes: – ‘mymagento-magento-sync:/app:delegated’ networks: magento-build: aliases: – build.magento2.docker depends_on: db: condition: service_healthy redis: condition: service_healthy elasticsearch: condition: service_healthy deploy: hostname: deploy.magento2.docker image: ‘magento/magento-cloud-docker-php:7.3-cli-1.1’ extends: generic volumes: – ‘mymagento-magento-sync:/app:delegated’ networks: magento: aliases: – deploy.magento2.docker depends_on: db: condition: service_healthy redis: condition: service_healthy elasticsearch: condition: service_healthy fpm_xdebug: hostname: fpm_xdebug.magento2.docker image: ‘magento/magento-cloud-docker-php:7.3-fpm-1.1’ extends: generic ports: – ‘9001:9001’ volumes: – ‘mymagento-magento-sync:/app’ environment: – ‘PHP_EXTENSIONS=bcmath bz2 calendar exif gd gettext intl mysqli pcntl pdo_mysql soap sockets sysvmsg sysvsem sysvshm opcache zip redis xsl sodium xdebug’ – XDEBUG_CONFIG=remote_host=host.docker.internal remote_autostart=On remote_enable=On idekey=XDEBUG remote_log=/tmp/xdebug.log remote_port=9000 networks: magento: aliases: – fpm_xdebug.magento2.docker depends_on: db: condition: service_started mailhog: hostname: mailhog.magento2.docker image: ‘mailhog/mailhog:latest’ restart: always ports: – ‘1025:1025’ – ‘8025:8025’ networks: magento: aliases: – mailhog.magento2.docker volumes: mymagento-magento-sync: driver_opts: type: none device: ‘${PWD}/mymagento-magento-sync’ o: bind mymagento-magento-db: { } networks: magento: driver: bridge magento-build: driver: bridge

5. Create Dockerfile at the location .docker/PHP/Dockerfile using the commands below

mkdir -p .docker/PHP/ && touch .docker/PHP/Dockerfile

5b. Copy the below content.

FROM php:7.3-fpm RUN apt-get update && apt-get install -y \ cron \ git \ libfreetype6-dev \ libicu-dev \ libjpeg62-turbo-dev \ libmagickwand-dev \ libmcrypt-dev \ libpng-dev \ libxslt1-dev \ default-mysql-client \ vim \ zip \ libzip-dev \ wget \ net-tools \ netcat RUN docker-php-ext-configure \ gd –with-freetype-dir=/usr/include/ –with-jpeg-dir=/usr/include/ RUN docker-php-ext-install \ bcmath \ gd \ gettext \ intl \ mbstring \ opcache \ pdo_mysql \ soap \ xsl \ zip \ sockets RUN pecl channel-update pecl.php.net \ && pecl install xdebug \ && docker-php-ext-enable xdebug \ && sed -i -e ‘s/^zend_extension/\;zend_extension/g’ /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini RUN pecl install imagick-3.4.3 \ && docker-php-ext-enable imagick RUN curl -sS https://getcomposer.org/installer | \ php — –install-dir=/usr/local/bin –filename=composer RUN wget https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 \ && chmod +x mhsendmail_linux_amd64 \ && mv mhsendmail_linux_amd64 /usr/local/bin/mhsendmail COPY conf/php.ini /usr/local/etc/php/ WORKDIR /app EXPOSE 9001

Paste it into .docker/PHP/Dockerfile

vi .docker/PHP/Dockerfileornano .docker/PHP/Dockerfile

6. Create a new directory named conf; add a file named php.ini in that directory.

mkdir -p .docker/PHP/conf/cd .docker/PHP/conf/vi php.ini

The path should be magento-local-env/.docker/PHP/conf/php.ini

7. Paste the following content into magento-local-env/.docker/PHP/conf/php.ini

memory_limit = 2G max_execution_time = 1800<br>zlib.output_compression = On cgi.fix_pathinfo = 0 date.timezone = UTC

8. Move back into the root dir

cd ../../../

9. Compose the local environment

touch .docker/config.php touch .docker/config.env mkdir mymagento-magento-syncdocker-compose -f docker-compose.yaml up –build -ddocker ps -a

It’s ok if the build or deploy container has an error or is “unhealthy”.

10. Tail the db container’s logs until you see “ready for connections”

Image for post
docker logs magento-local-env_db_1 -f

11. Access the fpm containers cli

docker exec -it magento-local-env_fpm_1 bash

12. Use composer to create and install Magento 2, move all of the contents of the Magento package into the /app dir

You will need to enter your Magento account credentials from https://marketplace.magento.com/customer/accessKeys/

The public key is the username; the private key is the password. If you don’t already have a Magento account/key pair just create one/them. It’s free 🙂

Reference: https://devdocs.magento.com/guides/v2.4/install-gde/prereq/connect-auth.html

composer create-project –repository-url=https://repo.magento.com/ magento/project-community-edition=2.3.5p2mv project-community-edition/* .rm -rf project-community-edition/

Enter your Magento account credentials from https://marketplace.magento.com/customer/accessKeys/

13. Set file permissions

find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+w {} +<br>find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} +<br>chown -R :www-data . # Ubuntu<br>chmod u+x bin/magento

14. Create an env.php file

exit && cd mymagento-magento-sync/app/etcsudo && vi env.php

Write your own custom configurations or paste the content below into the file.

Fyi, the reason I did not opt to create the file inside the fpm container is that vi doesn’t work as expected when trying to paste something inside the container for some reason.

Sample env.php below :

<?php return [ ‘MAGE_MODE’ => ‘developer’, ‘cache_types’ => [ ‘compiled_config’ => 1, ‘config’ => 1, ‘layout’ => 1, ‘block_html’ => 1, ‘collections’ => 1, ‘reflection’ => 1, ‘db_ddl’ => 1, ‘eav’ => 1, ‘customer_notification’ => 1, ‘config_integration’ => 1, ‘config_integration_api’ => 1, ‘target_rule’ => 1, ‘full_page’ => 1, ‘translate’ => 1, ‘config_webservice’ => 1, ‘vertex’ => 1 ], ‘backend’ => [ ‘frontName’ => ‘admin’ ], ‘db’ => [ ‘connection’ => [ ‘default’ => [ ‘username’ => ‘magento2’, ‘host’ => ‘magento-local-env_db_1’, ‘dbname’ => ‘magento2’, ‘password’ => ‘magento2’ ], ‘indexer’ => [ ‘username’ => ‘magento2’, ‘host’ => ‘magento-local-env_db_1’, ‘dbname’ => ‘magento2’, ‘password’ => ‘magento2’ ] ] ], ‘crypt’ => [ ‘key’ => ” ], ‘resource’ => [ ‘default_setup’ => [ ‘connection’ => ‘default’ ] ], ‘x-frame-options’ => ‘SAMEORIGIN’, ‘session’ => [ ‘save’ => ‘redis’, ‘redis’ => [ ‘host’ => ‘magento-local-env_redis_1’, ‘port’ => 6379, ‘database’ => 0, ‘disable_locking’ => 1 ] ], ‘install’ => [ ‘date’ => ‘Fri, 15 Jun 2018 10:17:40 +0000’ ], ‘static_content_on_demand_in_production’ => 0, ‘force_html_minification’ => 1, ‘cron_consumers_runner’ => [ ‘cron_run’ => false, ‘max_messages’ => 10000, ‘consumers’ => [ ] ], ‘cache’ => [ ‘frontend’ => [ ‘default’ => [ ‘backend’ => ‘Cm_Cache_Backend_Redis’, ‘backend_options’ => [ ‘server’ => ‘magento-local-env_redis_1’, ‘port’ => 6379, ‘database’ => 1 ] ], ‘page_cache’ => [ ‘backend’ => ‘Cm_Cache_Backend_Redis’, ‘backend_options’ => [ ‘server’ => ‘magento-local-env_redis_1’, ‘port’ => 6379, ‘database’ => 2 ] ] ] ], ‘directories’ => [ ‘document_root_is_pub’ => true ], ‘cron’ => [ ], ‘lock’ => [ ‘provider’ => ‘db’, ‘config’ => [ ‘prefix’ => null ] ] ];

15. Go back to the root directory and access the fpm containers cli again

cd ../../../docker exec -it magento-local-env_fpm_1 bash

16. Run the Magento 2 install command inside the container

Reference: https://devdocs.magento.com/guides/v2.4/install-gde/composer.html

bin/magento setup:install \–base-url=http://local.magento.com \–db-host=magento-local-env_db_1 \–db-name=magento2 \–db-user=magento2 \–db-password=magento2 \–admin-firstname=admin \–admin-lastname=admin \–[email protected] \–admin-user=admin \–admin-password=admin123 \–language=en_US \–currency=USD \–timezone=America/Chicago \–use-rewrites=1

** If you changed the base-url in the command above, remember to update your /etc/hosts file ***

17. (Optional) Install sample data

bin/magento sampledata:deploy

18. Navigate to local.magento.com or your custom domain and you’re done !!!

Image for post

If you got this far. Please leave a comment or share. I’d love to hear what you think about the article whether you hated or loved it. Was it helpful at all in improving your Magento development process? We sure hope so, since we love contributing to the the Magento development community and to the eCommerce development community as a whole.

Leave a Reply