Packaging a Custom PHP Installation for Windows Azure
One feature of the scaffolds that are in the Windows Azure SDK for PHP is that all rely on the Web Platform Installer to install PHP when a project is deployed. This is great until I want my application deployed with my locally customized installation of PHP. Not only might I have custom settings, but I might have custom libraries that I want to include (like some PEAR modules or any of the many PHP frameworks out there). In this tutorial, I’ll walk you through the steps for deploying a PHP application bundled with a custom installation of PHP. This tutorial does not rely on the Windows Azure SDK for PHP, but you will need…
- The Windows Azure SDK.
- Windows Azure subscription You really only need this if you want to actually deploy your application (step 8 below).
- PHP installed on your local machine and IIS configured to handle PHP requests. I recommend doing this with the Web Platform Installer.
Ultimately, I’d like to make this process (below) easier (by possibly turning this into a scaffold to be included in the Windows Azure SDK for PHP?), so please provide feedback if you try this out…
1. Customize your PHP installation. Configure any settings and external libraries you want for your application.
Edit: As pointed out in the comments, if all you want/need to do is customize PHP settings or include some extensions, you can do this using the default scaffolder. Just open the /php/php.ini file that is created by the default scaffolder, add any extensions or directives you want for your PHP version, and deploy your application. The additions to the php.ini file will be appended to the php.ini file that is used for your PHP installation running in Azure. However, if your customizations are more extensive than this, read on...
2. Create a project directory. You’ll need to create a project directory for your application and the necessary Azure configuration files. Ultimately, your project directory should look something like this (we’ll fill in some of the missing files in the steps that follow):
-YourProjectDirectory
-YourApplicationRootDirectory
-bin
-configureIIS.cmd
-PHP
-(application files)
-(any external libraries)
-web.config
-ServiceDefinition.csdef
A few things to note about the structure above:
- You need to copy your custom PHP installation to the bin directory.
- Make sure that all paths in your php.ini are relative (e.g. extension_dir=”.\ext”)
- Any external libraries need to be in your application root directory.
- Technically, this isn’t true. You could use a relative path for your include_path configuration setting (relative to your application root) and put this directory elsewhere in your project directory.
- Maybe this goes without saying, but be sure to turn off any debug settings (like display_errors) before pushing this to production in Azure.
3. Add a startup script for configuring IIS. IIS in a Web role is not configured to handle PHP requests by default. So, we need a script to run when an instance is brought on line to configure IIS. (We’ll set this script to run on start up in the next step.) Create a file called configureIIS.cmd, add the content below, and save it in the bin directory:
@ECHO ON SET PHP_FULL_PATH=%~dp0php\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"
4. Add a service definition file (ServiceDefinition.csdef). Every Azure application must have a service definition file. The important part of this one is that we set the script above to run on start up whenever an instance is provisioned:
<?xml version="1.0" encoding="utf-8"?> <ServiceDefinition name="YourProjectDirectory" xmlns="https://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"> <WebRole name="YourApplicationRootDirectory" vmsize="ExtraSmall" enableNativeCodeExecution="true"> <Sites> <Site name="YourPHPSite" physicalDirectory="./YourApplicationRootDirectory"> <Bindings> <Binding name="HttpEndpoint1" endpointName="defaultHttpEndpoint" /> </Bindings> </Site> </Sites> <Startup> <Task commandLine="configureIIS.cmd" executionContext="elevated" taskType="simple" /> </Startup> <InputEndpoints> <InputEndpoint name="defaultHttpEndpoint" protocol="http" port="80" /> </InputEndpoints> </WebRole> </ServiceDefinition>
Note that you will need to change the names of YourProjectDirectory and YourApplicationRootDirectory depending on what names you used in your project structure from step 1. You can also configure the VM size (which is set to ExtraSmall in the file above). For more information, see Windows Azure Service Definition Schema.
5. Generate a service configuration file (ServiceConfiguration.cscfg). Every Azure application must also have a service configuration file, which you can generate using the Windows Azure SDK. Open a Windows Azure SDK command prompt, navigate to your project directory, and execute this command:
cspack ServiceDefinition.csdef /generateConfigurationFile:ServiceConfiguration.cscfg /copyOnly
This will generate a ServiceConfiguration.cscfg file and a ServiceDefinition.csx directory in your project directory.
6. Run your application in the Compute Emulator. If you want to run your application in the Compute Emulator (for testing purposes), execute this command:
csrun ServiceDefinition.csx ServiceConfiguration.cscfg /launchbrowser
One thing to note about doing this: The configureIIS.cmd script will be executed on your local machine (setting your PHP handler to point to the PHP installation that is part of your Azure project). You’ll need to change this later.
7. Create a package for deployment to Azure. Now you can create the package file (.cspkg) that you need to upload to Windows Azure with this command:
cspack ServiceDefinition.csx ServiceConfiguration.cscfg
8. Deploy your application. Finally, you can deploy your application. This tutorial will walk you through the steps: https://azurephp.interoperabilitybridges.com/articles/deploying-your-first-php-application-to-windows-azure#new_deploy.
Again, I’d be very interested to hear feedback from anyone who tries this. Like I mentioned earlier, I think turning this into a scaffold that is included in the Windows Azure SDK for PHP might be very useful.
Thanks.
-Brian
Comments
Anonymous
November 23, 2011
If the only purpose is to add specific extensions and/or change php.ini directives, the DefaultScaffolder provides support for that. In the /php folder of the web role, there's a php.ini file which will be appended to the original php.ini file on the Windows Azure machine. In the ext folder, you can add extensions that will automatically be registered in the Windows Azure machine. Great post though if you really want a completely custom installation! Keep up the good work!Anonymous
November 28, 2011
@Maarten- Thanks...I should have included that information in the post...I'll update it now. -BrianAnonymous
November 30, 2011
Hi Brian, This custom installation could come in pretty handy as in particularly I am interested to override the OnStart() method in the WebRole.cs to run my own cmd script once the webRole is up and running. . Therefore regarding Step 2) do you mean to create a project within Visual Studio and copy the extracted WordPress installation inside the -php folder accordingly? What type of project is meant to be created? Thanks HoumanAnonymous
November 30, 2011
@Houman- I didn't use VS when creating my project. I added my finished application code to the project structure shown in the blog. I think this should be possible to do with WordPress, but I haven't tried it. Speaking of WordPress, have you seen the scaffolds that are available? azurephp.interoperabilitybridges.com/.../how-to-deploy-wordpress-using-the-windows-azure-sdk-for-php-wordpress-scaffold azurephp.interoperabilitybridges.com/.../how-to-deploy-wordpress-multisite-to-windows-azure-using-the-wordpress-scaffold Using one of those might be a better option in your particular case. -BrianAnonymous
March 12, 2012
I followed these instruction but the server only returned a 500.0 internal error. I connected to the server using RDP and installed PHP using the Web Platform installer to sort the problem. Any ideas on what could be wrong with my package?Anonymous
March 15, 2012
@Stuart Turner- Sorry for the delayed response. Can you email me details? brian.swan at microsoft dot com. I'll have a look. Thanks. -Brian