Install and configure a fully functional web server on WSL 2

May 24, 2021 MrAnyx 10 min to read


We assume that the linux subsystem is already activated. If you haven't already, follow the tutorial here.

For this example, we'll be using Ubuntu 20.04 LTS.

Update the distribution

In order to have the latest versions of the various libraries pre-installed, we will need to update the libraries.

sudo apt update

Then we will perform an upgrade of the libraries.

sudo apt upgrade

This last command may take a few minutes depending on your internet connection.

Install the necessary libraries

We will then install Apache, MySQL and PHP In order to create the basic structure of the LAMP stack (Linux, Apache, MySQL, PHP).

sudo apt-get install apache2 php7.4 libapache2-mod-php7.4 mysql-server php7.4-mysql

Here we have specified the PHP version we wanted to use. Here version 7.4.

We are also going to need to install some very common modules.

sudo apt-get install php-curl php-gd php-intl php-json php-mbstring php-xml

At the end of this step, we have: Apache as well as MySQL installed on the Linux subsystem. All that remains is to configure everything.

First of all, we will stop the apache2 and mysql services.

sudo service apache2 stop
sudo service mysql stop

We are now going to prevent these two services from starting automatically.

sudo systemctl disable apache2
sudo systemctl disable mysql

Installation of a graphical interface for the database

In order to facilitate the management of the database, it may be convenient to install a database management interface. If you are already using database management tools such as TablePlus or HeidiSQL, you will not need to perform this step.

Let's start by installing the adminer library.

sudo apt-get install adminer

Adminer is a small, very simple and very light interface for managing databases. It is written in PHP. We prefer to use Adminer rather than other solutions like phpMyAdmin because it is much lighter.

We can now configure the url that will be used to access the admin interface.

echo "Alias /adminer.php /usr/share/adminer/adminer.php" | sudo tee /etc/apache2/conf-available/adminer.conf

All that remains is to activate this new apache configuration.

sudo a2enconf adminer.conf

Then to restart the apache2 service.

sudo service apache2 restart

In this way, by going to the url localhost/adminer.php , you will be on the admin interface.

Adminer interface

MySQL configuration

It's all very well to have an interface for database management, but if we don't have any databases, it's useless.

So we'll have to create a user to access the database.

Indeed, since Ubuntu 18.04, the connection with the root user is only possible with the use of the command sudo . We must therefore create a user to avoid this restriction.

To do this, we first need to start the mysql service.

sudo service mysql start

It is possible that when you start the mysql service, the terminal returns [failed]. To resolve this, try running the command sudo usermod -d /var/lib/mysql/ mysql. If this still doesn't work, perform a shutdown of WSL 2 with the command wsl.exe --shutdown directly in the WSL terminal. Once done, restart the terminal and then run the command sudo service mysql start again. If this still doesn't work, stop the Apache service, then try starting MySQL and then Apache.

Then we will use the MySQL command lines.

sudo mysql

To create a user, simply enter the following command.

CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';

user will be the name of the new user. localhost is the host that the user will be able to connect to. Finally, password is the password for this new user. Of course, you can use a different username and password than the one shown in this demonstration.

We then need to add permissions to this user.

GRANT ALL PRIVILEGES ON * . * TO 'user'@'localhost';

Here ALL PRIVILEGES means that we want to give this user the rights to :

  • DROP

It is also possible to give only certain privileges to this user.

GRANT right_name ON db_name.table_name TO 'username'@'localhost';

Then to remove rights, simply change the GRANT keyword to REVOKE.

REVOKE right_name ON db_name.table_name TO 'username'@'localhost';

All that remains is to update the user's privileges.


So, if we go to the url : localhost/adminer.php, and use the user we have just created and then indicate the database : mysql, we now access the database named mysql with the user we have created.

To exit the MySQL command interface, simply enter the quit command.

PHP configuration

We will need to make some changes to the php.ini file located in /etc/php/7.4/apache2 .

To modify this file, we will use the nano utility natively available on Ubuntu 20.04.

sudo nano /etc/php/7.4/apache2/php.ini

We will then perform a search on the display_errors element. To do this, execute the command ctrl+w and then type the text : display_errors.

The cursor should automatically move to the following line:

display_errors = Off

If this is not the case, press ctrl+w again and then press the enter key on the keyboard until you find the right line.

Change the value of display_errors to On. You should get :

display_errors = On

Do the same for the display_startup_errors element a few lines below.

Then for the error_reporting element, we will keep only the value E_ALL.

error_reporting = E_ALL

We will now save the changes and exit. To do this, press ctrl+x then y and finally press enter on the keyboard.

Apache configuration file

Let's take a look at what an Apache configuration file looks like. These are located in the /etc/apache2/sites-available folder.

Currently, in this folder we find two files :

  • 000-default.conf
  • default-ssl.conf

If we display the contents of the 000-default.conf file with the command :

cat /etc/apache2/sites-available/000-default.conf

We will end up with something like this :

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

The most important lines are:

  • <VirtualHost *:80> : Here, we will accept any IP on port 80. For now, the only IP configured is localhost,
  • DocumentRoot /var/www/html : This line is the entry point for the site,
  • ErrorLog ${APACHE_LOG_DIR}/error.log : This line will allow you to specify the log file containing the list of errors that occurred during the hosting of the site.

To make things a little easier during the development of a site, we will create a symbolic link between a directory on your Windows machine and a directory on the Linux subsystem.

By chance, when WSL is initialized, it will automatically mount your hard disks. This way we can access them from Ubuntu 20.04 via the /mnt directory.

To do this, assuming that we have a directory located in D:\Sites\project. We will then create a symbolic link between this directory and the symbolic directory located in /var/www/project. To do this, we will run the following command.

sudo ln -s /mnt/d/Sites/projet /var/www/projet

In order to verify that the link has been executed, we will run the command

cd /var/www && ls -l

We notice that the html directory has not moved, but a new directory has been created. Furthermore, with the ls -l command, we notice that the project directory is linked to the /mnt/d/Sites/project directory.

All that remains is to modify the Apache configuration file to include the new directory as an entry point.

sudo nano /etc/apache2/sites-available/000-default.conf

Then we will modify the DocumentRoot line.

DocumentRoot /var/www/projet

All that remains is to apply the new changes.

sudo service apache2 reload

So, if we go to localhost we see this page appear.

This is quite normal because, at the moment, we have no file in the D:\Sites\project directory.

If we create a index.php file in the D:\Sites\project directory, and then put the following content :

<?php phpinfo(); ?>

By refreshing the page on your browser, you should see a next page.

It is possible that, when starting the apache2 service, you may get the following error :

Protocol not available: AH00076: Failed to enable APR_TCP_DEFER_ACCEPT

To solve this problem, simply add the lines AcceptFilter http none and AcceptFilter https none to the end of the /etc/apache2/apache2.conf file. This way, the error will no longer be displayed.

Create a site.local url

Modifying the url is not necessarily very useful. However, don't be fooled. It not only allows you to have custom urls but also to host multiple sites on the Linux subsystem.

We will now create a blog directory in the D:\Sites folder. Then we will create the symbolic link between this directory and the /var/www/blog folder.

sudo ln -s /mnt/d/Sites/blog /var/www/blog

By running the ls -l command in the /var/www directory, we notice that we now have three directories. The two we saw earlier: html and project. We also find our new blog directory which is directly linked to the /mnt/d/Sites/blog directory.

We will now create our own Apache configuration file.

Simply create a file that we will name blog.conf in the /etc/apache2/sites-available directory.

sudo touch /etc/apache2/sites-available/blog.conf

In which we will put the following content :

<VirtualHost *:80>
        ServerAlias blog.local
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/blog

        <Directory /var/www/>
               Options Indexes FollowSymLinks MultiViews
               AllowOverride all
               Order allow,deny
               Allow from all

        ErrorLog /var/log/apache2/
        CustomLog /var/log/apache2/ combined

All we have to do is activate the new configuration and restart the apache2 service.

sudo a2ensite blog.conf

Then we restart the Apache service.

sudo service apache2 restart

You can now put whatever content you want in the D:\Sites\blog directory. For the example we will put a basic html template.

<html lang="en">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <h1>My awesome blog</h1>

Unfortunately, if we go to the url blog.local, we get a DNS error (DNS_PROBE_FINISHED_NXDOMAIN). In other words, the default DNS used by the computer does not recognise this url. This is perfectly normal. You will simply have to tell it manually.

To do this, go to the C:\Windows\System32\drivers\etc directory and open the hosts file.

Then you just need to add the following lines at the end of the file :

::1               blog.local         blog.local

This file is protected by administrator rights. To modify it, you just need to launch a text editor such as NotePad++ or Visual Studio Code as an administrator. You can then modify this file.

Now, if we go to the url blog.local, you should find the blog page.

Enable url rewriting

If you want to use a framework such as Symfony or Laravel, you will have to activate the url rewriting.

To correct this problem, you will just have to execute the following commands :

sudo a2enmod rewrite

Then restart the Apache service.

sudo service apache2 restart

This manipulation will allow, via the use of a .htaccess file, to rewrite the Apache rules.

👍 Normally, with all this information in hand, you should be ready to create your website.

Deleting a site

In some cases, you may want to delete a site. It's very simple. Just delete the configuration files located in/etc/apache2/sites-available and /etc/apache2/sites-enabled and then delete the site folder in /var/www.

sudo rm /etc/apache2/sites-available/project_name.conf
sudo rm /etc/apache2/sites-enabled/project_name.conf
sudo rm /var/www/project_name

All that remains is to delete the log files corresponding to this configuration. These log files are located in the /var/log/apache2 directory.

sudo rm /var/log/apache2/project_name.log

You can now restart the Apache service to take into account the new changes.

sudo service apache2 restart

I really hope that this article has helped you or made you want to discover new technologies 💻.

Cover by Christopher Gower

This work is made available under the terms of the license Licence Creative Commons