How to easily install Laravel on a LEMP Stack using Docker and Kool on Windows 10’s WSL 2

Welder Lourenco
6 min readMar 28, 2021

Install Windows Subsystem for Linux on Windows 10

  1. Update Windows 10 until you’re up to date:
    (Start > type “Settings” and Enter > Update & Security > Check for updates)
  2. Turn WSL on:
    (Start > type “Turn Windows features on or off” and Enter)
    Check Virtual Machine Platform and Windows Subsystem for Linux and click OK. When finished, restart Windows.
  3. Download and install the WSL 2 Linux kernel update. Up to the date of this article, it has to be done manually.
  4. Install your favorite available Ubuntu distro from the Microsoft Store, I’ll install Ubuntu 20.04 LTS:
    (Start > type “Microsoft store” and Enter > search for “Ubuntu” and choose one > Install)
    After finishing installing, launch/run it. You will be asked for a username and a password for your new UNIX system.
  5. By default, WSL 1 is setup. Let’s convert it to 2 like so:
    5.1. (Start > type “Windows PowerShell” and Run it as Administrator)
    5
    .2
    . (type wsl -l and Enter). The command aside lists all your installed distros; Copy the name of the distro you wish to convert to WSL v2, in our case: Ubuntu-20.04
    5.3. (type wsl --set-version Ubuntu-20.04 2)
    (replace Ubuntu-20.04 for the name of the distro you installed, listed in 6.2)
    5.4. Upon success, the message “Conversion complete.” will be displayed.
  6. Now, once again, launch/run the distro you installed in step 5. In our case: Ubuntu 20.04 LTS. Leave that open and, in PowerShell, run wsl -l -v to confirm WSL VERSION 2 is setup and Running.

Install Visual Studio Code on Windows 10 (optional)

The next step is to choose which Command Line (Terminal) to use on Windows 10. I chose the Visual Studio Code integrated terminal, however, you could use Windows Terminal from Microsoft Store or even the Ubuntu app itself. If you chose a different terminal, you may skip the Visual Studio Code instructions.

  1. Download and Install Visual Studio Code for Windows.
    (leave checkbox “Add to PATH” checked)
  2. Let’s install the required Remote — WSL extension in Visual Studio Code.
    (Run Visual Studio Code > press Ctrl+Shift+X to open the Extensions explorer > search “Remote — WSL” > Install > reload Visual Studio Code after completion)
  3. Let’s open your Ubuntu home folder in Visual Studio Code.
    (Press Ctrl+Shift+P > search “Remote” and click “Remote — WSL: New Window” > a new Visual Studio Code window will open so you may close the current one)
  4. Let’s open Visual Studio Code integrated terminal.
    (Press Ctrl+J > run lsb_release -a to see it works)

Install Docker Desktop on Windows 10

  1. Download and Install Docker Desktop for Windows.
    (leave checkbox “Install required Windows components for WSL 2” checked). When finished, log out of Windows.
  2. After logging back in, the Docker Desktop app will launch/run automatically.
    (close the pop-up that appears > click to Skip Tutorial and you may close the Docker Desktop window)
  3. Check Docker engine is installed and running. From your Command Line (Terminal) run:
    docker -v
  4. (Optional) Log in to Docker Hub. From your Command Line (Terminal) run:
    docker login

Install Kool on Ubuntu

Kool is an open source multi-stack tool that can be used with any language and framework (including Laravel). It works with Docker / Docker Compose under the hood and comes with some cool presets to help you get started, everything is configurable / extendable.

  1. Let’s install Kool. From your Command Line (Terminal) run:
    cd ~ && curl -fsSL https://kool.dev/install | bash
    (during installation, you’ll be asked for sudo access)
  2. Check Kool is up and running. From your Command Line (Terminal) run:
    kool -v

Starting a fresh Laravel project with Kool

  1. Change directory into your application parent folder, in my case it will be: ~/git. From your Command Line (Terminal) run:
    cd ~ && mkdir git && cd ~/git
  2. Create the application base files. From your Command Line (Terminal) run:
    kool create laravel my-laravel-app
    (when prompted “Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]?”, answer Y)
  3. Kool will display a service configuration wizard in which you’ll be allowed to choose, up to version 1.10, by default from:
    3.1: PHP 7.4 or 8.0 and Composer V1 or V2
    3.2: MySQL 5.7, 8.0 or PostgreSQL
    3.3: Redis or Memcached (I chose none, for now)
    3.4: npm or yarn
    (I chose PHP 7.4, Composer V2, MySQL 5.7 and yarn for assets)
    (this will create the files you need to configure your services. Feel free to edit docker-compose.yml to add or remove services as needed)
  4. If not already opened, open your application base folder with your favorite editor. In our case using Visual Studio Code, from your Command Line (Terminal) run:
    cd ~/git/my-laravel-app && code .
    (a new Visual Studio Code window will open so you may close the current one)
  5. Let’s setup the application’s environment. Open the file .env.example and update the following entries:
    5.1. DB_HOST=database
    (different service configuration in step 3 may require different environment settings too, check Kool’s official installation documentation for all environment updates required for all services)
  6. And, finally, let’s serve the application locally. From your Command Line (Terminal) run in the project base folder:
    kool run setup (after completion, you should be able to access your site at http://localhost).
  7. Use kool start from the application base folder to serve the application for the second time forward (after a restart, for example) and also kool stop to stop serving the application (to serve another one, for example).

Existing project with Kool

  1. Change directory into your existing application base folder and from your Command Line (Terminal) run:
    kool preset laravel
    (jump to Starting a fresh Laravel project with Kool step 3 and follow from there).

The magic of Kool Run (kool.yml)

This is what our default kool.yml file looks like:

scripts:
artisan: kool exec app php artisan
composer: kool exec app composer2
mysql: kool exec -e MYSQL_PWD=$DB_PASSWORD database mysql -u $DB_USERNAME $DB_DATABASE
node: kool docker kooldev/node:14 node
node-setup:
- kool run yarn install
- kool run yarn dev
reset:
- kool run composer install
- kool run artisan migrate:fresh --seed
- kool run node-setup
setup:
- cp .env.example .env
- kool start
- kool run composer install
- kool run artisan key:generate
- kool run node-setup
yarn: kool docker kooldev/node:14 yarn

Kool allows to encapsulate scripts for you to use on your local environment or CI/CDs. It is created in your working directory when you run kool create or kool preset, but you can also create it inside a folder named kool in your user’s home directory. The scripts defined in it can be used with kool run.

You could also update your kool.yml file to include your own command following the yml syntax, for example:
work-queues: kool run artisan queue:work redis --tries=3 --delay=3
and run kool run work-queues from your Command Line (Terminal).

Here’s a real life example:

scripts:
# Scripts within the app service
composer: kool exec app composer
artisan: kool exec app php artisan
dusk: kool run artisan dusk
phpunit: kool exec app ./vendor/bin/phpunit
# Scripts within the node service
node: kool docker kooldev/node:14 node
yarn: kool docker kooldev/node:14 yarn
eslint: kool run yarn lint
# Scripts within the database service
mysql: kool exec database mysql -u$DB_USERNAME -p$DB_PASSWORD
mysql-no-tty: kool exec --disable-tty database mysql -u$DB_USERNAME -p$DB_PASSWORD
update-local-db: bash routines/update_local_db_as_of_prod.bash
# Local provisioning scripts
install:
- kool run composer install
- kool run artisan migrate
- kool run yarn install
- kool run yarn run dev
setup:
- cp .env.example .env
- kool start
- kool run artisan key:generate
- kool run install
reset:
- kool run update-local-db
- kool run install
# QA scripts
wait-services: kool exec app dockerize -wait tcp://database:3306 -wait tcp://cache:6379 -timeout 30s

start:chrome: kool docker -- --name="chromedriver" --network=$KOOL_GLOBAL_NETWORK -d --shm-size=256M mylaravelapp/chromedriver:latest

stop:chrome: docker stop chromedriver

phpqa: kool docker jakzal/phpqa:1.17.0-php7.2-alpine

phan: kool run phpqa phan --color -p -l app -iy 5

phpcpd: kool run phpqa phpcpd --fuzzy app

phpmd: kool run phpqa phpmd app text phpmd/codesize.xml,phpmd/controversial.xml,phpmd/design.xml,phpmd/naming.xml,unusedcode,phpmd/cleancode.xml

phpmnd: kool run phpqa phpmnd app --ignore-funcs=round,sleep,abort,strpad,number_format --exclude=tests --progress --extensions=default_parameter,-return,argument

php-security-checker: kool run phpqa security-checker security:check composer.lock
php-cs-fixer-check:
- kool run phpqa php-cs-fixer fix --diff --dry-run app/
- kool run phpqa php-cs-fixer fix --diff --dry-run tests/
- kool run phpqa php-cs-fixer fix --diff --dry-run resources/lang
- kool run phpqa php-cs-fixer fix --diff --dry-run config
- kool run phpqa php-cs-fixer fix --diff --dry-run database
php-cs-fixer:
- kool run phpqa php-cs-fixer fix --diff --format=txt --verbose app/
- kool run phpqa php-cs-fixer fix --diff --format=txt --verbose tests/
- kool run phpqa php-cs-fixer fix --diff --format=txt --verbose resources/lang
- kool run phpqa php-cs-fixer fix --diff --format=txt --verbose config
- kool run phpqa php-cs-fixer fix --diff --format=txt --verbose database

--

--