Deploying Your Play! Framework App to Azure as a PaaS


We wanted to deploy a Play! framework application to the cloud but we didn’t want to take care of all security updates on a virtual machine. Heroku is very expensive and Amazon has had no suitable solutions for our needs. We decided to go with Windows Azure.

The previous process (& its problems)

Without automation our process was:

With this concept, automation was really hard, but this was a stable starting ground.



First of all, I took the core part of the WindowsAzureToolkitForEclipseWithJava and edited it to look like as if it was generated by the Azure Tool itself.

The .startup.cmd describes how the environment should be set up to start your cloud service. We need to modify the .startup.cmd executable according to the code below. As you can see I use ZuluJDK because it has all the capabilities to run this Play! framework application.

rd "\%ROLENAME%"
if defined DEPLOYROOT (
    mklink /J "\%ROLENAME%" "%DEPLOYROOT%"
) else (
    mklink /J "\%ROLENAME%" "%ROLEROOT%\approot"
set JAVA_HOME=%DEPLOYROOT%\zulu1.7.0_85-
:: zulu jdk deploy start
cmd /c util\wash.cmd blob download "" "" eclipsedeploy <storageName> "<storageAccesKey>" ""
if not exist "" (
    cmd /c util\wash.cmd file download "" ""
    if not exist "" exit 0
    cmd /c util\wash.cmd blob upload "" "" eclipsedeploy <storageName> "<storageAccesKey>" ""
) else (
if not exist "" exit 0
cscript /NoLogo util\unzip.vbs "" "%DEPLOYROOT%"
del /Q /F ""
:: zulu jdk deploy end
:: Starting the application
start "Azure" /D"<appName-version>\bin" ;<appName>.bat
if %ERRLEV%==0 (echo Startup completed successfully.) else (echo *** Azure startup failed [%ERRLEV%]- exiting...)
timeout 5
exit %ERRLEV%

The next file we need to edit is the definitionFile. You can define your vm size, the name of your project and most importantly, the Endpoint. (The latter should look similar to the code below.) The name property doesn’t count but the localPort should be set to 9000 or whatever your application listens to. The port property needs to be set to 80, because it redirects your request to your application listening to port 9000.


<?xml version="1.0" encoding="utf-8" standalone="no"?>
<ServiceDefinition xmlns="" name="AzureDeploymentProject">
  <WorkerRole name="WorkerRole1" vmsize="Medium">
      <!-- Sample startup task calling startup.cmd from the role's approot folder -->
      <Task commandLine="util/.start.cmd .startup.cmd" executionContext="elevated" taskType="simple"/>
    <Runtime executionContext="elevated">
            <!-- Sample entry point calling run.cmd from the role's approot folder -->
            <ProgramEntryPoint commandLine="run.cmd" setReadyOnProcessStart="true"/>
        <InputEndpoint localPort="9000" name="play" port="80" protocol="tcp"/>

As mentioned in the article above, you have to modify a few things in .bat. I think it is easier to set the JAVAOK flag to true instead of setting the JAVAINSTALLED flag to 1. Of course, there is still a problem with the argument list being too long, so you shouldn’t forget about shortening the APP_CLASSPATH variable either. Those two operations can be easily replaced with one single command line script.


AUthor: Barnabás Oláh, 2015.11.27
Replace-In-File $File "JAVAOK=false" "JAVAOK=true"
Replace-In-File $File "set "APP_CLASSPATH=%APP_LIB_DIR%\\.*" "set "APP_CLASSPATH=%APP_LIB_DIR%\*`""
catch [System.Exception] {
    Write-Host $_.Exception.ToString()
    exit 1

Download this script!

If you are new to powershell you can use this:

.\Fix-PlayDistBat.ps1 -File "path\to\file"

After you are done with all the modifications, you need to create the WorkerRole package. On our deployment server this cspack is added to the Enviroment Variables.

cspack ServiceDefinition.csdef \out:ServicePackage.cspkg

Now you have everything ready to deploy your packed application to Azure. Just a quick overview of what’s going on during the deployment process:

  1. You will be “signed in” with the help of your PublishSettings file and the Name of your Subscription; this will identify you.
  2. Your package will be uploaded to your storage. This is kinda necessary. I wasn’t able to deploy from my local machine, because the connection timed out – deployment failed.
  3. Checking if the given slot of your CloudService is free. If the slot is free, a new deployment will be created. It will publish your package from your storage account to the given slot of the CloudeService (with the Configuration you described in you ServiceConfiguration file (*.cscfg).). If the slot is ‘taken’ there it will be replaced by your package.
  4. Checking if the deployment was successful.


.PARAMETER PublishSettings
.PARAMETER StorageAccount
.PARAMETER Subscription
.PARAMETER CloudService
.PARAMETER ContainerName
.PARAMETER ServiceConfig
.PARAMETER ServicePackage
.PARAMETER Production
AUthor: Barnabás Oláh, 2015.11.27
Function Set-Slot($IsProduction){
    if($IsProduction) {
    } else {
Function Set-AzureSettings($PublishSettings, $Subscription, $StorageAccount){
    Import-AzurePublishSettingsFile $PublishSettings
    Set-AzureSubscription -SubscriptionName $Subscription -CurrentStorageAccount $StorageAccount
    Select-AzureSubscription $Subscription
Function Upload-Package($ServicePackage, $ContainerName){
    $blob = "$CloudService.package.$(get-date -f yyyy_MM_dd_hh_ss).cspkg"
    $containerState = Get-AzureStorageContainer -Name $ContainerName -ErrorAction silentlycontinue
    if ($containerState -eq $null)
        New-AzureStorageContainer -Name $ContainerName > $null
    Set-AzureStorageBlobContent -File $ServicePackage -Container $ContainerName -Blob $blob -Force > $null
    $blobState = Get-AzureStorageBlob -blob $blob -Container $ContainerName
Function Create-Deployment($ServicePackageUrl, $CloudService, $slot, $ServiceConfig){
    $opstat = New-AzureDeployment -Slot $slot -Package $ServicePackageUrl -Configuration $ServiceConfig -ServiceName $CloudService
Function Upgrade-Deployment($ServicePackageUrl, $CloudService, $slot, $ServiceConfig){
    $setdeployment = Set-AzureDeployment -Upgrade -Slot $slot -Package $ServicePackageUrl -Configuration $ServiceConfig -ServiceName $CloudService -Force
Function Check-Deployment($CloudService, $slot){
    $completeDeployment = Get-AzureDeployment -ServiceName $CloudService -Slot $slot
    Set-AzureSettings -publishsettings $PublishSettings -subscription $Subscription -storageaccount $StorageAccount
    $ServicePackageUrl = Upload-Package -ServicePackage $ServicePackage -ContainerName $ContainerName
    $slot = Set-Slot($Production)
    $deployment = Get-AzureDeployment -ServiceName $CloudService -Slot $slot -ErrorAction silentlycontinue
    if ($deployment.Name -eq $null) {
        Create-Deployment -ServicePackageUrl $ServicePackageUrl -CloudService $CloudService -slot $slot -ServiceConfig $ServiceConfig
    } else {
        Upgrade-Deployment -ServicePackageUrl $ServicePackageUrl -CloudService $CloudService -slot $slot -ServiceConfig $ServiceConfig
    $deploymentid = Check-Deployment -CloudService $CloudService -slot $slot
    exit 0
catch [System.Exception] {
    Write-Host $_.Exception.ToString()
    exit 1

Download this script!

Using it is pretty easy: you will need

.\Deploy-Azure.ps1 -PublishSettings path\to\ServicePublishSettings.publishsettings -StorageAccount "$storageAccount" -ContainerName "$containerName" [-Production] 
-Subscription "$subscriptionName" -CloudService "$CloudServiceName"
-Serviceconfig path\to\ServiceConfiguration.cscfg -ServicePackage path\to\ServicePackage.cspkg


According to this description you can create a Jenkins job which helps your productivity even more. If you have any questions, don’t be afraid to ask. I’m not an expert but spent a few hours finding a solution to our deployment problem – maybe I can help you even more.

I’m not really satisfied with the concept of deploying your Play! framework application like it’s described above. The solution Heroku provides is quite smooth, but Heroku is more expensive compared to Microsoft Azure, hopefully Microsoft will provide better support for deploying Play! framework Apps to Azure. Cheers!

member photo

Never underestimate the capabilities of a lazy person.

Latest post by Barnabás Oláh

Deploying Your Play! Framework App to Azure as a PaaS