Are you using Nginx, PHP, PHP-FPM and MySQL on your Linux servers? Are you totally in love with this setup? I do! But, as a Web developer, I also need a local Web server on my Windows machine for testing. So far, I've always been using the standard "WAMP" setup: Windows, Apache, MySQL, PHP. Why couldn't I run Nginx and PHP-FPM on my Windows machine as well? Today, I will teach you how to achieve it so you can really say goodbye to Apache! This post covers the installation and configuration of the following products: - MySQL Win32 (server and client) - Cygwin - Nginx under Cygwin - MySQL (client only) under Cygwin - PHP and PHP-FPM under Cygwin IMPORTANT NOTES Table of contents 1 - Getting the needed files 2 - Installing MySQL Win32 (server and client) 3 - Installing Cygwin 4 - Installing Nginx under Cygwin 5 - Installing MySQL (client only) under Cygwin 6 - Installing PHP and PHP-FPM under Cygwin 7 - Creating Windows services 8 - Using your new installation Conclusion Resources Annex 1 - Simple benchmark 1 - Getting the needed files Download these files to your Windows machine: http://www./setup.exe http://dev./get/Downloads/M.../mysql_mirror/ http:///nginx/nginx-0.6.32.tar.gz http://dev./get/Downloads/M.../mysql_mirror/ http://php-fpm./downloads/...-0.5.9.diff.gz http://us3./get/php-5.2.6.tar...om/this/mirror http://www./people/m-kasahr...o-1.6.3.tar.gz If the PHP-FPM link isn't working, go here: http://php-fpm./download.html And download the latest version of PHP-FPM for PHP 5.2.6. 2 - Installing MySQL Win32 (server and client) First of all, unpack mysql-noinstall-5.0.67-win32.zip in c:\ and rename the mysql-5.0.67-win32 folder to mysql. Then, create the c:\my.cnf file with the following lines: c:\my.cnf: [mysqld] basedir=c:/mysql datadir=c:/mysql/data Now, open a Command Prompt window (Start, Run, "cmd" - or Win+R, "cmd") and type: REM " Change to the MySQL bin directory cd c:\mysql\bin REM " Install the MySQL service mysqld-nt --install REM " Start MySQL net start mysql MySQL is now running. It's a good idea to change the root password. In your Command Prompt Windows, type: REM " Change the MySQL root password mysqladmin -u root password pass By default, the MySQL service will start with Windows. You can change this behavior in Control Panel, Administrative Tools, Services. 3 - Installing Cygwin Run setup.exe and hit "Next" 6 times (you want "Install from Internet", choose the mirror of your choice). You will arrive at a huge list of packages to choose from. Tip: you can maximize that window. To select a package, click in the "New" column (it cycles through Skip, Keep, Uninstall, etc.). When a version number is displayed, it will be installed. Select these additional packages (dependencies for these packages will be automatically selected): Admin/cygrunsrv Devel/autoconf Devel/automake Devel/bison Devel/curl-devel Devel/flex Devel/gcc Devel/libiconv Devel/libmcrypt-devel Devel/libtool Devel/libxml2 Devel/libxml2-devel Devel/make Devel/patchutils Devel/pcre Devel/pcre-devel Editors/vim Libs/jpeg Libs/libmcrypt Then hit "Next" to install. Tip: you can run setup.exe anytime to add or remove packages. NOTE: these packages are those I needed for my own Nginx, MySQL and PHP ./configure's options. If your ./configure's options differ from mine, you may need to select additional packages or your ./configure's will fail for missing dependencies. -- Now that Cygwin is installed, run c:\cygwin\Cygwin.bat to get a shell Window. Your home directory (c:\cygwin\home\Administrator) will be created and prepared. Copy the following files in c:\cygwin\home\Administrator: nginx-0.6.32.tar.gz mysql-5.0.67.tar.gz php-5.2.6.tar.gz php-5.2.6-fpm-0.5.8.diff.gz getaddrinfo-1.6.3.tar.gz 4 - Installing Nginx under Cygwin Open Cygwin and extract nginx-0.6.32.tar.gz: cd tar xvfz nginx-0.6.32.tar.gz cd nginx-0.6.32 Now, configure Nginx: ./configure --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module And finally, compile and install Nginx: make make install -- Now we will prepare our "www" directory: mkdir /www As well as our Nginx configuration: /usr/local/nginx/conf/nginx.conf: worker_processes 5; You may adjust this configuration file to suit your needs. 5 - Installing MySQL (client only) under Cygwin We install the MySQL client only to be able to compile PHP with MySQL support. Open Cygwin and extract mysql-5.0.67.tar.gz: cd tar xvfz mysql-5.0.67.tar.gz cd mysql-5.0.67 Now, configure MySQL: ./configure --without-server And finally, compile and install MySQL: make make install 6 - Installing PHP and PHP-FPM under Cygwin Open Cygwin and extract php-5.2.6.tar.gz: cd tar xvfz php-5.2.6.tar.gz Then, patch PHP with PHP-FPM: gzip -cd php-5.2.6-fpm-0.5.7.diff.gz | patch -d php-5.2.6 -p1 Under Linux, you would be ready to configure, make and install PHP, but under Cygwin, there's a little fix to apply... Applying the getaddrinfo fix When I first tried to compile PHP with PHP-FPM under Cygwin, I ran into troubles with getaddrinfo. I tried to fix it myself but I only found 50% of the solution. So I contacted Andrei Nigmatulin, the creator of PHP-FPM, and he helped me with this problem. Here's what you need to do: cd tar xvfz getaddrinfo-1.6.3.tar.gz cp getaddrinfo/getaddrinfo.c getaddrinfo/getaddrinfo.h php-5.2.6/sapi/cgi/fpm Then, edit php-5.2.6/sapi/cgi/fpm/fpm_sockets.c and add the following line after the other includes: php-5.2.6/sapi/cgi/fpm/fpm_sockets.c: #include "getaddrinfo.h" Then, you need to add "getaddrinfo.c" to the FPM_SOURCES variable in php-5.2.6/sapi/cgi/fpm/config.m4: php-5.2.6/sapi/cgi/fpm/config.m4: FPM_SOURCES="fpm.c \ Then, you have to rebuild the PHP Makefile: cd php-5.2.6 ./buildconf --force -- We are now ready to configure PHP: ./configure --enable-fastcgi --enable-fpm --with-mcrypt --with-zlib --enable-mbstring --with-openssl --with-mysql --with-gd --with-jpeg-dir --enable-gd-native-ttf --without-sqlite --disable-pdo --disable-reflection --with-curl --with-iconv Then, make and install PHP: make all install And finally, install the default php.ini file: cp php.ini-recommended /usr/local/lib/php.ini You can edit /usr/local/lib/php.ini to suit your needs. You can also edit /usr/local/etc/php-fpm.conf if you need. 7 - Creating Windows services The Cygwin application "cygrunsrv" allows you to create Windows services. We definitely want to do this for Nginx and PHP. First of all, in Cygwin, let's create the services scripts: /home/Administrator/php.sh: #!/bin/sh function handleQuit { echo "STOPPING" su Administrator -c "/usr/local/sbin/php-fpm stop" exit } echo "STARTING" su Administrator -c "/usr/local/sbin/php-fpm start" trap "handleQuit" SIGQUIT echo "WAITING" while true do sleep 1 done /home/Administrator/nginx.sh: #!/bin/sh function handleQuit { echo "STOPPING" su Administrator -c "kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid)" exit } echo "STARTING" su Administrator -c "/usr/local/nginx/sbin/nginx" trap "handleQuit" SIGQUIT echo "WAITING" while true do sleep 1 done Then, under Windows, use the following batch file to create the services: cywgin_install_services.bat: @echo off echo. cd c:\cygwin\bin echo Stopping services... net stop php net stop nginx echo Removing services... cygrunsrv -R php cygrunsrv -R nginx echo Installing services... cygrunsrv --install php --path /home/Administrator/php.sh --desc "PHP-FPM" -t auto --termsig QUIT --shutdown cygrunsrv --install nginx --path /home/Administrator/nginx.sh --desc "Nginx" -t auto --termsig QUIT --shutdown echo These services are now installed: echo. cygrunsrv -L echo. pause Voila! Our Windows services are created! But... how does it work? Let's examine the creation of a service, with some comments... cygrunsrv # Name of the service --install php # Path of the file to execute --path /home/Administrator/php.sh # Description of the service --desc "PHP-FPM" # Startup type (auto or manual) -t auto # Signal to send to the service when stopping it --termsig QUIT # Stop the service when shutdowning Windows --shutdown When /home/Administrator/php.sh is invoked by Windows to start the service, we start PHP-FPM as Administrator (because we don't want to run as SYSTEM). Then, we order the script to trap QUIT and to execute the handleQuit() function when it gets one. Then, we wait for something to happen with an infinite while/sleep loop. When a QUIT signal is caught (Windows wants to stop the service), the handleQuit() function is executed: PHP-FPM is stopped, and the script exits. 8 - Using your new installation To start/stop MySQL on your Windows machine, use the following commands: REM " Start MySQL net start mysql REM " Stop MySQL net stop mysql To start/stop PHP on your Windows machine, use the following commands: REM " Start PHP net start php REM " Stop PHP net stop php To start/stop Nginx on your Windows machine, use the following commands: REM " Start Nginx net start nginx REM " Stop Nginx net stop nginx So if you start MySQL, Nginx and PHP, and that you create this file... /www/index.php: print "Hello world!"; ...then you should be able to point http://locahost with your Web brower and see "Hello world!". -- VERY important note about PHP and mysql_connect Don't do this: mysql_connect("localhost","root","pass"); It won't work because then PHP wants to use the mysql.sock file (/tmp/mysql.sock or /var/run/mysql.sock) and this file doesn't work under Cygwin. So instead, do this: mysql_connect("127.0.0.1","root","pass"); By using the IP address, PHP will connect to MySQL using TCP networking. So far, it's the only limitation I've found with this setup. Conclusion That's it! You did it! You've just replaced your old WAMP setup by a faster Nginx+PHP+PHP-FPM (WNMP?) setup! I ran a pretty simple benchmark (see Annex 1 below) with both setups and, on my machine, my new WNMP setup is around 33% faster than my old WAMP setup! Thanks for reading... all comments are welcome! Resources Nginx Web site http:/// Nginx English Wiki http://wiki./Main http://wiki./NginxCommandLine And thanks to Andrei Nigmatulin, the creator of PHP-FPM, for his help. Annex 1 - Simple benchmark I ran a very simple benchmark on my 2 setups: - connect to MySQL - flush test table - start timer - insert 10,000 records in test table - select the 10,000 records from test table - display each record - close connection to MySQL - display timer The average time for Nginx was 2 seconds while Apache had an average of 3.1 seconds. If you use this script, don't forget to adjust the root password for mysql_connect! And don't run the test on both setups at the same time because they share the same test table. SQL: CREATE DATABASE test; USE test; CREATE TABLE test ( pk bigint auto_increment, a varchar(50), b varchar(50), c varchar(50), d varchar(50), primary key(pk) ); index.php: // Debug function function debug($d) { print "<pre>".print_r($d,true)."</pre>"; } // Include the timer class file require_once("timer.php"); // Connect to the database mysql_connect("127.0.0.1","root","pass"); // Use the test database mysql_select_db("test"); // Remove everything from the test table mysql_query("delete from test;"); // OK we're ready to begin the test, start the timer $timer = new Timer(); // Insert 10,000 records in the test table for ( $i = 1; $i <= 10000; $i++ ) { mysql_query("insert into test (a,b,c,d) values ('a','b','c','d');"); } // Fetch these 10,000 records $res = mysql_query("select * from test;"); // Display these 10,000 records while ( $row = mysql_fetch_object($res) ) { debug($row); } // We're done, close the MySQL connection mysql_close(); // Display the time print "<hr>"; print $timer->fetch(); timer.php: class Timer { var $s; function Timer() { $this->s = $this->getmicrotime(); } function fetch($decimalPlaces = 3) { return round(($this->getmicrotime() - $this->s), $decimalPlaces); } function getmicrotime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } } |
|