DEV Community

Cristiano Pacheco for run_as_root GmbH

Posted on • Updated on

Good-bye Docker, Hello Nix: Configuring a Magento 2 Development Environment with Rooter

Table of Contents

Introduction:

In 2023, I switched from Linux to macOS. I used Linux for years, mainly because it supported Docker natively. However, during a system update, I encountered a problem with the video driver that cost me an entire Saturday searching for solutions, tweaking files I didn't even know existed until finally, at the end of the day, I found a workaround to get the darn Nvidia driver working.

Come Monday morning, I shared my tech nightmare with a friend at work, who promptly asked:

"Why don't you switch to macOS?"

I replied: "Because it doesn't have native Docker support, and I don't want to use a virtual machine."

With a virtual machine, you have to allocate a good chunk of RAM, not to mention the slower disk processing. While disk speed might not matter much for many applications, it makes a huge difference for a Magento 2 environment.

"Why do you even need Docker?" he asked.

That sparked a quick conversation where he introduced me to Nix and devenv.

With these tools, it's possible to create a development environment that's entirely reproducible and native to macOS!

It was love at first sight! When I saw it in action, my mind was blown!

shocked

During that conversation, I first contacted one of the early versions of rooter.

Rooter is a powerful command-line tool to automate repetitive tasks in creating and maintaining development environments.

Shortly after, I bought a MacBook and started using rooter to manage my projects. Nowadays, I don't have Docker installed on my machine, and I couldn't be happier!

Requirements

You need macOS operating system and the softwares below installed:

Just follow the instructions on the rooter documentation.

Just giving a brief introduction about the these tools:

  • rooter is a CLI tool created By Matthias Walter. This tool will be your best friend during your development journey. It is similar to Warden or DDEV. It takes care of things like automatic DNS resolution using dnsmasq, managing project routes with Traefik, creating SSL certificates, and even includes handy commands for importing and exporting databases, plus a whole lot more.

  • nix has been around since 2003 and it's super reliable. It's like a toolbox with lots of useful tools inside, such as a programming language, an operating system, and a package manager. It helps you make software systems that are consistent and easy to recreate.

  • devenv is kind of like docker-compose, but way stronger. It's like being able to use a programming language to set up your environment, giving you even more control and flexibility.

  • direnv is a tool that figures out and loads all the stuff you need for your current project whenever you step into its folder in your terminal. We'll get to see how it works soon.

Creating a Magento 2 dev environment

So getting straight to the point, let's set up a development environment to run Magento 2.

At this point, I'm assuming you've got rooter and all the necessary tools it relies on installed and ready to roll. Let's dive in!

1. Creating the project directory



mkdir -p ~/Sites/magento2


Enter fullscreen mode Exit fullscreen mode

2. Entering in the created directory



cd ~/Sites/magento2


Enter fullscreen mode Exit fullscreen mode

3. Creating the environment with rooter



rooter env:create


Enter fullscreen mode Exit fullscreen mode

Rooter will ask what type of environment:

rooter env type

Type 2 and enter for Magento 2

It generated 4 files:

  • .env
  • .envrc
  • devenv.nix
  • devenv.yaml

4. Allowing direnv to execute

You probably saw this message in your terminal:

dir env allow

You need to allow direnv to execute.

Run the command below:



direnv allow .


Enter fullscreen mode Exit fullscreen mode

Now you'll see something like this in your terminal:

dir env steup

In this moment, your dev stack declared in the devenv.nix file will be downloaded and configured. This is the longest step. Wait until the installation process finishes.

You will see something like this when the process finishes:

direnv installation finished

Now, please take a look into this image:

direnv loading

If you've noticed, when I'm not in the project folder, the PHP version in the terminal is different, not 8.2. But as soon as I step into the project folder, direnv works its magic and loads the entire setup into the terminal. Pretty neat, isn't it?

5. Cloning the Magento 2 repository



composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition:2.4.6-p4 magento2-codebase


Enter fullscreen mode Exit fullscreen mode

It'll clone the Magento 2 repository into a directory named magento2-codebase. Once it's done, just copy everything from the magento2-codebase folder to the current directory, and then you can delete the magento2-codebase directory with the command below:



cp -R magento2-codebase/* . && rm -Rf magento2-codebase


Enter fullscreen mode Exit fullscreen mode

6. Starting the environment stack

I like to start the environment in the debug mode in the first attempt, because this shows detailed output about the initialization and in case there is an issue, it is visible right away:



rooter env:start --debug


Enter fullscreen mode Exit fullscreen mode

Basically devenv will download all services upon first start. That could also be nginx, opensearch, rabbitmq etc.

opensearch lib download

After the first start I like to stop the environment (CMD + c) and start it again without the debug flag:



rooter env:start


Enter fullscreen mode Exit fullscreen mode

The reason being that now it is running in the background rather than the foreground which it was with --debug flag passed.

To see what is the status of the environment, run the command below:



rooter env:status


Enter fullscreen mode Exit fullscreen mode

It will show something like this:

env status

As mentioned earlier, it uses process-compose in the background. There is a command to attach to the process-compose and get a control panel to check the various processed that got launched.



rooter env:process-compose


Enter fullscreen mode Exit fullscreen mode

As you can see in the image below, you can easily switch between the different services and watch their logs update live.

Process compose

7. Setting up the database

Run the command below to setup the database:



rooter magento2:db-install


Enter fullscreen mode Exit fullscreen mode

Rooter will drop and recreate the database and by default run the commands below:

  • bin/magento setup:install
  • bin/magento setup:upgrade
  • bin/magento indexer:reindex

An admin user will be created with the username admin and password admin123.

If you pass the option --config-data-import it will run the command bin/magento config:data:import config/store dev/rooter

Note: The config:data:import is provided by the Magento2-ConfigImportExport module. You need to install it to use the --config-data-import option flag.

You can skip the reindex by passing the option --skip-reindex

Run the commands below to set some extra configs:



bin/magento config:set web/unsecure/base_url https://magento2.rooter.test/ && \
bin/magento config:set web/secure/base_url https://magento2.rooter.test/ && \
bin/magento config:set web/secure/offloader_header X-Forwarded-Proto && \
bin/magento config:set web/secure/use_in_frontend 1 && \
bin/magento config:set web/secure/use_in_adminhtml 1 && \
bin/magento config:set web/seo/use_rewrites 1 && \
bin/magento config:set catalog/search/enable_eav_indexer 1 && \
bin/magento config:set dev/static/sign 0 && \
bin/magento deploy:mode:set -s developer && \
bin/magento cache:clean


Enter fullscreen mode Exit fullscreen mode

These are the Store front and admin URLs:

Tcharaaam!

home

What really blows me away is the speed. Running Magento natively on Mac makes everything super fast and smooth.


Rooter Appendix

The .devenv directory

The .devenv directory contains the data about the profile, nix garbage collector, the stack state, etc.

The .devenv/state directory is where some of the stack code lives, as for example, elasticsearch, mysql, php-fpm, nginx, rabbitmq, etc.

You don't need to touch these folders or the files on it.

.devenv directory

Versioning

Which files and directories should you version or remove from versioning:

You don't need to version the files and folders below, so add them to your .gitignore file.

  • .devenv
  • .direnv
  • .env

You need to version the files below:

  • .devenv.flake.nix
  • .envrc
  • devenv.lock
  • devenv.nix
  • devenv.yaml

Note: None of this files is required by rooter. They are required from devenv and direnv.

Diving deeper into the most important files

.env file:

Contains all variable environments that is used in your project stack

dot env file

ROOTER_ENV_TYPE defines the type of the environment, it can be:

  • magento1
  • magento2
  • php-plan
  • shopware6
  • symfony

DEVENV_HTTP_PORT defines the http port used from the Nginx webserver

DEVENV_HTTPS_PORT defines the https (SSL) port used from the Nginx webserver

DEVENV_DB_PORT defines the Mysql/MariaDB/Percona database port

Note: In the current version of rooter, only Mysql* database is supported.

Mysql* I mean any of the versions or forks of it, for instance MariaDB, Percona, etc.

DEVENV_MAIL_SMTP_PORT defines the mailpit SMTP port

DEVENV_MAIL_UI_PORT defines the mailpit user interface port

DEVENV_REDIS_PORT the name already explains it :)

DEVENV_AMQP_PORT defines the RabbitMQ port that will be used in your application

DEVENV_AMQP_MANAGEMENT_PORT defines the RabbitMQ admin panel

DEVENV_ELASTICSEARCH_PORT defines the ElasticSearch port that will be used from your application

DEVENV_ELASTICSEARCH_TCP_PORT the name already explains it :)

DEVENV_PROCESS_COMPOSE_PORT the name already explains it :)

We'll see more about the process compose later.

In case you noticed and are wondering, where the heck did the values of the ports defined in these variables come from?

Rooter has a mechanism that will get the available ports in your environment, taking into account the existing environments that were created by rooter.

It will assign ports using certain ranges, you can see how it works in this file, please look:

rooter ports manager

.envrc file:

envrc file

This file is used by the direnv tool.

It will load all the declared stack to the current terminal context.

devenv.nix file:

This file is used by devenv, it uses the Nix language to declare the environment.

You can find more information about it here.

Let's get more details of the most important parts of this file:



{ pkgs, inputs, lib, config, ... }:


Enter fullscreen mode Exit fullscreen mode

In Nix, when you see this line, it's like setting up a template for a function. It says that the function will at least get these four things: pkgs, inputs, lib, and config. But it's cool because it can also get more stuff using the ... thingy.



let
    rooterBin = if builtins.getEnv "ROOTER_BIN" != "" then builtins.getEnv "ROOTER_BIN" else "rooter";
    composerPhar = builtins.fetchurl{
        url = "https://github.com/composer/composer/releases/download/2.2.22/composer.phar";
        sha256 = "1lmibmdlk2rsrf4zr7xk4yi5rhlmmi8f2g8h2izb8x4sik600dbx";
    };
    magerun2Phar = builtins.fetchurl{
        url = "https://github.com/netz98/n98-magerun2/releases/download/7.2.0/n98-magerun2.phar";
        sha256 = "0z1dkxz69r9r9gf8xm458zysa51f1592iymcp478wjx87i6prvn3";
    };
in {


Enter fullscreen mode Exit fullscreen mode

The let...in block in the provided devenv.nix file defines a scope for local definitions that can be used later in the expression. This construct allows for declaring variables and their values before using them in the main body of the Nix expression.

Here's a breakdown of the let block and its components:

  • rooterBin: Defined based on the ROOTER_BIN environment variable. If set, rooterBin uses its value; if not, it defaults to "rooter". Enables flexible configuration.

  • composerPhar/magerun2Phar: Downloads the Composer PHAR and n98-magerun2 PHAR file from GitHub using a URL and a sha256 hash for security.



    dotenv.enable = true;
    env = {
        PROJECT_NAME = "magento2";
        PROJECT_HOST = "magento2.rooter.test";

        NGINX_PKG_ROOT = pkgs.nginx;
        DEVENV_STATE_NGINX = "${config.env.DEVENV_STATE}/nginx";

        DEVENV_PHPFPM_SOCKET = "${config.env.DEVENV_STATE}/php-fpm.sock";

        DEVENV_DB_NAME = "app";
        DEVENV_DB_USER = "app";
        DEVENV_DB_PASS = "app";

        DEVENV_AMQP_USER = "guest";
        DEVENV_AMQP_PASS = "guest";
    };


Enter fullscreen mode Exit fullscreen mode

The env block declares the environment variables.

The project's domain is determined by the PROJECT_HOST variable. So, you can access the project using the address: https://magento2.rooter.test.

If you need to change the PROJECT_HOST variable value, follow the instructions here.

It is possible to have custom subdomains, you can see more info about it here.

Just a heads up, the database will use as name, user, and password, all set to app by default. Feel free to tweak these settings whenever you need.

Similarly, for RabbitMQ, the default user and password are both guest. You're welcome to adjust these as necessary.

php declaration

This is where we define and set up PHP. If you ever need to switch the PHP version, simply make the change in the highlighted section shown in the image.

Mysql

The same for MariaDb version. If you need a different version just change it.

To know what are the supported versions, you can search in directly in the nix packages page, for example:

Mysql search

Note: please note that we're using the unstable channel, it is the default channel for devenv, because it has more packages and with newer versions on it. So when you'll search the package, don't forget to select the unstable channel.

unstable channel

Last we have RabbitMQ declaration, if your project does not use it, just remove it from the devenv.nix file. We'll maintain it :)

Rabbit MQ

devenv.yaml file:

This file is used by devenv. It will serve to declare what is the source of the packages. You can have multiple inputs, using different channels, for example.

Accessing the traefik dashboard

To access the traefik dashboard, just type rooter traefik:dashboard

traefik

Accessing the mailpit UI

Mailpit is a fork of mailhog, It is newer and constantly receives updates.

It is per environment it will have always the URL with this pattern:

https://PROJECT_NAME-mail.rooter.test

In our case it will be:

http://magento2-mail.rooter.test

mailpit

Note: The PROJECT_NAME variable is defined in the devenv.nix file

Rooter commands

Just a heads up, to explore the existing rooter commands, you can simply run the command rooter commands. This will give you a list of all available commands. Happy exploring!

rooter commands

Xdebug

The only thing action you need to configure Xdebug is to set this environment env to your terminal:



export XDEBUG_CONFIG="idekey=PHPSTORM-XDEBUG"


Enter fullscreen mode Exit fullscreen mode

You can append it with the command below:



echo 'export XDEBUG_CONFIG="idekey=PHPSTORM-XDEBUG"' >> ~/.zshrc


Enter fullscreen mode Exit fullscreen mode

Now you're able to debug your Magento 2 store on CLI or throughout web without any configuration.

On PHPStorm for instance, you just have to click on the "Bug" button to start listening to Xdebug connections:

Xdebug


If you have any specific scenarios you'd like guidance on, like setting up Magento with multiple websites or store views, feel free to leave your question in the comments below. I'll do my best to assist you!

I hope you found this helpful! 👋

Top comments (15)

Collapse
 
jwater profile image
Jack • Edited

Hi

Thanks for the detailed explanation.

I came across this line and couldn't find any reference to this command in the Magento docs bin/magento config:data:import

Can you please explain what this does in your comment context ?.

Do you need to have composer installed globally or it does this in the project folder context when you run project create command ?

Thanks

Collapse
 
qixiano profile image
Cristiano Pacheco

Hello @jwater, very good question.

About the bin/magento config:data:import command,
it comes from semaio/magento2-configimportexport module.

That is an excellent module for exporting/importing the configurations to a yaml file.

Do you need to have composer installed globally or it does this in the project folder context when you run project create command ?

Everything you need to run the stack, including composer is already installed by devenv. Basically, when you enter the ~/Sites/magento2 folder, all the stack is loaded to the terminal context and available for usage out of the box. When you exit the ~/Sites/magento2 folder the stack is gone :)

Collapse
 
jwater profile image
Jack

Hi @qixiano

Thank you for getting back. Much appreciated.

So this module will have to be installed correct if you have to run this command ?.

It might be worth mentioning this in the guide.

May I kindly request to know, from what I understand this setup doesn't use docker or virtual machine ?

Thanks

Thread Thread
 
qixiano profile image
Cristiano Pacheco

Hello @jwater,

No, the semaio/magento2-configimportexport is required to be installed only if you run the rooter magento2:db-install command with --config-data-import option on it.

I'll mention it in the guide. Thank you for your suggestion.

May I kindly request to know, from what I understand this setup doesn't use docker or virtual machine?

You can still use Docker to run this setup if you want. However, it is not required at all. With Nix, the stack is installed natively on your machine.

Thread Thread
 
jwater profile image
Jack

Thanks @qixiano , got it.

Collapse
 
tomerbendavid profile image
Tomer Ben David

What is Magento? Does rooter supports java will it show in options?

Collapse
 
qixiano profile image
Cristiano Pacheco

Hello @tomerbendavid, Magento is an e-commerce platform.

Rooter does not support Java stack yet, but devenv supports it.

What is your current stack with Java? I mean what is the web server ( tomcat, wildfly, etc). Do you use some framework, such as spring boot?

Collapse
 
tomerbendavid profile image
Tomer Ben David

Jetty + Spring + Lombok. Works like a charm.

Collapse
 
mrovaiz profile image
Mohammed Rahil Ovaiz

Rooter is only for mac?
How can I do same setup of magento 2 in linux with nixos?
Please help me with this.

Collapse
 
qixiano profile image
Cristiano Pacheco

Hello @mrovaiz, Rooter only has support for macOS right now but will have support for Linux soon.

Collapse
 
jwater profile image
Jack

Hi @qixiano

I have been trying to setup a Magento project.

I have installed everything but when I run rooter magento2:db-install , I get the below.

Any help would be much appreciated.

rooter magento2:db-install

Dropping and recreating database

Removing app/etc/env.php

rm: app/etc/env.php: No such file or directory

In InstallMagento2DbCommand.php line 126:

  The command "rm app/etc/env.php" failed.                                

  Exit Code: 1(General error)                                             

Enter fullscreen mode Exit fullscreen mode
Collapse
 
jwater profile image
Jack • Edited

Hi @qixiano

So I manually created an empty env.php file in app/etc and run rooter magento2:db-install

Now I'm having issue with rabbitmq, see below

rooter magento2:db-install

Dropping and recreating database

Removing app/etc/env.php

Running magento setup:install

Could not connect to the Amqp Server.
Enter fullscreen mode Exit fullscreen mode

This is the setting it shows in the error message
--amqp-host=127.0.0.1 --amqp-port=5732 --amqp-user=guest --amqp-password=guest --amqp-virtualhost="/" \

When I do the status, it gets stuck like this (attached)

Appreciate any help.

Thanks

Image description

Collapse
 
qixiano profile image
Cristiano Pacheco

Hello @jwater, it seems your env is not running. Just try to start it and try again.

Thread Thread
 
jwater profile image
Jack

Hi @qixiano

I did, but noticed the stop sometimes doesn't work as it errors due to one port staying in use.

Anyway, I managed to finally setup another project and the rabbitmq initially started but then after some time crashed.

I created another new project not knowing how to restart rabbitmq service only and rabbitmq crashed immediately when I ran rooter env:start --debug

I have opened a ticket here with the error details github.com/run-as-root/rooter/issu...

If you know how I can try to restart rabbitmq or any other advice, would be helpful.

Thanks

Collapse
 
jwater profile image
Jack

Hi @qixiano

I wanted to ask how would I got setting up cron if I have more than one magento 2 environment ?.

Would it look something similar like below in my crontab crontab -l ?

#~ MAGENTO START c5f9e5ed71cceaabc4d4fd9b3e827a2b

* * * * * /nix/store/env-1-hash-devenv-profile/bin/php /path/to/magento-env-1/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> path/to/magento-env-1/var/log/magento.cron.log

* * * * * /nix/store/env-2-hash-devenv-profile/bin/php /path/to/magento-env-2/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> path/to/magento-env-2/var/log/magento.cron.log

#~ MAGENTO END c5f9e5ed71cceaabc4d4fd9b3e827a2b
Enter fullscreen mode Exit fullscreen mode

Thanks

Some comments may only be visible to logged-in visitors. Sign in to view all comments.