Deploying Java EE apps to Azure: Part 1

Abhishek Gupta
Nov 21, 2019 · 8 min read

There are a multitude of options for cloud based application development ranging from traditional IaaS (Infrastructure-as-a-Service), PaaS (Platform-as-a-Service) and CaaS (Containers-as-a-Service) all the way to Kubernetes and Serverless (and probably some more which I might be missing!). Think of it as a spectrum rather than a “one size fits all model”, with each option having its pros and cons. Ultimately, every scenario is unique and the final choice is driven by requirements — but its always good to know that you have “choices” at your disposal!

This is the first of a series of blogs that will walk you through one of the options of running Java EE applications on Azure. We will follow the most basic approach for deploying our Java EE app to an application server which is set up in a Virtual Machine on Microsoft Azure along with the Azure Database for PostgreSQL service as the backend database. In essence, this is the combination of IaaS (Azure VM) along with a PaaS (managed PostgreSQL on Azure)

Other options such as containers and Kubernetes will be covered in upcoming posts

The example used in the blog post is a simple three-tier application that uses Java EE 8 specifications such as JAX-RS, EJB, CDI, JPA, JSF, Bean Validation. We will use the Payara Server to deploy the application and use PostgreSQL as the relational database.

During the course of the tutorial, we will cover:

  • Postgres and Virtual machine setup on Azure
  • Setup Payara server on the Virtual machine
  • Configure and install the Java EE application
  • Explore its functionality

Except for minor changes, the application used in this tutorial has been adapted from this project by Reza Rahman


If you don’t have a Microsoft Azure account, go ahead and sign up for a free one! The Azure CLI is a cross-platform command-line experience for managing Azure resources — please install it using these instructions.

First things first…

To set your Azure subscription ID

export AZURE_SUBSCRIPTION_ID=[to be filled]az account set --subscription $AZURE_SUBSCRIPTION_ID

Create a resource group that will contain all the services (resources) which you will create as a part of this tutorial. A resource group is like a logical container that holds related resources for an Azure solution. The resource group includes those resources that you want to manage as a group.

To create a resource group

export AZURE_RESOURCE_GROUP_NAME=[to be filled]
export AZURE_LOCATION=[to be filled]
az group create --name $AZURE_RESOURCE_GROUP_NAME --location $AZURE_LOCATION

Install PostgreSQL on Azure

We will be using the single server option for the purposes of this tutorial

We will use the az postgres server createcommand to create a Postgres server instance on Azure. First, set up some of the server properties such as the name, admin user, etc.

export AZURE_POSTGRES_SERVER_NAME=[to be filled]
export AZURE_POSTGRES_ADMIN_USER=[to be filled]
export SKU=B_Gen5_1
export STORAGE=5120

For storage and SKU options, please refer to the documentation

And, then invoke the command to initiate the database instance creation:

az postgres server create --resource-group $AZURE_RESOURCE_GROUP_NAME --name $AZURE_POSTGRES_SERVER_NAME  --location $AZURE_LOCATION --admin-user $AZURE_POSTGRES_ADMIN_USER --admin-password $AZURE_POSTGRES_ADMIN_PASSWORD --storage-size $STORAGE --sku-name $SKU

The provisioning process will take a few minutes.

To check the details of the Postgres database instance you just provisioned, invoke az postgres server show command

az postgres server show --resource-group $AZURE_RESOURCE_GROUP_NAME --name $AZURE_POSTGRES_SERVER_NAME

You should get a JSON response. Please note down the value for the fullyQualifiedDomainName attribute as you will be using this to connect to the Postgres instance later.

It should be of the format: [AZURE_POSTGRES_DB_NAME]

Install Virtual Machine on Azure

Let’s start by setting up the required information for the VM

export AZURE_VM_NAME=[to be filled]
export AZURE_VM_USER=[to be filled]
export AZURE_VM_PASSWORD=[to be filled]
export VM_IMAGE=UbuntuLTS

We will use the az vm create command to create the VM instance

az vm create --resource-group $AZURE_RESOURCE_GROUP_NAME --name $AZURE_VM_NAME --image $VM_IMAGE --admin-username $AZURE_VM_USER --admin-password $AZURE_VM_PASSWORD

The VM provisioning will take a few minutes.

You need to get the public IP address of the VM. Do so using the az vm list-ip-addresses command

az vm list-ip-addresses --resource-group $AZURE_RESOURCE_GROUP_NAME --name $AZURE_VM_NAME

You will see a JSON response — take a look at the publicIpAddresses section and note down the value of theipAddress property. Configure it as an environment variable as you will be using it in the subsequent steps

export VM_IP=[to be filled]

Allow VM to access the Postgres database

export FIREWALL_RULE_NAME=AllowJavaEECafeAppOnVMaz postgres server firewall-rule create --resource-group $AZURE_RESOURCE_GROUP_NAME --server $AZURE_POSTGRES_SERVER_NAME --name $FIREWALL_RULE_NAME --start-ip-address $VM_IP --end-ip-address $VM_IP

Install Payara server on the Virtual Machine

Check out the project on GitHub or dive into its documentation to learn more!

SSH into the Linux VM you just provisioned using the username and VM IP


Enter the password once prompted. Once you’re logged into the Virtual Machine, proceed with the next steps.

Install required toolset

sudo apt-get update
sudo apt install openjdk-8-jdk
sudo apt install maven

Setup Payara server

export PAYARA_VERSION=5.193.1wget$PAYARA_VERSION/payara-$PAYARA_VERSION.zipsudo apt install unzip
unzip payara-$

To confirm, run ls ~/payara5/

Start the server using asadmin

~/payara5/bin/asadmin start-domain

It will take a few moments for the server to boot up. You should see the following logs:

Waiting for domain1 to start ..................
Successfully started the domain : domain1
domain Location: /home/abhishgu/payara5/glassfish/domains/domain1
Log File: /home/abhishgu/payara5/glassfish/domains/domain1/logs/server.log
Admin Port: 4848
Command start-domain executed successfully.

Setup and deploy the application

Start by cloning the Git repository

git clone APP_FOLDER_NAME=javaee-on-azure-iaas

The web.xml file (under javaee-on-azure-iaas/src/main/webapp/WEB-INF) needs to be updated with the JDBC URL for the Postgres database on Azure. This is present in the <url> attribute of the <data-source section and its format is as follows:


Here is the list of placeholders which form a part of the JDBC URL:

  • POSTGRES_FQDN with value of fullyQualifiedDomainName for Postgres instance
  • AZURE_POSTGRES_ADMIN_USER with admin user name used to provision PG
  • AZURE_POSTGRES_SERVER_NAME with server name used to provision PG
  • AZURE_POSTGRES_ADMIN_PASSWORD with admin password used to provision PG

Set the required values

export POSTGRES_FQDN=[to be filled]
export AZURE_POSTGRES_ADMIN_USER=[to be filled]
export AZURE_POSTGRES_SERVER_NAME=[to be filled]

Simply use these commands to replace


Here is an e.g. of what the <data-source> section will look like:


The application is now configured. Let’s build it!

mvn clean install -f $APP_FOLDER_NAME/pom.xml

You should have the WAR file available. To confirm

ls -lrt $APP_FOLDER_NAME/target | grep javaee-cafe.war

As a final step in the application setup process, let’s download the JDBC driver for Postgres and add it to Payara server

We are using driver version 42.2.8

export PG_DRIVER_JAR=postgresql-42.2.8.jarwget$PG_DRIVER_JAR

Add the JAR to Payara, simply invoke asadmin add-library

~/payara5/glassfish/bin/asadmin add-library $PG_DRIVER_JAR

Finally, to deploy the WAR file, just copy it to the domain autodeploy folder

cp $APP_FOLDER_NAME/target/javaee-cafe.war ~/payara5/glassfish/domains/domain1/autodeploy

The deployment will take some time. In the meanwhile, you can track the logs using:

tail -f ~/payara5/glassfish/domains/domain1/logs/server.log

You should see log messages indicating successful deployment of the javaee-cafe application

[2019-11-18T13:34:21.317+0000] [Payara 5.193] [INFO] [NCLS-DEPLOYMENT-02035] [] [tid: _ThreadID=104 _ThreadName=payara-executor-service-scheduled-task] [timeMillis: 1574084061317] [levelValue: 800] [[
[AutoDeploy] Successfully autodeployed : /home/abhishgu/payara5/glassfish/domains/domain1/autodeploy/javaee-cafe.war.]]

Explore the application

We need to create a firewall rule using the az vm open-port to access it from our local machine. We just need to expose port 8080 since that's the default HTTP port which Payara server uses

az vm open-port --port 8080 --resource-group $AZURE_RESOURCE_GROUP_NAME --name $AZURE_VM_NAME

Access the JSF front end

Use the REST API

export VM_IP=[to be filled]

Create coffees

curl -X POST $VM_IP:8080/javaee-cafe/rest/coffees -d '{"name":"cappuccino","price":"10"}' -H "Content-Type: application/json"
curl -X POST $VM_IP:8080/javaee-cafe/rest/coffees -d '{"name":"caffe-latte","price":"15"}' -H "Content-Type: application/json"

Get all coffees

curl -H "Accept: application/json" $VM_IP:8080/javaee-cafe/rest/coffees

You should see a JSON response listing both the coffee options you just added

Get a coffee by ID

curl -H "Accept: application/json" $VM_IP:8080/javaee-cafe/rest/coffees/1

Delete a coffee by ID

curl -X DELETE $VM_IP:8080/javaee-cafe/rest/coffees/1
curl -H "Accept: application/json" $VM_IP:8080/javaee-cafe/rest/coffees

Notice that cappuccino is now deleted

Clean up resources

Please be aware that this will delete all the resources in the group which includes the ones you created as part of the tutorial (VM, Postgres etc.) as well as any other service instances you might have if you used an already existing resource group

az group delete --name $AZURE_RESOURCE_GROUP_NAME


As mentioned earlier, each option comes with its own pros and cons. In this case, you have complete control over your application, its deployment infrastructure, the way you scale it, etc. On the other hand, remember that managing the infrastructure, sizing it for your application, securing it, etc. is a set of responsibilities that you have to take on along with delivering core business value as a part of the app functionality.

The next part will dive into how to use a Docker container platform to deploy your Java EE applications. Stay tuned!

Microsoft Azure

Any language.

Microsoft Azure

Any language. Any platform. Our team is focused on making the world more amazing for developers and IT operations communities with the best that Microsoft Azure can provide. If you want to contribute in this journey with us, contact us at

Abhishek Gupta

Written by

Azure Cosmos DB at Microsoft | I like Databases, Go, Kubernetes

Microsoft Azure

Any language. Any platform. Our team is focused on making the world more amazing for developers and IT operations communities with the best that Microsoft Azure can provide. If you want to contribute in this journey with us, contact us at