Pages

How to Install Magento 2 on Windows using WSL2, Docker, and VS Code: Full Step-by-Step Guide with Real Errors and Fixes

How to Install Magento 2 on Windows using WSL2, Docker, and VS Code: Full Step-by-Step Guide with Real Errors and Fixes


Installing Magento 2 in a Windows environment using WSL2 and Docker can be tricky if you're new to the stack. In this detailed blog post, I’ve documented my complete experience, including every real error I encountered and solutions. Whether you're setting up Magento for the first time or helping a friend, this guide will walk you through every step.


🧰 Prerequisites

  • Windows 10/11 with WSL2 enabled

  • Ubuntu installed via Microsoft Store

  • Docker Desktop (with WSL2 integration)

  • Visual Studio Code with Dev Containers extension

  • Magento 2 source code (fetched from Magento Marketplace)

  • Composer

  • Apache

  • MySQL or MariaDB

  • PHP (8.2)

  • Elasticsearch or OpenSearch


✅ Step 1: Enable WSL2 and Install Ubuntu

  1. Open PowerShell as Administrator and run:

    wsl --install
    
  2. Restart your system.

  3. Go to the Microsoft Store → Search for Ubuntu 22.04 LTS → Install.

  4. Launch Ubuntu, set your username and password.


✅ Step 2: Install Docker Desktop

  1. Download from https://www.docker.com/products/docker-desktop

  2. During installation, enable WSL2 Integration.

  3. Go to Settings → Resources → WSL Integration and enable for Ubuntu.


✅ Step 3: Install VS Code & Dev Containers

  1. Install Visual Studio Code

  2. Install the Dev Containers extension from the Extensions Marketplace.

  3. Clone or copy your Magento 2 source code to a folder.

  4. Open that folder in VS Code → Reopen in Container (when prompted).


✅ Step 4: Install Apache, MySQL, PHP, Elasticsearch and Required Packages

sudo apt update && sudo apt upgrade -y
sudo apt install php8.2 php8.2-common php8.2-mysql php8.2-xml php8.2-curl php8.2-cli php8.2-bcmath php8.2-gd php8.2-intl php8.2-mbstring php8.2-soap php8.2-zip php8.2-xdebug php8.2-opcache -y
sudo apt install apache2 mysql-server unzip curl git -y

✅ Step 5: Fix PHP Version to 8.2

sudo update-alternatives --set php /usr/bin/php8.2
php -v

✅ Step 6: Install Composer

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version

✅ Step 7: Fix Composer Performance

composer config --global process-timeout 2000
composer clear-cache

✅ Step 8: Configure Magento Marketplace Auth

composer config --global http-basic.repo.magento.com <public_key> <private_key>

✅ Step 9: Create Magento 2 Project

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

✅ Step 10: Set SQL Variables (Important)

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Add or edit:

sql-mode=""

Then:

sudo service mysql restart

✅ Step 11: Install and Start Elasticsearch or OpenSearch

sudo apt install apt-transport-https openjdk-11-jdk wget -y
wget -qO - https://artifacts.opensearch.org/publickeys/opensearch.pgp | sudo apt-key add -
echo "deb https://artifacts.opensearch.org/releases/bundle/opensearch/2.x/apt stable main" | sudo tee /etc/apt/sources.list.d/opensearch-2.x.list
sudo apt update && sudo apt install opensearch -y
sudo systemctl start opensearch.service
sudo systemctl enable opensearch.service

✅ Step 12: Install Magento 2

php bin/magento setup:install \
--base-url=http://magento2.local \
--db-host=localhost \
--db-name=magento \
--db-user=magento \
--db-password=magento@123 \
--admin-firstname=Admin \
--admin-lastname=User \
--admin-email=admin@example.com \
--admin-user=admin \
--admin-password=Admin@123 \
--language=en_US \
--currency=USD \
--timezone=Asia/Kolkata \
--use-rewrites=1

✅ Step 13: Setup Apache Virtual Host

sudo nano /etc/apache2/sites-available/magento2.conf

Add:

<VirtualHost *:80>
    ServerName magento2.local
    DocumentRoot /var/www/html/magento2/pub

    <Directory /var/www/html/magento2/pub>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/magento2_error.log
    CustomLog ${APACHE_LOG_DIR}/magento2_access.log combined
</VirtualHost>

Enable site:

sudo a2ensite magento2.conf
sudo a2enmod rewrite
sudo systemctl restart apache2

✅ Step 14: Update Windows Hosts File

  1. Find WSL IP:

ip addr show eth0 | grep inet
  1. In Windows Notepad (Run as Admin), add:

<WSL_IP> magento2.local

✅ Step 15: Set Permissions

sudo chown -R $USER:www-data .
sudo find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+rw {} \;
sudo find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+rwxs {} \;

✅ Step 16: Composer Install

composer install

✅ Step 17: Fix GitHub OAuth Token Issues (If any)

  1. If you see:

    Your github oauth token for github.com contains invalid characters: ""
    
  2. Fix it with:

composer config --global --auth --unset github-oauth.github.com
composer config --global --auth github-oauth.github.com YOUR_NEW_TOKEN
  1. Or edit manually:

mkdir -p ~/.config/composer
nano ~/.config/composer/auth.json

And add:

{
  "github-oauth": {
    "github.com": "YOUR_NEW_TOKEN"
  }
}

✅ Step 18: Check Apache, MySQL, PHP Status

sudo systemctl status apache2
sudo systemctl status mysql
php -v

To start if stopped:

sudo systemctl start apache2
sudo systemctl start mysql

✅ Step 19: Common Magento Commands

php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento setup:static-content:deploy -f
php bin/magento cache:flush
tail -n 50 var/log/exception.log

Thanks for reading - Happy Code

Create a password reset link that will expiry after 30 mins in tha url

 To create a password reset link that will expire after 30 minutes in the URL, you can use a combination of a unique token (e.g. a randomly generated string) and a timestamp. When a user requests a password reset, you can generate a token and attach it to a URL along with the current timestamp. When the user clicks on the link, you can check the timestamp to see if 30 minutes have passed. If so, the link is expired and the user will need to request a new password reset.


Here's an example of what the URL might look like:


https://example.com/resetpassword?token=abcdefghijklmnopqrstuvwxyz&timestamp=1613792400


In this example, "abcdefghijklmnopqrstuvwxyz" is the token and "1613792400" is the timestamp (in Unix time format).


When the user clicks the link, your server can check the current timestamp and compare it to the timestamp included in the URL. If the difference is greater than 30 minutes, the link is expired and the password reset process should be halted.


Please note that this is a simple example, in real production environment, you should use more secure way of creating token and handling timestamp and also consider various security measures to protect your user's account.

Magento 2.3.4 - Install eWay Payment Gateway using Composer

1) Install extension using Composer : 

             composer require eway/eway-rapid-magento2:3.0.5

2) Enable :

 php bin/magento module:enable --clear-static-content Eway_DirectConnection       Eway_SharedPage Eway_SecureFields Eway_IFrame Eway_TransparentRedirect   Eway_EwayRapid

3) Required command: 

           upgrade and di-compile 


Magento 2.3 - Find file using Putty (SSH)

 The following cmd show where is the file,


                find . -name PaymentInformationManagement.php


Magento 2.3.4 - Check the detail error about the error

Eg: Customer login error: An unspecified error occurred. Please contact us for assistance

If you want the more detail about the error

 Go to file

vendor/magento/module-customer/Controller/Account/LoginPost.php
and put these lines 

    $message = $e->getMessage();
    $this->messageManager->addError($message);

just before lines- 

    $this->messageManager->addError(
                            __('An unspecified error occurred. Please contact us for assistance.')
                        );

now on front try to log in and check error.

Magento 2.3 : Generate Custom Log

Following code return custom log,

             $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/custom.log');  
             $logger = new \Zend\Log\Logger();  
             $logger->addWriter($writer);  
             $logger->info('Your log details: ' .$your_variable);  

Magento 1.9 - PLP Page sort by ASC order

For Temporary:

Paste below code into Backend Magento category -> Custom Design -> Custom Layout Update section:

 
 <reference name="product_list">  
      <action method="setDefaultDirection"><dir>asc</dir></action>  
 </reference>  
  

For Permanent :

 Add following code to app/design/frontend/default/theme/layout/local.xml

 <?xml version="1.0"?>  
 <layout version="0.1.0">  
   <!-- Change default direction for simple searches -->  
   <catalogsearch_result_index>  
     <reference name="search_result_list">  
       <action method="setDefaultDirection"><dir>asc</dir></action>  
     </reference>  
   </catalogsearch_result_index>  
   <!-- Change default direction for advanced searches -->  
   <catalogsearch_advanced_result>  
     <reference name="search_result_list">  
       <action method="setDefaultDirection"><dir>asc</dir></action>  
     </reference>  
   </catalogsearch_advanced_result>  
   <!-- Change default direction for a category without layered navigation -->  
   <catalog_category_default>  
     <reference name="product_list">  
       <action method="setDefaultDirection"><dir>asc</dir></action>  
     </reference>  
   </catalog_category_default>  
   <!-- Change default direction for a category with layered navigation -->  
   <catalog_category_layered>  
     <reference name="product_list">  
       <action method="setDefaultDirection"><dir>asc</dir></action>  
     </reference>  
   </catalog_category_layered>  
  </layout>  

Magento 2 - Run commands after added Plugins & Obsevers

1)  rm -rf var/di/* var/generation/* var/cache/* var/log/* var/page_cache/* var/session/* var/view_preprocessed/* pub/static/*

2)  php bin/magento setup:upgrade

3)  php bin/magento setup:di:compile

4) php bin/magento setup:static-content:deploy -f   // (-f for Development Mode)

5)  php bin/magento indexer:reindex

6)  php bin/magento cache:clean

7)  php bin/magento cache:flush

Magento 1 - Get Payment Methods (code) using Observer.

The following code return payment methods code,
<?php
    class Gta_FindPaymentGateway_Model_Observer
    {
        public function paymenter($Observer)
        {
           $allPaymentMethods = Mage::getModel('payment/config')->getAllMethods();

           foreach($allPaymentMethods as $paymentMethod)
           {
                Mage::log($paymentMethod->getCode(),null,'filter.log',true);
           }
        }
    }
?>

Magento 1.9 - Find what event using in Observer.

Following code return what event used in the observer,

app\etc\modules\Gta_FindPaymentGateway.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Gta_FindPaymentGateway>
            <codePool>local</codePool>
            <active>true</active>
        </Gta_FindPaymentGateway>
    </modules>
</config>

app\code\local\Gta\FindPaymentGateway\etc\config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Gta_FindPaymentGateway>
            <version>1.0.0</version>
        </Gta_FindPaymentGateway>
    </modules>
    <global> 
        <models>
            <gta_findpaymentgateway>
                <class>Gta_FindPaymentGateway_Model</class>
            </gta_findpaymentgateway>
        </models> 
        <events>
            <checkout_cart_product_add_after>
                <observers>
                    <Gta_FindPaymentGateway_Model_Observer>   
                        <type>singleton</type>
                        <class>Gta_FindPaymentGateway_Model_Observer</class>
                        <method>paymenter</method>
                    </Gta_FindPaymentGateway_Model_Observer>
                </observers>
            </checkout_cart_product_add_after>      
        </events>
    </global> 
</config>

app\code\local\Gta\FindPaymentGateway\Model\Observer.php

<?php
    class Gta_FindPaymentGateway_Model_Observer
    {
        public function paymenter($Observer)
        {
            $order = $Observer->getEvent();
            Mage::log($order->getName(),null,'eventsss.log',true);
        }
    }
?>