Skip to content

Instantly share code, notes, and snippets.

@sebastian-meyer
Last active December 20, 2023 23:41
Show Gist options
  • Save sebastian-meyer/be4662db945c1df3e95e020970cba606 to your computer and use it in GitHub Desktop.
Save sebastian-meyer/be4662db945c1df3e95e020970cba606 to your computer and use it in GitHub Desktop.
PHP Web Development on WSL2

PHP Web Development on WSL2

Introduction

The goal is to have an easy to use environment for developing web projects with PHP. We don't want to fiddle with configuration files each time we start a new project or try a different version of our project. Instead we want to create a new directory, deploy our files and fire up the browser to get going.

The following environment provides Debian GNU/Linux 12 (Bookworm) with PHP 8.1, Composer 2.x, Nginx 1.22, MariaDB 10.11, Memcached and Redis.

Recommendation: Windows Terminal

Windows Terminal is not strictly necessary to run WSL, but it is highly recommended. Windows Terminal supports multiple command lines in tabs or window panes which makes switching between multiple Linux distributions or other command lines easy. Follow the instructions for Windows Terminal installation.

Accessing the Microsoft Store

When installing WSL or any Linux distribution the default command downloads all files from the Microsoft Store. If you can't access the Microsoft Store you can use the parameter --web-download with any wsl.exe --install and wsl.exe --update command or manually download and install the package from GitHub.

Setting up the environment

Installing Windows Subsystem for Linux (WSL)

Follow the instructions to Install WSL

  • Start a PowerShell as Administrator
  • Run WSL installation
    • wsl.exe --install --no-distribution

Alternatively on older versions of Windows:

Follow the Manual installation steps for older versions of WSL

  • Start a PowerShell as Administrator
  • Activate the WSL Feature
    • dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
  • Activate the VM Platform Feature
    • dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
  • Reboot
  • Download and install the Linux Kernel Update Package
  • Update WSL components to latest version
    • wsl.exe --update
  • Use WSL2 as default
    • wsl.exe --set-default-version 2

Installing Debian/GNU Linux

  • Download and install distribution image
    • wsl.exe --install -d Debian
  • Set username and password
  • Start shell with root privileges
    • sudo -s
  • Update packages
    • apt-get update && apt-get upgrade
  • Install useful packages
    • apt-get install curl git lsb-release mc nano unzip wget zip
  • Add DEB.SURY.ORG package archive for PHP
    • curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
    • sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ bookworm main" > /etc/apt/sources.list.d/php.list'
    • apt-get update
  • Install development packages
    • apt-get install mariadb-server memcached nginx php8.1-bcmath php8.1-cli php8.1-curl php8.1-fpm php8.1-mbstring php8.1-mysql php8.1-xml php-tokenizer redis
  • Secure MariaDB instance
    • service mariadb start
    • mysql_secure_installation
      • Set password for root
  • Install Composer
    • Create and run ./install_composer (see below)
    • Allow Composer (and PHP) to write in web directories
      • chown -R www-data:www-data /var/www
  • Configure Nginx server
    • Stop service
      • service nginx stop
    • Create /etc/nginx/sites-available/dev-sites (see below)
    • Deactivate default site
      • rm /etc/nginx/sites-enabled/default
    • Activate development sites
      • ln -s /etc/nginx/sites-available/dev-sites /etc/nginx/sites-enabled/dev-sites
  • Start all services
    • Create and run /usr/local/bin/startup_env (see below)

Working with the environment

The Nginx configuration automatically serves sub-directories like /var/www/*.localhost/ as http://*.localhost while using /var/www/*.localhost/public/ as document root. Using domains other than localhost may require additional DNS configuration.

E. g. the file /var/www/example.localhost/public/index.php can be reached via http://example.localhost/index.php.

The files in WSL can be accessed in Visual Studio Code by using the Remote Development extension pack (or at least the WSL plugin). There is a nice tutorial on how to set up the IDE.

Alternatively, the WSL filesystem can be mounted as network storage in the file explorer with the address \\wsl$\Debian. Or you can symlink your Windows filesystem (automatically mounted as /mnt/c, /mnt/d, etc.) to /var/www/* and keep your files where they are. Be aware that cross-system filesystem performance is not the fastest with WSL2.

There are some helpful basic commands for WSL.

Restarting the environment

  • Start all services after reboot
    • sudo startup_env
@sebastian-meyer
Copy link
Author

install_composer.sh

#!/bin/sh

EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"

if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
then
    >&2 echo 'ERROR: Invalid installer checksum'
    rm composer-setup.php
    exit 1
fi

php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php
mv composer.phar /usr/local/bin/composer
rm install_composer.sh
exit $RESULT

@sebastian-meyer
Copy link
Author

sebastian-meyer commented Nov 7, 2022

dev-sites

server {
    listen 127.0.0.1:80 default_server;
    listen [::1]:80 default_server;
    server_name _;

    root /var/www/${host}/public;

    index index.php index.htm index.html;

    charset utf-8;

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

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_buffering off;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    }

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
}

@sebastian-meyer
Copy link
Author

startup_env

#!/bin/sh

service mariadb start
service memcached start
service redis-server start
service php8.1-fpm start
service nginx start

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment