To facilitate web development, I wanted the same environment on my Windows 10 desktop as exists on my Ubuntu VPS server. With WSL (Windows Subsystem for Linux), I can have the same LEMP (Linux, Nginx, MySQL, and PHP) setup on my Windows 10 desktop.
See my previous post, Install Subversion on Ubuntu WSL on Windows 10, to get an Ubuntu-flavored WSL working on your Windows 10 system.
Instructions to install LEMP on Ubuntu WSL are almost the same as what I used to install LEMP on my Ubuntu server (see Install Ubuntu, LEMP, and WordPress on an Unmanaged VPS).
Install PHP
The latest Ubuntu WSL version is 18.04.1 LTS, which supports the latest PHP 7.2 version.
# - php7.2-cli - PHP command line
# - php-mysql - PHP library to call MySQL database
# - php-fpm - PHP FastCGI Process Manager for Nginx integration
sudo apt install php7.2 php7.2-cli php7.2-mysql php7.2-fpm
# List the installed packages and grep for php-specific packages:
dpkg --get-selections | grep -i php
# Get the version of PHP installed
php --version
Install MySQL
sudo apt install mysql-server
# Get version of MySQL server and CLI installed
mysqld --version
mysql --version
# Start MySQL server
sudo service mysql start
sudo service mysql status
# Log into MySQL server as root user with blank password.
sudo mysql -u root
mysql> show databases;
mysql> quit
Note: Instead of using the “quit” command to exit the MySQL client, you can also use the “exit” command. Semi-colon termination (for example, “quit;” or “exit;”) are optional for these close connection commands.
By default, the MySQL server is configured to only allow root MySQL login from the root Linux user. Thus, we had to use “sudo mysql -u root” above. If we wish to allow a non-root Linux user to login using the root MySQL user (eliminate need for “sudo”), we’ll need to change how the root MySQL user is athenticated (switch to “mysql_native_password” plugin instead of the “auth_socket” plugin).
sudo mysql -u root
# Allow connection from a non-root Linux user
mysql> use mysql;
mysql> update user set plugin='mysql_native_password' where User='root';
mysql> flush privileges;
# Exit MySQL client.
mysql> quit
# Log into MySQL server as root user without "sudo".
mysql -u root
mysql> show databases;
mysql> quit
If you wish to secure the MySQL server, you can use the convenient “mysql_secure_installation” utility. Run the utility to enable password validation, set a root user password, remove anonymous users, disable remote root login, and remove the test database. You can re-run the utility again to reset the root user password if you need to.
sudo mysql_secure_installation
# Log into MySQL server as root user with password prompt
mysql -u root -p
mysql> show databases;
mysql> quit
If you wish to go back to using a blank MySQL root password, run the following to disable password validation and set a blank root password:
mysql> uninstall plugin validate_password;
mysql> set PASSWORD for root@localhost=PASSWORD('');
mysql> quit
Install Nginx
sudo apt install nginx
# Start Nginx server
sudo service nginx start
Browse to http://localhost/ and you should see the initial Nginx welcome page.
Start the PHP-FPM service so Nginx can execute PHP scripts.
grep "listen =" /etc/php/7.2/fpm/pool.d/www.conf
# output: listen = /run/php/php7.2-fpm.sock
# Start PHP-FPM service.
sudo service php7.2-fpm start
Edit the default Nginx server block file to use the PHP-FPM service:
In the “default” server block file, change the following:
# Add index.php to the list if you are using PHP
#index index.html index.htm index.nginx-debian.html;
# Add index.php to front of "index" to execute it first
index index.php index.html index.htm index.nginx-debian.html;
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# Make sure unix socket path matches PHP-FPM configured path above
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
# Prevent ERR_INCOMPLETE_CHUNKED_ENCODING when browser hangs on response
fastcgi_buffering off;
}
}
Restart the Nginx service to have the changes take effect:
Test PHP and MySQL Integration
Note: On my Ubuntu WSL system, the Nginx default configuration block file (“/etc/nginx/sites-available/default”) sets the document root directory to be “root /var/www/html”. On your system, Nginx may use a different document root path so please double-check the Nginx block file if you encounter errors below.
Create a PHP test script by running this edit command:
In the “info.php” file, input the following content:
phpinfo();
?>
Browse to http://localhost/info.php and you should see a page containing information about the PHP installation.
Create a PHP MySQL test script by running this edit command:
In the “mysql.php” file, input the following content:
// HTML response header
header('Content-type: text/plain');
// Database connection parameters
$DB_HOST = 'localhost';
$DB_PORT = 3306; // 3306 is default MySQL port
$DB_USER = 'root';
$DB_PASS = ''; // blank or password (if you set one)
$DB_NAME = 'mysql'; // database instance name
// Open connection (all args can be optional or NULL!)
$mysqli = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME, $DB_PORT);
if ($mysqli->connect_error) {
echo 'Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error . PHP_EOL;
} else {
// Query users
if ($result = $mysqli->query('SELECT User FROM user')) {
echo 'Database users are:' . PHP_EOL;
for ($i = 0; $i < $result->num_rows; $i++) {
$result->data_seek($i);
$row = $result->fetch_assoc();
echo $row['User'] . PHP_EOL;
}
$result->close();
} else {
echo 'Query failed' . PHP_EOL;
}
}
// Close connection
$mysqli->close();
?>
Browse to http://localhost/mysql.php and you should see a page listing the MySQL database users.
Debugging LEMP
To debug issues with LEMP, look at these log files:
Nginx: /var/log/nginx/error.log
PHP: /var/log/php7.2-fpm.log
For performance reasons, the debug logs from the PHP-FPM worker threads are discarded by default. If you wish to see error logs from your PHP applications, you will need to enable logging from worker threads.
Enable logging in the configuration of the PHP-FPM pool:
sudo nano /etc/php/7.2/fpm/pool.d/www.conf
# Uncomment this line:
catch_workers_output = yes
# Edit main PHP-FPM config file to set log level; otherwise you won't see any logs
sudo nano /etc/php/7.2/fpm/php-fpm.conf
# Uncomment this line:
log_level = notice
# Reload the PHP-FPM service to make the changes take effect
sudo service php7.2-fpm reload
You should now see error logs from the PHP worker threads outputted to the “/var/log/php7.2-fpm.log” file.
Tip: The PHP-FPM service may cache the PHP source files so after changing a PHP source file, you might need to reload the PHP-FPM service in order for the updated PHP code to execute.
Info above derived from:
Thanks!
If MySQL PHP integration fails because root cannot access mysql there’s a StackOverflow answer that might help.
https://stackoverflow.com/questions/39281594/error-1698-28000-access-denied-for-user-rootlocalhost
I use WSL with Ubuntu 18-04 so it’ll probably happen to someone else.
Thanks for the stackoverflow link. Turns out that I had used Option 1 above, which is to switch the root user to use the “mysql_native_password” plugin instead of the default “auth_socket” plugin.
Thank you!
Everything is working. Long time google could not help me)))
If done exactly according to the instructions, then when you try to execute
sudo nano /var/www/html/info.php
404 error, while the page localhost/ is working.
It helped me if you specify in the settings server{…}
root/var/www/html;
Great point. Thanks for pointing it out.
I added a note to indicate that the Nginx default configuration block file may set the document root to be something different than “/var/www/html”.