Deploy PostgreSQL using Infrastructure-As-Code(Azure Bicep)

10 mins read

Deploy an Ubuntu virtual machine with PostgreSQL using Azure Bicep

Deploy PostgreSQL using Infrastructure-As-Code(Azure Bicep)

This article will show how you can deploy an Ubuntu virtual machine with PostgreSQL using Azure Bicep, a Domain Specific Language (DSL) for deploying Azure resources declaratively.

We will leverage the Azure Linux CustomScript extension to install the PostgreSQL server in the Ubuntu virtual machine.


An Active Azure account: You can create an account for free.Azure Bicep installed in your local machine.Azure PowerShell. See: Install Azure PowerShell.A resource group in your Azure subscription

Let’s get started!

Solution Overview

We will author a Bicep template that creates an Ubuntu VM and use the Azure Linux CustomScript extension to install the PostgreSQL server, version:9.3.5.

The installation includes:

port: 1999,data directory: m/opt/pgsql_data,installation directory: /opt/pgsql,user: postgres

The solution will include the following files:

📄 main.bicep: This is the Bicep template📄 azuredeploy.parameters.json: This parameter file contains the values to use for deploying your Bicep template.📁artifacts: This folder will contain a script named ‘’.

This template also provisions a storage account, virtual network, a public IP address, and a network interface required by the installation.

Resources deployed

1. Create SSH Key Pair

The first step is to create an SSH key pair; you can check the following article on how to create an SSH key pair for Linux VMs in Azure —

In this case, we will create an SSH key pair using the Azure Bash console. In the Azure Portal, request a new console as shown in the below image:

Cloud Shell — Azure Portal

Then we will generate an SSH Key using the command below:

-m PEM
-t rsa
-b 4096
-C “postgresql”
-f ~/.ssh/postgresql-key
-N yourpasshphrase

This will generate the Key under the SSH directory in your file share.

If you’re not familiar with the format of an SSH public key, you can display your public key with the following cat command, replace ‘~/.ssh/’ with the path and filename of your own public key file if needed:

cat ~/.ssh/

The above command will show the SSH public key in the console. We will need it during deployment time so have it at hand.

Cool! Now we have the SSH key pair. We will pass the value of this SSH Key in the parameters file.


The next step is to prepare the location of the artifacts (the ). You have two options: One option is to create a storage account in Azure and then create a container named ‘artifacts’. Then upload the following files in that container.

The second option is to store the artifacts( the script named ‘’) in a public repository. In this example, we will use this option.

Note: IF you prefer to use the first option, ensure you generate the correct Shared Access Tokens (SAS) so that the files/artifacts are accessible during deployment time. Pass on two parameter values: the SAS token and the location (URL to the artifact location).

2. Azure Bicep Template — parameters

Create a new file in your working directory and name it ‘main.bicep’. We will define the following parameters:

@description(‘User name for the Virtual Machine.’)
param adminUsername string@description(‘DNS Name for the publicly accessible node. Must be lowercase. It should match with the following regular expression: ^[a-z][a-z0-9-]{1,61}[a-z0-9]$ or it will raise an error.’)
param dnsNamePrefix string@description(‘The size of the virtual machines used when provisioning’)
param VmSize string = ‘Standard_B2s’@allowed([
@description(‘The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.’)
param ubuntuOSVersion string = ‘18.04-LTS’@description(‘Location for all resources.’)
param location string = resourceGroup().location@allowed([
@description(‘Type of authentication to use on the Virtual Machine. SSH key is recommended.’)
param authenticationType string = ‘sshPublicKey’@description(‘SSH Key or password for the Virtual Machine. SSH key is recommended.’)
param adminPasswordOrKey string// @description(‘The base URI where artifacts required by this template are located. When the template is deployed using the accompanying scripts, a private location in the subscription will be used and this value will be automatically generated.’)
// param artifactsLocation string = ‘’// @description(‘The sasToken required to access _artifactsLocation. When the template is deployed using the accompanying scripts, a sasToken will be automatically generated.’)
//param artifactsLocationSasToken string = ”

Note we are storing the script in a public repository to access it at deployment time. As a best practice, you can deploy a storage account and then store the script in the storage account and generate the SAS token to access the script at deployment time.

3. Azure Bicep Template — variables

We will define the following variables:

var imagePublisher = ‘Canonical’
var imageOffer = ‘UbuntuServer’
var nicName_var = ‘ubuntuVmNic’
var addressPrefix = ‘’
var subnetName = ‘Subnet’
var subnetPrefix = ‘’
var publicIPAddressName_var = ‘myPublicIP’
var publicIPAddressType = ‘Dynamic’
var vmName_var = ‘MyUbuntuVM’
var virtualNetworkName_var = ‘MyVNET’
var subnetRef = resourceId(‘Microsoft.Network/virtualNetworks/subnets’, virtualNetworkName_var, subnetName)
var linuxConfiguration = {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
path: ‘/home/${adminUsername}/.ssh/authorized_keys’
keyData: adminPasswordOrKey

4. Azure Bicep Template — resources

We will define the following resources:

resource pip ‘Microsoft.Network/publicIPAddresses@2021-02-01’ = {
name: publicIPAddressName_var
location: location
properties: {
publicIPAllocationMethod: publicIPAddressType
dnsSettings: {
domainNameLabel: dnsNamePrefix
}resource virtualNetworkName ‘Microsoft.Network/virtualNetworks@2020-07-01’ = {
name: virtualNetworkName_var
location: location
properties: {
addressSpace: {
addressPrefixes: [
subnets: [
name: subnetName
properties: {
addressPrefix: subnetPrefix
}resource nicName ‘Microsoft.Network/networkInterfaces@2020-07-01’ = {
name: nicName_var
location: location
properties: {
ipConfigurations: [
name: ‘ipconfig1’
properties: {
privateIPAllocationMethod: ‘Dynamic’
publicIPAddress: {
subnet: {
id: subnetRef
dependsOn: [
}resource vmName ‘Microsoft.Compute/virtualMachines@2020-12-01’ = {
name: vmName_var
location: location
properties: {
hardwareProfile: {
vmSize: VmSize
osProfile: {
computerName: vmName_var
adminUsername: adminUsername
adminPassword: adminPasswordOrKey
linuxConfiguration: ((authenticationType == ‘password’) ? json(‘null’) : linuxConfiguration)
storageProfile: {
imageReference: {
publisher: imagePublisher
offer: imageOffer
sku: ubuntuOSVersion
version: ‘latest’
osDisk: {
name: ‘${vmName_var}_OSDisk’
caching: ‘ReadWrite’
createOption: ‘FromImage’
networkProfile: {
networkInterfaces: [
}resource vmName_newuserscript ‘Microsoft.Compute/virtualMachines/extensions@2020-12-01’ = {
parent: vmName
name: ‘newuserscript’
location: location
properties: {
publisher: ‘Microsoft.Azure.Extensions’
type: ‘CustomScript’
typeHandlerVersion: ‘2.0’
autoUpgradeMinorVersion: true
settings: {
fileUris: [’
commandToExecute: ‘bash’

Note we use an Azure Linux CustomScript extension to deploy the PostgreSQL server.

5. Parameters file

Create a new file named ‘azuredeploy.parameters.json’. The code below shows the definition of the parameters file:

“$schema”: ““,
“contentVersion”: “”,
“parameters”: {
“adminUsername”: {
“value”: “GEN-UNIQUE”
“dnsNamePrefix”: {
“value”: “GEN-UNIQUE”
“adminPasswordOrKey”: {
“value”: “GEN-SSH-PUB-KEY”

6. Azure Bicep Template — Deployment

We will use the command below to deploy our Bicep template:

$date = Get-Date -Format “MM-dd-yyyy”
$deploymentName = “AzInsiderDeployment”+”$date”New-AzResourceGroupDeployment -Name $deploymentName -ResourceGroupName azinsider_demo -TemplateFile .main.bicep -TemplateParameterFile .azuredeploy.parameters.json -c

The image below shows the preview of the deployment:

Deployment preview using What-IF

Then we will execute the deployment. The image below shows the deployment output:

Deployment output — PostgreSQL using Azure Bicep

Now you can SSH into the virtual machine. You can use the same Azure Cloud Shell to SSH into the virtual machine.

SSH into Ubuntu VM on Azure using Azure Cloud Shell

Once you’re in the VM you can verify the deployment


You can find the code of this solution in the following URL, feel free to contribute!

azinsider/application-workloads/postgresql-on-ubuntu at main · daveRendon/azinsider

👉 Join the AzInsider email list here.

-Dave R.

💪Deploy PostgreSQL using Infrastructure-As-Code(Azure Bicep) was originally published in CodeX on Medium, where people are continuing the conversation by highlighting and responding to this story.

Leave a Reply

Your email address will not be published.

Follow Us