Nginx + PHP + MySQL on Windows in 6 minutes

Setting up PHP with Nginx

In our previous example, we setup PHP with Nginx’s fast-cgi capability.

This example is essentially the same with some minor alterations…

Navigate to C:\nginx\php, copy and rename php.ini-production to php.ini.

In this php.ini file, scroll down to (or hit Ctrl + F to find in Notepad) extension_dir = “ext”. Remove the semicolon in front uncomment this line.

Now scroll down to the “Windows Extensions” section and uncomment the following lines :

extension=php_bz2.dll
extension=php_gd2.dll
extension=php_imap.dll
extension=php_mbstring.dll
extension=php_mysql.dll
extension=php_mysqli.dll

Also change the include path location :

include_path = "c:\php\PEAR"

This is in case you want to install any PEAR modules (which can be frankly annoying at times), you just need to download, extract and copy to the PEAR folder.

I think these extensions would be required for functional content management which, I imagine, is the reason you’re reading a post on installing MySQL with Nginx and PHP in the first place.

And finally, uncomment the following line :

log_errors = On

After these changes are done, we can finally get into the the Nginx configuration…

Setup Nginx

In C:\nginx\conf\ copy nginx.conf as a backup and edit the original. Find the following lines, uncomment them and change the fastcgi_param :

location ~ \.php$ {
	root		html;
	fastcgi_pass	127.0.0.1:9000;
	fastcgi_index	index.php;
	fastcgi_param	SCRIPT_FILENAME	$document_root$fastcgi_script_name;
	include		fastcgi_params;
}

I modified this bit from an absolute path of the html folder to $document_root, which is a better way to do things.

Update Feb 26, 2012 for HaKi’s concern about uploaded executions

If you have an upload directory on your server, it’s best to avoid any PHP executions on any uploaded files.
E.G :


location /uploads {
	if $request_uri ~ \.php$ {return 403;}
}

And that should be it for the configuration…

Onward to starting your server…

About these ads

82 thoughts on “Nginx + PHP + MySQL on Windows in 6 minutes

  1. Pingback: nginx + PHP on Windows in 5 minutes « This page intentionally left ugly

    • Thanks!

      Oh yes, I was going to leave it with bat files like Kevin’s old distribution, but then I remembered, I didn’t like seeing those command line windows popping up. ;)

  2. Thank you, this is a very well written tutorial and I found it very helpful. I skipped the MySQL part because I don’t need it and the nginx and php are working great but I have a problem with your start/stop scripts.

    Everytime I run the start script (with the MySQL line commented out) it creates at least 6 processes that I can see in the Windows Task Manager. These are:

    cmd.exe
    cmd.exe
    nginx.exe
    nginx.exe
    PHP-CGI.EXE

    Then I run the stop script (with the MySQL line commented out) it does indeed close the nginx process, but it does NOT close the php-cgi process or the cmd processes and in fact creates two more cmd processes, leaving me with the following processes still running.

    cmd.exe
    cmd.exe
    cmd.exe
    cmd.exe
    PHP-CGI.EXE

    Let’s say I repeat these steps (as in restarting the server and stopping it again), then I will be left with the following processes still running:

    cmd.exe
    cmd.exe
    cmd.exe
    cmd.exe
    cmd.exe
    cmd.exe
    cmd.exe
    cmd.exe
    PHP-CGI.EXE
    PHP-CGI.EXE

    So, if I am testing changes to my nginx configuration which require restarting the server multiple times, this quickly becomes a huge mess of processes, which are using a fair bit of memory until I log out or restart my computer, or manually end them in the Task Manager.

    Do you agree that this is a problem, and if so could you address this by updating your post with new scripts? In the meantime, I will try to write my own scripts and post them up here if they are any good.

    Thanks

    • Hi Aaron, glad you found it useful.

      Try this :

      Instead of using VBScripts alone, create a couple of new bat files called start.bat and stop.bat

      In start.bat, enter the following :

      @ECHO OFF
      start nginx
      c:\nginx\php\php-cgi -b 127.0.0.1:9000 -c c:\nginx\php\php.ini

      And in stop.bat :

      @ECHO OFF
      nginx -s quit
      taskkill /f /IM php-cgi.exe
      

      Now change the start and stop vbs files to the following :

      In start.vbs…

      Dim sh
      Set sh = WScript.CreateObject("WScript.Shell")
      
      sh.run "start.bat", 0
      
      Set sh = Nothing

      And in stop.vbs…

      Dim sh
      Set sh = WScript.CreateObject("WScript.Shell")
      
      sh.run "stop.bat", 0
      
      Set sh = Nothing

      Now this does leave you with four files to control the startup and shutdown of your server and php-cgi instead of the original two, but now at least it should completely stop the php-cgi process and prevent those extra cmd processes.

      • Hi eksith,

        Thanks for your great tutorial.
        Using the bat scripts, how do I start and shut down mysql server?

        Am I suppose to add the following at the end of start.bat:
        C:\nginx\mysql\bin\ & mysqld
        and the following at the end of stop.bat?
        C:\nginx\mysql\bin\ & mysqladmin -u root shutdown

  3. I think the correct switch to close a CMD after having executed the line is /C

    Check it out in cmd /?

    Maybe that’s why in the end there’s a lot of CMD processes running..

  4. Thanks again for this tutorial really very useful. I am stuck at the moment. I’ve gone through this process, have nginx and mysql started fine… or so I think, simply loading the “Welcome to NGINX!” screen at http://localhost/… which works.

    But when I create a new file, test.php with contents of , loading the page runs and returns “The page you are looking for is temporarily unavailable. Please try again later. ” after a few minutes.

    Am I missing something obvious? Thanks again!

    • If that’s the case, then check to see if php-cgi.exe is running in the list of background processes.
      If it’s not running, then start it by running the following:

      C:\nginx\php\php-cgi.exe -b 127.0.0.1:9000

      I’m hoping it’s something simple like php-cgi.exe not running, or else, we’ll need to dig deeper. If that FastCGI process isn’t running, then nginx can’t hand off PHP requests so I think that’s why it says “temporarily” unavailable.

      Also double-check to see if the files are unzipped to the correct locations and all files were copied over.

      • So strange… when I try to execute that line from c:\ngingx\php\, cmd returns:

        The system cannot execute the specificed program

        I am able to open files in this directory, but trying to execute any .bat or .exe returns this vague error.

        I’m on a Windows XP box (VM), so not like I need to run as administrator, which I am.

        I’ll try this setup on another box, see if I run into the same issue. Thanks again!

      • AH!

        That usually means the system doesn’t have the Visual C++ redistributable installed. On most computers with windows, the redistributable is included because of bundled software, but a VM box is “too clean” ;)

        Try installing the Microsoft Visual C++ Redistributable Package and see if it can run.

        Depending on what you’re running, you’ll need the x86 version or the x64 version

  5. Pingback: Nginx + PHP + MySQL on Windows | Nginx Lighttpd Tutorial

  6. Pingback: WEMP – Nginx + PHP + MySQL no Windows em 6 minutos | blogdodiego.net

    • Hi nXqd,

      This usually means that another service is using port 80.

      You can change the port to something else in the config file like 8080 if you’re just testing.

      Or else, check to see if you have something like Skype or perhaps the Tor project’s Polipo running in your services. If they are, close them and try again.

    • Hi vitalyx,

      I think this article does the best job explaining the differences and why in this case I went with thread-safe.

      Short version : Because this is on Windows, there may be some hiccups when using the non-thread safe branch with thread-safe software.

  7. Maybe I stupid here but what is the fastcgi script name?

    c:/nginx/html/$fastcgi_script_name;

    Shall it look like this or shall I replace it with something else?

    I get an error that the fastcgi_script is not set.

    Any suggestions?
    Thanks,
    Bernt

    • Hi Bernt, the $fastcgi_script_name is basically a placeholder for nginx. Any file from that html folder with a .php extension will go through FastCGI this way.

  8. stupid tutorial! you didn’t even specify where the mysql.sock is found, can’t see where the folder temp is found lol

    • The file is created at runtime. “c:/nginx/mysql/tmp/mysql.sock” As mentioned twice.

      “stupid tutorial!”
      The dozen or so emails I get daily thanking me for this disagree.

  9. Great post, love the tutorial which have saved me many hours myself setting it all up on a my winbox for develop and testing

    Y R the man!

    Regards

  10. After having a bit of trouble showing a phpinfo() page on a friends system, we found it was due to short_open_tags being set to Off as standard, and us using “” to test :)

    Most standard PHP distributions have “short_open_tags = On”. I wont even enter the debate whether using short open tags in PHP are bad code practice or not, but just a helpful hint: Your PHP pages will show pure source code if you use <?'s as openers and have not set "short_open_tags = On" in php.ini.

    • “I wont even enter the debate whether using short open tags in PHP are bad code practice or not”

      Good call ;)

      Thanks for sharing that, Jakob. I’m sure there are others who came across the same issue.

  11. create a txt file with in it, then rename the file as image.gif
    paste this in your localhost/upload/ folder.
    open browser and type localhost/uploads/image.gif/x.php :)
    users can execute php code in your server if you allow them to upload files :)

    • HaKi, yes that is a problem.

      The solution is to limit any uploads only to a specific folder and deny execution of PHP files stored there. I’ve updated the code on page two for the nginx configuration reflecting that.

  12. location ~ \.php$ {
    root html;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    if ($uri !~ “^/uploads/”) { fastcgi_pass 127.0.0.1:9000; }
    }
    this works for me. with your fix i can still execute the php

  13. Pingback: Alternatif Apache « Wisnau

  14. I can’t run those .vbs files on my Windows Vista SP2. When I tried to run them, a dialog box appear and it said “Can’t find script engine “VBScript” for script “C:\nginx\start-server.vbs””

    • This is an issue on your local machine.

      I’m guessing you have a McAfee or similar AV program. They have been known to make Windows “forget” to use the VBScript engine to run .vbs files.

      Try this fix (it’s for Windows 7, but should work equally well for Vista).

  15. Hi,

    Just somethings that I have noted during my installation of this setup here (I am new to these):

    For 403 forbidden access
    nginx.conf:
    line 45: index index.php index.html index.htm;

    I have notice that if I run the commands using the vbs, mysql server would not start.. When I went through the cmd lines one by one, I have noted that the php-cgi.exe would not exit and hence conclude that it would be better to start mysql server first.

    And when I run through the commands one by one, I noted that extension_dir in php.ini needs to be defined:
    php.ini:
    line 730: extension_dir = “C:\nginx\php\ext\”

    Thanks for your clear instructions still. :)

    • Hi Robert,

      There may be a security setting preventing VBS files from executing. VBS is a fairly common vector for worms and such so some systems may prevent some functionality.

      Thanks ext dir fixup. I noticed that this was already posted in the comments by nXqd, but it seems I never updated in my post.

  16. Pingback: nginx Web Server – 'some notes

  17. Pingback: Windowsへのnginx + PHP + MySQLの導入 - kur.jp

  18. At least for me, I had to set PHP_FCGI_MAX_REQUESTS to 0 so I won’t hit the default 500 hit limit — it’ll simply stop serving requests after 500. Setting it to 0 removes that limit. And no matter what I set PHP_FCGI_CHILDREN to, PHP will not auto-spawn. This behaves so differently from the Linux environment. Have you figured out how to get either the spawn-fcgi or FPM working correctly on Windows without using Cygwin?

    • Hi PMob, sorry a little late to reply to this.

      Honestly, that I didn’t figure out yet. Then again, this was just a very quick example and I probably need to update this completely since new versions of all the software have come out.

      The PHP_FCGI_CHILDREN issue seems like a bug in the Windows build to me. I’ll need to investigate that more.

  19. BTW, if you ever want a non VBS way to restart and stop, I use this batch file to start/restart (I have to rely on RunHiddenConsole utility that you can find in various places so php-cgi.exe window doesn’t stay open):

    TASKKILL /f /IM nginx.exe

    TASKKILL /f /IM php-cgi.exe

    C:\Users\___USER_NAME___\Devel\mysql\bin\mysqladmin -u root shutdown

    choice /n /c y /t 3 /d y > nul

    PUSHD C:\Users\___USER_NAME___\Devel\nginx\

    SET PHP_FCGI_MAX_REQUESTS=0

    START nginx.exe

    RunHiddenConsole C:\Users\___USER_NAME___\Devel\nginx\php5\php-cgi.exe -b 127.0.0.1:9000 -c C:\Users\___USER_NAME___\Devel\nginx\php5\php.ini

    START C:\Users\___USER_NAME___\Devel\mysql\bin\mysqld

    choice /n /c y /t 5 /d y > nul

    POPD

  20. I have installed and run nginx + php + MySQL on my Windows 8 . But it stops responding after couple of minutes . I need it to stop and start to get the it working what to do ? ..
    System : Windows 8 build 9000 , nginx/1.2.6 , php 5.4.9 , MySQL Server 5.5 . intel dual core @ 1.76 , 1.5gb ram , X86

    • Hi Siddhu, sorry for the late reply. I was taking a break from the blog.

      Without knowing more about which versions you’ve installed, it’s hard to say. Then again, it could also be something internal to Windows 8 that’s causing it as well. I don’t have access to a Win8 machine at the moment, so I have no way to test it out.

      I can try at work when I go back, but it will be after the holidays, I’m afraid. Meanwhile, try and see if the PHP or nginx documentation has anything regarding the new OS.

  21. if you replace “cmd /K” for “cmd /C” the problem with the process ends, right? Is there any problem with this solution?

  22. I have set this up with nginx on port 81.
    I set php as an index file extension.
    I went to localhost:81
    403 FORBIDDEN appears
    I went to localhost:81/index.php
    The file downloads :(
    403 FORBIDDEN appears

    Help.

  23. Another good suggestion is to install nginx and fastcgi as services over windows. It’s possible trought WIndows Server Wrapper. The steps:

    First of all, downlod the lastest version of winsw here: http://goo.gl/HG6Z5 (just click the lastest version folder and download the “winsw-XXX-bin.exe” file.

    Creating the server wrapper for nginx:
    1. Put a copy of the downloaded exe into your nginx folder and rename it as your wish (I choose “nginx-server.exe”). Don’t run it.

    2. Create a xml file in the same folder with the same name (but with the xml extension). In my sample, it was “nginx-server.xml”.

    3. Save this code into the xml file if your nginx folder is “c:\nginx\” (I printed the screen, cuz I know how sux wordpress print codes in commentaries. The print screen is here: http://goo.gl/PJ79Z):

    nginxsrv
    nginx
    nginx web server
    c:\nginx\nginx.exe
    c:\nginx\logs\
    roll

    -p c:\nginx
    -p c:\nginx -s stop

    4. Now, open a CMD window, enter the nginx folder and run (without the quatation marks) “nginx-server install”.

    5. Now, to start nginx is installed as manual service, and you can start it with the command “net start nginxsrv”. And stop it with “net stop nginxsrv”.

    Now, creating the server wrapper for fastCGI. It’s pretty similar, with just a little trick to stop it. The steps:
    1. Put another copy of the downloaded “winsw-XXX-bin.exe” into your php folder and rename it as your wish (I choose “fcgi-server.exe”). Don’t run it.

    (THE TRICK)
    2. Create a new php file in the php folder and name it as your wish (I choose “fcgikill.php”), and save this code in it (again the print screen for the code: http://goo.gl/IFrkY):

    3. Now, create the xml file in the same folder with the same name. In this sample it was “fcgi-server.xml”.

    4. Create the folder “logs” into php folder, for the logs.

    5. Save this code into the xml file if your php folder is “c:\nginx\php\” (last print screen: http://goo.gl/rGzmK):

    fcgisrv
    FastCGI
    PHP FastCGI
    c:\nginx\php\php-cgi.exe
    c:\nginx\php\logs\
    roll

    -b 127.0.0.1:9000 -c c:\nginx\php\php.ini
    c:/nginx/php/fcgikill.php

    6. Now, open a CMD window, enter the php folder and run (without the quatation marks) “fcgi-server install”.

    7. Now the fastCGI is installed as manual service, and you can start it with the command “net start fcgisrv”. And stop it with “net stop fcgisrv”.

    NOTE:
    All nodes ID, NAME and DESCRIPTION in xml file can be what you wish, just remember that the service ID have to be exclusive.

    Sorry my awful english and thanks for the tutorial!
    Hope this helps.

    • The WordPress removed all tags from my sample codes. So, if you want to go it, just ignore all code typed, and copy them from the screenshots (the links are right before each respective code).

      Sorry the confusing.

      • My first comment doesn’t appear. I don’t know if you denied it or if something wrong happened with wordpress… anyway, you can delete my prior comment, otherwise I’ll look like crazy talking nonsenses. lol

      • Hi Messala

        Thanks for contributing to this! Sorry about the comment not appearing immediately; it showed up in the pending list for approval. That sometimes happens with links and code and stuff. It’s up and public now.

    • I forgot to say that the command to install the services wrapper, you have to open the CMD as administrator for Windows Vista, 7 and 8 with UAC activated (for Windows 8, even with UAC disabled).

      I said that the services would be installed as MANUAL service, but I was wrong. It’s installed as AUTOMATIC service, so they will be started automatic at Windows log on. To change to MANUAL, open RUN window (WIN key + R) and run “services.msc” (without quotation), find both nginxsrv and fgisrv (or the IDs you gave to them) services in the list, double click to open properties and change the combo box from “Automatic” to “Manual”. To start and stop them, you use the NET command normally.

      The WordPress cropped the samples of code much more than I expected, so I’ll try again with the generic tag:

      • XML to nginx service wrapper:

      <service>
      	<id>nginxsrv</id>
      	<name>nginx</name>
      	<description>nginx web server</description>
      	<executable>c:\nginx\nginx.exe</executable>
      	<logpath>c:\nginx\logs\</logpath>
      	<logmode>roll</logmode>
      	<depend></depend>
      	<startargument>-p c:\nginx</startargument>
      	<stopargument>-p c:\nginx -s stop</stopargument>
      </service>
      

      • PHP to stop FastCGI:

      <?PHP
      	shell_exec("taskkill /im php-cgi.exe");
      	sleep(5);
      	shell_exec("taskkil /f /im php-cgi.exe");
      	exit();
      ?>
      

      • XML to FastCGI service wrapper:

      <service>
      	<id>fastcgisrv</id>
      	<name>FastCGI</name>
      	<description>PHP FastCGI</description>
      	<executable>c:\nginx\php\php-cgi.exe</executable>
      	<logpath>c:\nginx\php\logs\</logpath>
      	<logmode>roll</logmode>
      	<depend></depend>
      	<startargument>-b 127.0.0.1:9000 -c c:\nginx\php\php.ini</startargument>
      	<stopargument>c:/nginx/php/killfastcgi.php</stopargument>
      </service>
      
  24. I intend to chime in on your VBS scripts towards the end, since you’re duplicating functionality and creating garbage cmd.exe’s in your processes which is completely unnecessary. I realize this is old news though, so pardon me if you’ve already corrected this elsewhere.

    The WScript.Shell object -is- “cmd” for all intents and purposes, so you’re running Shell (CMD) with Shell here basically;
    ‘ Navigate to the the nginx folder and shut it down
    sh.run “cmd /K CD C:\nginx\ & nginx -s quit”, 0
    This creates a hidden cmd.exe that is never shut down properly. You can just as easily write;
    sh.run “nginx.exe -s quit”, 0 (If you keep the script in the same folder, which you likely do)
    Which will create no garbage cmd.exe’s.

    I will paste my stop.vbs for reference;
    Dim sh
    Set sh = WScript.CreateObject(“WScript.Shell”)
    sh.run “nginx.exe -s quit”, 1
    sh.run “taskkill /f /IM php-cgi.exe”, 1

    (You also forgot to write a /c or /k before taskkill in your original script, which is why it didn’t work for Aaron.)

    • Hi Johannes, thanks for that.

      This code is very old and there are a lot of improvements that can be done to it (also the stack as well now that PHP, MySQL and of course Nginx all have new versions out). I plan to rewrite this when I have time with MariaDB instead of MySQL the next time and plan on moving on from the outdated startup/shutdown code.

      Future releases will probably use a HTMLapplication that will look nicer instead of just raw bat and vbs files.

  25. When someone writes an piece of writing he/she retains the plan of a user in his/her mind that
    how a user can be aware of it. Therefore that’s why this piece of writing is perfect. Thanks!

  26. Thought someone else might find this useful. Here’s a batch file I wrote for both starting and stopping the server. I didn’t like having two separate files.

    @ECHO OFF
    tasklist /FI "IMAGENAME eq nginx.exe" | find /I "nginx.exe" > NUL && (
    	GOTO STOP
    ) || (
    	GOTO START
    )
    
    :START
    ECHO Starting nginx
    start nginx
    start php\php-cgi.exe -b 127.0.0.1:9000 -c php.ini
    net start mysql
    GOTO DONE
    
    :STOP
    ECHO Stopping nginx
    start nginx -s quit
    taskkill /f /IM php-cgi.exe
    net stop mysql
    
    :DONE
    TIMEOUT 3
    
      • I’ve updated my script somewhat since I posted the above. I now use [RunHiddenConsole] (http://redmine.lighttpd.net/attachments/660/RunHiddenConsole.zip “RunHiddenConsole.zip”) to hide the annoying windows and [MinGW/msys](http://www.mingw.org/) for monitoring the NGinX error log, which is extremely useful in a development environment.

        Here’s the updated code if anyone wants it.

        @ECHO OFF
        CD C:\Tools\NGinX
        tasklist /FI "IMAGENAME eq nginx.exe" | find /I "nginx.exe" > NUL && (
            GOTO STOP
        ) || (
            GOTO START
        )
         
        :START
        ECHO Starting nginx
        start nginx
        C:\Tools\RunHiddenConsole\RunHiddenConsole C:\Tools\NGinX\php\php-cgi.exe -b 127.0.0.1:9000 -c C:\Tools\NGinX\php\php.ini
        net start mysql
        start C:\Tools\MinGW\msys\1.0\bin\sh.exe --login -i -c "tail -n 1 -f C:/Tools/NGinX/logs/error.log"
        GOTO DONE
         
        :STOP
        ECHO Stopping nginx
        start nginx -s quit
        taskkill /f /IM php-cgi.exe
        taskkill /IM sh.exe
        net stop mysql
         
        :DONE
        timeout 3
        
  27. So i was following your tutorial i’ve triple checked everything and for some reason nginx isn’t using php anytime i go to my site i get No input file specified. os i’m using is windows 2008

    • This usually means a FastCGI error. Make sure that the PHP process has actually started. Sometimes, there’s a delay between starting Nginx and FastCGI so in your processes (Ctrl + Alt + Del) check that Nginx and PHP are both there.

      Edit: Actually that’s a fairly common error. I found this page very helpful.

  28. Pingback: How to add MySQL to my nginx, which is running on windows 7?CopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery, copyquery.com, android doubt, ios question, sql query, sqlite query, nodejsquery,

    • I built this as a way to learn how to setup the components and how they relate to each other. But if you need, something turn-key, then by all means, that may work too.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s