DEV Community

Cover image for Set Up LEMP for Laravel on Windows using WSL
Don Cadavona
Don Cadavona

Posted on • Updated on

Set Up LEMP for Laravel on Windows using WSL

Chapters

I. Introduction

Finally, we can set up a true Linux, Nginx, MySQL and Php (LEMP) environment on our Windows machine using Windows Subsystem for Linux (WSL).

If you're a Linux or Mac user, but you're forced to use a Windows machine just like me, or, if you simply want to develop web applications on your Windows PC while still on a Linux or Unix-like environment without dual-booting, this guide is for you.

Why not just use XAMPP, WAMP or MAMP? Well, these are functional until they aren't. They are very clunky, they can't make your local projects look good with domains like myproject.test.

Why not use Homestead? Well, I wished I did, until I gave up trying to make it work on my Windows PC.

Why not use Laragon? I do use Laragon! I love it. It's lightweight, configurable, gives beautiful local domains like myproject.test and also supports sharing your local project to the internet using Ngrok.
But, it is still not a true Linux/Unix-like environment.

Why use WSL? It's the real deal! It's lightweight and fast! It's official! You get to deal with a true Linux environment here. You setup your project on your local machine the same as you would in a real remote Linux server. This way, you are already practicing your server-administration skills.

II. Install Windows Terminal

Install Windows Terminal from Microsoft Store:
https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701

III. Install WSL and Ubuntu

We will be using Ubuntu 20.04 as it is the default and the latest stable Linux distribution supported by WSL.

To install WSL and Ubuntu 20.04, follow the official guide:
https://docs.microsoft.com/en-us/windows/wsl/install

Once WSL Ubuntu is installed, open a new Ubuntu tab in Windows Terminal.

$ cd ~
$ sudo apt update

IV. Install Nginx

$ sudo apt install nginx

To start, stop or restart Nginx, run:
$ sudo service nginx start
$ sudo service nginx stop
$ sudo service nginx restart

V. Install MySQL

To install MySQL, run:

$ sudo apt install mysql-server

To start, stop or restart MySQL, run:
$ sudo service mysql start
$ sudo service mysql stop
$ sudo service mysql restart

Connect to MySQL:

$ sudo mysql <-- If username and password is not needed.
or
$ sudo mysql -u root -p <-- If username and password is needed.

Inside MySQL, create a new database for our example Laravel application:

mysql > create database laravel;
mysql > exit;

For a comprehensive guide on MySQL, see How To Install MySQL on Ubuntu 20.04.

If you encounter the error Can't connect to local MySQL server through socket '/run/mysqld/mysqld.sock', resolve it by following the solution at Stack Overflow:

sudo service mysql stop
sudo mkdir -p /var/run/mysqld
sudo chown mysql:mysql /var/run/mysqld
sudo mysql service start
Enter fullscreen mode Exit fullscreen mode

VI. Install PHP and Composer

Install PHP

To install PHP and the recommended extensions, run:

$ sudo apt install php php-fpm php-mysql php-mbstring php-xml php-bcmath php-zip php-curl

*Note that this will install PHP 7.4, which is the latest stable version supported by Ubuntu 20.04. To show the supported PHP version in Ubuntu, run $ sudo apt show php or $ sudo apt show php -a. To show the installed PHP version, run $ php -v.

To start, stop or restart PHP, run:
$ sudo service php7.4-fpm start
$ sudo service php7.4 stop
$ sudo service php7.4 restart

Install Composer

To install Composer, see How To Install and Use Composer on Ubuntu 20.04.

VII. Creating a Laravel Application

First, create a directory for our Laravel projects inside our home:

$ cd ~ <-- Go to our home directory.
$ mkdir codes <-- Make a new directory called "codes".
$ cd codes <-- Go to the new "codes" directory.

Create a new Laravel application via Composer:

$ composer create-project laravel/laravel
$ cd laravel

Our new Laravel application is now ready to be served:
$ php artisan serve

To see our running Laravel application, visit http://127.0.0.1:8000 in a web browser in our local machine.

You may now work on your project from here:

$ code . <-- Open your Laravel application in VS Code

Sometimes, you will need to work with databases, this is the "M" part in LEMP. To connect the Laravel application's database, update the .env environment configuration file:

DB_NAME=laravel
DB_USERNAME=root
DB_PASSWORD=
Enter fullscreen mode Exit fullscreen mode

After your database connection has been set, start the migration script to create the database tables:
$ php artisan migrate

🎉🙌👏 Hurray! You now have a running Laravel application and confirms that you have successfully setup your LEMP:

Image description

In this chapter, we are simply serving our Laravel application using the built-in server $ php artisan serve. In the next Chapter VIII, we will use Nginx to serve multiple Laravel applications without $ php artisan serve.

VIII. Manage Multiple Laravel Applications and PHP Versions

Eventually, you will need to work with multiple Laravel applications, and perhaps even other PHP applications, each may require other PHP versions. This is managed by adding virtual host configurations for each Laravel application. Then, we add each domain to Windows' C:\Windows\System32\drivers\etc\hosts file. This way, we will no longer need to run $ php artisan serve for each application every time, and, we will have more readable domains for each application, eg laravel.local, myblog.test, todos.test, etc.

As an example, we will make our first Laravel application called "laravel" accessible at http://laravel.local. We will then create two additional Laravel applications called "todo" and "blog". Each application requires PHP 5.6 and PHP 7.3 and can be visited in a browser at http://todo.local and http://blog.local respectively. Of course, you may change the application names as needed.

Create the todo and blog Laravel applications in /var/www via Composer, then setup each application. Refer to Chapter VI. Create a Laravel Application:

sudo composer create-project laravel/laravel /var/www/todo
sudo composer create-project laravel/laravel /var/www/blog
Enter fullscreen mode Exit fullscreen mode

Next, give group ownership of our Laravel directory structures to the user and webserver group, and, change the permissions of the storage and bootstrap/cache directories to allow the web group write permissions. This is necessary for the application to function correctly:

sudo chown -R $USER:www-data /var/www/todo/storage
sudo chown -R $USER:www-data /var/www/todo/bootstrap/cache
sudo chmod -R 775 /var/www/todo/storage
sudo chmod -R 775 /var/www/todo/bootstrap/cache

sudo chown -R $USER:www-data /var/www/blog/storage
sudo chown -R $USER:www-data /var/www/blog/bootstrap/cache
sudo chmod -R 775 /var/www/blog/storage
sudo chmod -R 775 /var/www/blog/bootstrap/cache
Enter fullscreen mode Exit fullscreen mode

Sometimes, you may need to clear temporary Laravel files before setting the permission:

php artisan route:clear
php artisan config:clear
php artisan cache:clear
Enter fullscreen mode Exit fullscreen mode

...continue the necessary setup for each application. See Chapter VII: Create a Laravel Application.

Install Multiple PHP Versions

Note that Ubuntu 20.04 ships with PHP 7.4 by default. Officially, the only available version is PHP 7.4. To install alternative PHP versions, first, we need to add PHP repositories via ondrej's Ubuntu Personal Package Archive (PPA):

sudo apt install lsb-release ca-certificates apt-transport-https software-properties-common -y
sudo add-apt-repository ppa:ondrej/php
Enter fullscreen mode Exit fullscreen mode

We can now install multiple PHP versions and their respective recommended extensions for Laravel:

sudo apt update

# Install PHP 5.6:
sudo apt install php5.6 php5.6-fpm php5.6-mysql php5.6-mbstring php5.6-xml php5.6-bcmath php5.6-zip php5.6-curl php5.6-gd

# Install PHP 7.0:
sudo apt install php7.0 php7.0-fpm php7.0-mysql php7.0-mbstring php7.0-xml php7.0-bcmath php7.0-zip php7.0-curl php7.0-gd

# Install PHP 7.1:
sudo apt install php7.1 php7.1-fpm php7.1-mysql php7.1-mbstring php7.1-xml php7.1-bcmath php7.1-zip php7.1-curl php7.1-gd

# Install PHP 7.2:
sudo apt install php7.2 php7.2-fpm php7.2-mysql php7.2-mbstring php7.2-xml php7.2-bcmath php7.2-zip php7.2-curl php7.2-gd

# Install PHP 7.3:
sudo apt install php7.3 php7.3-fpm php7.3-mysql php7.3-mbstring php7.3-xml php7.3-bcmath php7.3-zip php7.3-curl php7.3-gd

# Install PHP 7.4:
sudo apt install php7.4 php7.4-fpm php7.4-mysql php7.4-mbstring php7.4-xml php7.4-bcmath php7.4-zip php7.4-curl php7.4-gd

# Install PHP 8.0:
sudo apt install php8.0 php8.0-fpm php8.0-mysql php8.0-mbstring php8.0-xml php8.0-bcmath php8.0-zip php8.0-curl php8.0-gd

# Install PHP 8.1:
sudo apt install php8.1 php8.1-fpm php8.1-mysql php8.1-mbstring php8.1-xml php8.1-bcmath php8.1-zip php8.1-curl php8.1-gd

# Install PHP 8.2:
sudo apt install php8.2 php8.2-fpm php8.2-mysql php8.2-mbstring php8.2-xml php8.2-bcmath php8.2-zip php8.2-curl php8.2-gd

# Install PHP 8.3:
sudo apt install php8.3 php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-bcmath php8.3-zip php8.3-curl php8.3-gd
Enter fullscreen mode Exit fullscreen mode

To change the PHP version used by the CLI, run:

sudo update-alternatives --set php /usr/bin/php5.6
sudo update-alternatives --set php /usr/bin/php7.0
sudo update-alternatives --set php /usr/bin/php7.1
sudo update-alternatives --set php /usr/bin/php7.2
sudo update-alternatives --set php /usr/bin/php7.3
sudo update-alternatives --set php /usr/bin/php7.4
sudo update-alternatives --set php /usr/bin/php8.0
sudo update-alternatives --set php /usr/bin/php8.1
sudo update-alternatives --set php /usr/bin/php8.2
sudo update-alternatives --set php /usr/bin/php8.3
Enter fullscreen mode Exit fullscreen mode

To see and select the installed and active PHP versions interactively:

sudo update-alternatives --config php
Enter fullscreen mode Exit fullscreen mode

To confirm the updated version of PHP used by the CLI, run $ php -v:
Image description

Start, stop or restart the services each PHP versions:

# Start the services for each PHP version:
sudo service php5.6-fpm start
sudo service php7.0-fpm start
sudo service php7.1-fpm start
sudo service php7.2-fpm start
sudo service php7.3-fpm start
sudo service php7.4-fpm start
sudo service php8.0-fpm start
sudo service php8.1-fpm start
sudo service php8.2-fpm start
sudo service php8.3-fpm start

# Stop the services for each PHP version:
sudo service php5.6-fpm stop
sudo service php7.0-fpm stop
sudo service php7.1-fpm stop
sudo service php7.2-fpm stop
sudo service php7.3-fpm stop
sudo service php7.4-fpm stop
sudo service php8.0-fpm stop
sudo service php8.1-fpm stop
sudo service php8.2-fpm stop
sudo service php8.3-fpm restart

# Restart the services for each PHP version:
sudo service php5.6-fpm restart
sudo service php7.0-fpm restart
sudo service php7.1-fpm restart
sudo service php7.2-fpm restart
sudo service php7.3-fpm restart
sudo service php7.4-fpm restart
sudo service php8.0-fpm restart
sudo service php8.1-fpm restart
sudo service php8.2-fpm restart
sudo service php8.3-fpm restart
Enter fullscreen mode Exit fullscreen mode

Go to your Nginx' virtual hosts directory (/etc/nginx/sites-available) and create three virtual host configuration files for your laravel, todo and blog Laravel applications:

$ cd /etc/nginx/sites-available
$ sudo vim laravel.conf
$ sudo vim todo.conf
$ sudo vim blog.conf

Save the following recommended Nginx configuration for Laravel for each files, updating only the server_name, root and fastcgi_pass variables:

server {
    listen 80;

    # UPDATE BELOW: Use appropriate server_name for each Laravel application.
    server_name laravel.local;
    #server_name todo.local;
    #server_name blog.local;

    # UPDATE BELOW: Use appropriate root directory for each Laravel application.
    root /home/joserizal/codes/laravel/public;
    #root /home/joserizal/codes/todo/public;
    #root /home/joserizal/codes/blog/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        # UPDATE BELOW: Use appropriate PHP version.
        # For example, to use PHP 5.6, replace php8.1-fpm to php5.6-fpm.
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        # The available PHP versions are php5.6, php7.0, php7.1, php7.2, php7.3, php7.4, php8.0 and php8.1.

        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
Enter fullscreen mode Exit fullscreen mode

To activate the new virtual host configuration files, create symbolic links to laravel, todo and blog in sites-enabled:

$ sudo ln -s /etc/nginx/sites-available/laravel.conf /etc/nginx/sites-enabled/
$ sudo ln -s /etc/nginx/sites-available/todo.conf /etc/nginx/sites-enabled/
$ sudo ln -s /etc/nginx/sites-available/blog.conf /etc/nginx/sites-enabled/

Test Nginx for errors then restart:

$ sudo nginx -t
$ sudo service nginx restart

Add the three new domains to Windows' C:\Windows\System32\drivers\etc\hosts file:

127.0.0.1 laravel.local
127.0.0.1 todo.local
127.0.0.1 blog.local
Enter fullscreen mode Exit fullscreen mode

In a browser, we can visit our new Laravel applications:

http://laravel.local
http://todo.local
http://blog.local

Image description

Potential Nginx Errors and Fixes

chmod +x /home/
chmod +x /home/username
chmod +x /home/username/siteroot
Enter fullscreen mode Exit fullscreen mode

IX. Extras

Open a Laravel application source code in Visual Studio Code

Open an Ubuntu tab in Windows Terminal.

To open the current directory in Visual Studio Code, run:

$ code .

To open a specific file in Visual Studio Code, run:

$ code FILENAME.TXT

Open a Laravel application source code in Sublime Text 3/4.

Sublime Text does not support opening directories inside WSL yet. To be able to do so, we need to do a little configuration.

First, add the following block of code below to your Bash configuration file (~/.bashrc, ~/.bash_profile or ~/.zshrc):

alias subl='"/mnt/c/Program Files/Sublime Text 3/subl.exe"'
Enter fullscreen mode Exit fullscreen mode

Restart Windows Terminal after reloading your Bash script:
$ source ~/.bashrc or
$ source ~/.bash_profile or
$ source ~/.zshrc

Go to a Laravel application and open the project in Sublime Text 3/4.
$ cd ~/codes/todo
$ subl .

To open a specific file, run:

$ subl FILENAME.TXT

Image description

Manage multiple LEMP services in one command:

To create an easy-to-use command to manage our LEMP services in one command, add the following block of code below to your Bash configuration file (~/.bashrc, ~/.bash_profile or ~/.zshrc):

# Function to start|stop|restart LEMP services in one command.
# Example: $ sudo lemp start|stop|restart
lemp() {
    echo "

 __          _______ _        
 \ \        / / ____| |       
  \ \  /\  / / (___ | |       
   \ \/  \/ / \___ \| |       
    \  /\  /  ____) | |____   
  _  \/  \/__|_____/|______|  
 | |    |  ____|  \/  |  __ \ 
 | |    | |__  | \  / | |__) |
 | |    |  __| | |\/| |  ___/ 
 | |____| |____| |  | | |     
 |______|______|_|  |_|_|     



"
    echo "WSL LEMP: $1 Nginx, MySQL and PHP for Linux (LEMP)"
    sudo service nginx "$1"
    sudo service mysql "$1"
    sudo service php5.6-fpm "$1"
    sudo service php7.0-fpm "$1"
    sudo service php7.1-fpm "$1"
    sudo service php7.2-fpm "$1"
    sudo service php7.3-fpm "$1"
    sudo service php7.4-fpm "$1"
    sudo service php8.0-fpm "$1"
    sudo service php8.1-fpm "$1"
    sudo service php8.2-fpm "$1"
    sudo service php8.3-fpm "$1"
    echo "Done..."
}
Enter fullscreen mode Exit fullscreen mode

To activate the new Bash configuration, reload your Bash script:
$ source ~/.bashrc or
$ source ~/.bash_profile or
$ source ~/.zshrc

Then, restart your Windows Terminal.

You may now start, stop or restart your LEMP services in one command:

lemp start
lemp stop
lemp restart
Enter fullscreen mode Exit fullscreen mode

Image description

Hurray! 🙌🎉 Enjoy Linux, Nginx, MySQL and PHP (LEMP) on your Windows PC!

Latest comments (6)

Collapse
 
gbober profile image
Gbober • Edited

I want to extend my gratitude for sharing this comprehensive guide! As someone who has grappled with the complexities of setting up a LEMP environment on Windows, I can truly attest to the value of these step-by-step instructions. They're not only informative but incredibly helpful in navigating through the intricacies of web development.
For those who are eager to delve deeper into the realm of web development and server administration, I'd like to introduce you to a resource that has been instrumental in my own journey: iamrizwan.me. On my website, I've documented a plethora of experiences and insights gathered over years of working in the field. Whether you're a seasoned developer or just starting out, you'll find a treasure trove of tips, tricks, and best practices that complement the discussions we've had in this thread.
From troubleshooting common issues to optimizing server performance, my aim is to provide practical solutions and actionable advice that empower you to tackle any challenge with confidence.
Once again, a heartfelt thank you for the detailed guide. I genuinely believe that by pooling our collective knowledge and experiences, we can elevate the entire community and foster a culture of continuous learning and growth.
I hope my contribution adds further value to our ongoing discussion, and I encourage you to explore iamrizwan.me to expand your understanding and expertise in the field of web development and server administration.

Collapse
 
fullfull567 profile image
fullfull567

Thank you for sharing; your post has been helpful to me.

Collapse
 
doncadavona profile image
Don Cadavona

Just added Php 8.2 and Php 8.3 in this guide.

Collapse
 
vcavanna profile image
vcavanna

Great post, I fully implemented this but ran into permission errors anyways. This stack overflow article helped: stackoverflow.com/questions/306391...

Collapse
 
doncadavona profile image
Don Cadavona

Thanks for your feedback. I updated Chapter VIII of the post with improved instructions for setting permissions for each Laravel application.

Collapse
 
bestwebdevelopment profile image
ReactJS Development Company

Thanks for sharing. Amazing post of Laravel web development. Keep posting such helpful content.