Customizing a Windows Azure PHP Worker Role
I was recently asked if it is possible to run PHP 5.4 in a Windows Azure Worker Role. (The default scaffold for a PHP worker role currently installs a version of PHP 5.3.) This got me to wondering how you might use any custom PHP installation in a worker role. The short answer is, yes, you can use ay custom PHP installation in a worker role – in this post I’ll walk you through the steps for doing so. However, a disclaimer first: my investigations here raised a few questions I haven’t answered yet, so depending on what you want to do, this post may/or may not be helpful.
Note: The Windows Azure team is looking at ways to enhance the tooling so that you can choose a specific version of PHP and add/enable extensions all from the command line prior to deployment. This post is simply meant to show you what you need to do before that tooling becomes available. Of course, we’d like to hear feedback about what you would like to see in the tooling.
Anyway, here’s what I did to get my local installation of PHP 5.4 running in a worker role…
1. I used the Windows Azure Powershell cmdlets to create a new Windows Azure Service, add a PHP worker role, and enable remote desktop access:
2. I added my local PHP 5.4 installation to the WorkerRole1 directory. I also edited the php.ini file to make sure all paths referenced in the file were relative, not absolute (e.g. include_path=".\ext\" instead of "C:\php54\ext\").
Note: Here is where some questions arise. Some PHP extensions may require dependencies that aren’t installed by default. For example, the sqlsrv extension requires SQL Server Native Client. In this case, I could install the dependency using the Web Platform Installer, but other dependencies may require other methods.
3. I deleted all other files from the WorkerRole1 directory except for the setup_worker.cmd file. This script is called when the role is started, and I changed it so that it will add my PHP installation to the Path environment variable.
@echo off echo Granting permissions for Network Service to the deployment directory... icacls . /grant "Users":(OI)(CI)F if %ERRORLEVEL% neq 0 goto error echo OK echo SUCCESS setx Path "%PATH%;%~dp0php54" /M exit /b 0 :error echo FAILED exit /b -1
4. I added two files to the WorkerRole1 folder: php_entry.cmd and entry.php. The first file (php_entry.cmd) will be the program entry point for the role (I’ll configure this in a later step). The only thing that this file does is call the entry.php script. It’s contents are simply this:
php entry.php
The entry.php script is just an example of some long-running script that might actually do something interesting in a “real” scenario. In my case this is just a proof of concept, so I just open and write to a file once every minute:
<?php $h = fopen("output.txt", "a+"); while(true){ fwrite($h, "Hello world!"); sleep(60); } ?>
My WorkerRole1 directory now looks like this:
5. Finally, publish the project with the Powershell cmdlets: Publish-AzureServiceProject
It will take a few minutes to publish the project, but when it is ready, you should be able to login to it via remote desktop…
…and find your way to the approot directory to see that your long-running php script is writing to the file as expected. (Of course, your project will do something interesting.)
One last thing to consider: By default, port 80 is open on a PHP Worker Role. Here’s the entry in the ServiceDefinition.csdef file:
<Endpoints> <InputEndpoint name="HttpIn" protocol="tcp" port="80" /> </Endpoints>
Depending on what your worker role does, you may want to close this endpoint. To allow other Azure services to communicate with your worker role, you may want to open other endpoints. For more information, see How to: Enable Role Communication.
The approach to using a custom PHP installation for a web role is similar to that for a worker role. The steps are basically…
1. Use the Powershell tools to create a new project and PHP Web Role.
2. Add your PHP installation to the WebRole/bin directory.
3. Modify the startup script (setup_web.cmd) to configure IIS (this configures IIS to run PHP from my php54 directory):
SET PHP_FULL_PATH=%~dp0php54\php-cgi.exe SET NEW_PATH=%PATH%;%RoleRoot%\base\x86 %WINDIR%\system32\inetsrv\appcmd.exe set config -section:system.webServer/fastCgi /+"[fullPath='%PHP_FULL_PATH%',maxInstances='12',idleTimeout='60000',activityTimeout='3600',requestTimeout='60000',instanceMaxRequests='10000',protocol='NamedPipe',flushNamedPipe='False']" /commit:apphost %WINDIR%\system32\inetsrv\appcmd.exe set config -section:system.webServer/fastCgi /+"[fullPath='%PHP_FULL_PATH%'].environmentVariables.[name='PATH',value='%NEW_PATH%']" /commit:apphost %WINDIR%\system32\inetsrv\appcmd.exe set config -section:system.webServer/fastCgi /+"[fullPath='%PHP_FULL_PATH%'].environmentVariables.[name='PHP_FCGI_MAX_REQUESTS',value='10000']" /commit:apphost %WINDIR%\system32\inetsrv\appcmd.exe set config -section:system.webServer/handlers /+"[name='PHP',path='*.php',verb='GET,HEAD,POST',modules='FastCgiModule',scriptProcessor='%PHP_FULL_PATH%',resourceType='Either',requireAccess='Script']" /commit:apphost %WINDIR%\system32\inetsrv\appcmd.exe set config -section:system.webServer/fastCgi /"[fullPath='%PHP_FULL_PATH%'].queueLength:50000"
In this case, you will likely want to leave port 80 open.
That’s it. As usual, feedback in the comments is appreciated.
Thanks.
-Brian
Comments
Anonymous
August 21, 2012
Thanks, Brian. Really helped me out with understanding the role configuration and startup tasks, and what or rather, what aren't needed to get a worker role up and running. Cheers, David SmithAnonymous
October 06, 2014
I logged in using both the options Azure AD & Publish profile, login is successful but getting below error with cmdlet such as Get-AzureWebsite & Publish-AzureServiceProject. Any clue what is wrong? error: Get-AzureWebsite : Value cannot be null. Parameter name: subscriptionId I created a PHP workerrole following steps listed in your articleAnonymous
October 14, 2014
Hi Raghu, it sounds like maybe your login for your Azure subscription has timed out, or a default subscription hasn't been set. Something along those lines. Try using 'get-azuresubscrition' and see if it returns information about your subscription. If you get an error, or it doesn't return any information, try following the steps in azure.microsoft.com/.../install-configure-powershell to authenticate to the subscription. Alternatively, if this is an older install of the PowerShell bits for Azure, you might try downloading a newer version. There's a link in that article. Thanks, Larry