# Set up high availability in Azure

> Configure high availability for Cloud Management Platform in Azure

---

Site [llms.txt](/llms.txt)

---

A high availability (HA) deployment of Cloud Management Platform (CMP) in Azure uses two or more VM nodes behind a Standard Azure Load Balancer, with a shared Azure Database for PostgreSQL flexible server and an Azure Files NFS share providing a common data layer across all nodes.

## Create virtual machines

<div class="alert alert-info" role="alert">


Deploy in the region closest to your physical infrastructure, or the region where the majority of your cloud infrastructure resides. Before creating virtual machines, ensure that Azure Database for PostgreSQL flexible server is available in your desired region.
</div>


Create the required number of Azure virtual machines, such as one primary and one secondary, with either an Oracle Enterprise Linux 8 or RHEL 8 image.

## Configure Cloud Management Platform

**Perform the following steps on all instances.**

### Deploy Cloud Management Platform

1. [Deploy using the installer](/docs/cmp/get-started/install/deploy-with-installer/).

### Initial platform setup

**Perform the following steps on all instances.**

1. Launch the CMP web interface.
1. Follow the steps in [Complete initial setup](/docs/cmp/get-started/complete-initial-setup/).

### Configure node connectivity

1. Remove any public IPs created during deployment.
1. Ensure you can connect to the instances, for example, using [Azure Bastion](https://learn.microsoft.com/en-us/azure/bastion/), [Azure Cloud Shell](https://learn.microsoft.com/en-gb/azure/cloud-shell/vnet/overview), or another VM.

### Upgrade the platform

<div class="alert alert-info" role="alert">


The upgrade can take up to ten minutes to complete.
</div>


1. Locate the **latest release's upgrader file** from the **[Support Portal](https://support.cloudbolt.io/cloudbolt/s/topic/0TO5c000001MolrGAC/releases)**.
1. SSH into the instance.
1. Run the following commands, replacing **latest-release-upgrader-url** with the URL of the upgrader file:

   ```bash
   sudo su -
   wget latest-release-upgrader-url
   tar -xvzf cloudbolt_upgrader_*.tgz
   cd cloudbolt_upgrader_*
   ./upgrade_cloudbolt.sh
   ```

### Prepare for database configuration

**Perform the following steps on the primary instance.**

The `/var/opt/cloudbolt/.postgresql_password` file contains `postgresql_root_pass` and `postgresql_pass`.

1. Open an SSH session.
1. Make a copy of the instance's database:

   ```bash
   source /var/opt/cloudbolt/.postgresql_password
   export PGPASSWORD=${postgresql_pass}
   pg_dump -h localhost -p 5432 -U cb_dba -w --clean -F t -f /tmp/cloudbolt.tar cloudbolt
   ```

1. Run the following command to update permissions on `secret-key-for-cloudbolt.bin`:

   ```bash
   chmod 777 /var/opt/cloudbolt/secrets/secret-key-for-cloudbolt.bin
   ```

## Create and configure a PostgreSQL database

### Create an Azure Database for PostgreSQL flexible server

1. In the Azure portal, go to **Azure Database for PostgreSQL flexible servers** and select **Create**.
1. Select a **Subscription** and **Resource Group**.
1. Provide a **Server name**.
1. Select the same **region** as your VMs.
1. Select **PostgreSQL version 18**.
1. For **Workload type**, select **Dev/Test or Production**.
1. Configure high availability if required.
1. Under **Authentication**, provide Administrator login: **cb_dba** and a **password**.
1. Select **Next : Networking >**.
1. Select **Private Access (VNet Integration)** under **Connectivity method**.
1. Under **Virtual network** select a **Virtual network** that has a subnet that is delegated for use for PostgreSQL Flexible Server, or create a new one.
1. Select **Review + Create**.
1. Select **Create**.

**After creating the database, select it and copy the Endpoint FQDN from the overview tab.**

### Configure the instances to use the database

**Perform the following steps on the primary instance.**

1. Create the CMP database in the PostgreSQL database, replacing **remote-db-dns-name**, **remote-db-user**, and **remote-db-pass**:

   ```bash
   export PGPASSWORD='<remote-db-pass>'
   psql --host=remote-db-dns-name --port=5432 --username=remote-db-user --dbname=postgres <<END_OF_SQL
   drop database if exists cloudbolt with (force);
   create database cloudbolt;
   grant all privileges on database cloudbolt to cb_dba;
   END_OF_SQL
   ```

1. Restore the database copy to the new PostgreSQL database, replacing **remote-db-dns-name**, **remote-db-user**, **remote-db-pass**, and **remote-db-port**:

   ```bash
   export PGPASSWORD='<remote-db-pass>'
   pg_restore -h remote-db-dns-name -U remote-db-user --no-owner --role=remote-db-user -w -p remote-db-port -e --clean --if-exists -d cloudbolt /tmp/cloudbolt.tar
   ```

1. Run the following commands to set permissions for **cb_dba**, replacing **remote-db-dns-name**, **remote-db-user**, and **remote-db-pass**:

   ```bash
   export PGPASSWORD='<remote-db-pass>'
   psql --host=remote-db-dns-name --port=5432 --username=remote-db-user --dbname=postgres <<END_OF_SQL
   alter role cb_dba in database cloudbolt set search_path to cloudbolt,public;
   grant all privileges on database cloudbolt to cb_dba;
   END_OF_SQL
   ```

1. Run the following commands to verify the database connection, ensuring they return values, replacing **remote-db-dns-name**, **remote-db-user**, **remote-db-pass**, and **remote-db-port**:

   ```bash
   psql postgresql://remote-db-user:remote-db-pass@remote-db-dns-name:remote-db-port/cloudbolt -c "\l" | grep -qw cloudbolt
   ```

1. Copy the `DATABASES` section from `/opt/cloudbolt/settings_local.py` to `/var/opt/cloudbolt/proserv/customer_settings.py`, updating the **password** and **hosts** fields.

**Perform the following steps on all instances.**

1. Run the following commands to **stop and disable PostgreSQL**:

   ```bash
   systemctl stop postgresql-18; systemctl disable postgresql-18
   ```

   The service is `postgresql-18` on nodes installed with CMP 2026.3.97 or later, and `postgresql-14` on older nodes.

## Create and configure an Azure Files NFS file share

### Register the NFS file share feature

If the **AllowNfsFileShares** feature is already registered, skip this step and continue to [Create a storage account and file share](#create-a-storage-account-and-file-share).

1. Register the AllowNfsFileShares feature in your Azure Subscription:

   ```bash
   az feature register --name AllowNfsFileShares --namespace Microsoft.Storage
   ```

1. Verify feature registration:

   ```bash
   az feature show --name AllowNfsFileShares --namespace Microsoft.Storage --query properties.state
   ```

### Create a storage account and file share


**Bash**

```bash
resourceGroup="<resource-group>"
storageAccountName="<orgname>cmpfiles"
location="<region>"

az storage account create \
    --resource-group $resourceGroup \
    --name $storageAccountName \
    --location $location \
    --sku Premium_LRS \
    --kind FileStorage

az storage share-rm create \
    --resource-group $resourceGroup \
    --storage-account $storageAccountName \
    --name nfscmpfiles \
    --enabled-protocol NFS \
    --root-squash NoRootSquash \
    --quota 100
```

**PowerShell**

```powershell
$resourceGroup = "<resource-group>"
$storageAccountName = "<orgname>cmpfiles"
$location = "<region>"

az storage account create `
    --resource-group $resourceGroup `
    --name $storageAccountName `
    --location $location `
    --sku Premium_LRS `
    --kind FileStorage

az storage share-rm create `
    --resource-group $resourceGroup `
    --storage-account $storageAccountName `
    --name nfscmpfiles `
    --enabled-protocol NFS `
    --root-squash NoRootSquash `
    --quota 100
```


### Configure the storage account

1. In the Azure portal, go to **Storage accounts** and select the new storage account.
1. Under **Properties**, select **Networking**.
1. Under **Public network access**, select **Manage**.
1. Next to **Public network access**, select **Enable**.
1. Next to **Public network access scope**, select **Enable from selected networks**.
1. Select the **virtual networks**, **IP addresses**, and **resource instances** that can access the account, and select **Save**.
1. Under **Settings**, select **Configuration**.
1. Set **Secure transfer required** to **Disabled**, and select **Save**.
1. Under **Data storage**, select **File shares**.
1. Select the file share.
1. Select **Connect**.
1. Select **Linux**.
1. Copy the **Mount point**.

### Configure NFS on the instances

1. SSH into **all instances**.
1. **On all instances**, run the following commands, using the mount path:

   ```bash
   sudo yum install nfs-utils
   mkdir /mnt/nfs
   sudo mount -t nfs -o vers=4,minorversion=1,sec=sys <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles /mnt/nfs
   ```

1. **On the primary instance only**, run the following commands:

   ```bash
   mv /var/opt/cloudbolt /mnt/nfs/cloudbolt
   mv /var/log/cloudbolt/jobs /mnt/nfs/jobs
   mv /var/www/html/cloudbolt/static /mnt/nfs/static
   ```

1. **On secondary instances only**, run the following commands:

   ```bash
   rm -rf /var/opt/cloudbolt
   rm -rf /var/log/cloudbolt/jobs
   rm -rf /var/www/html/cloudbolt/static
   ```

1. **On all instances**, run the following commands:

   ```bash
   mkdir /var/opt/cloudbolt
   mkdir /var/log/cloudbolt/jobs
   mkdir /var/www/html/cloudbolt/static
   sudo mount -t nfs -o vers=4,minorversion=1,sec=sys <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles/cloudbolt /var/opt/cloudbolt
   sudo mount -t nfs -o vers=4,minorversion=1,sec=sys <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles/jobs /var/log/cloudbolt/jobs
   sudo mount -t nfs -o vers=4,minorversion=1,sec=sys <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles/static /var/www/html/cloudbolt/static
   ```

1. **On all instances**, open the `/etc/fstab` file for editing, add the following lines (using the mount path), and save the file:

   ```bash
   <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles/cloudbolt /var/opt/cloudbolt nfs rw,hard,intr,rsize=8192,wsize=8192,timeo=14 0 0
   <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles/jobs /var/log/cloudbolt/jobs nfs rw,hard,intr,rsize=8192,wsize=8192,timeo=14 0 0
   <storageaccount>.file.core.windows.net:/<storageaccount>/nfscmpfiles/static /var/www/html/cloudbolt/static nfs rw,hard,intr,rsize=8192,wsize=8192,timeo=14 0 0
   ```

1. **On all instances**, run `mount -fav` to validate the update.

## Reboot instances

On all instances, run `sudo reboot` to reboot the instances.

## Post-reboot checks

After rebooting, verify that essential services are starting and healthy on each of your nodes.

### Apache HTTP server

1. Check the `httpd` status:

   ```bash
   systemctl status httpd
   ```

1. If `httpd` fails to start or is unhealthy, you may need to set `SELinux` to permissive mode, or create `SELinux` entries to grant `httpd` access to NFS share files.

   **Option 1: Run SELinux in permissive mode**

   1. Set `SELinux` to `permissive` for the current session:

      ```bash
      setenforce 0
      ```

   1. Open `/etc/selinux/config` for editing:

      ```bash
      vi /etc/selinux/config
      ```

   1. Set `SELINUX` to `permissive` and save the file:

      ```bash
      SELINUX=permissive
      ```

   1. Restart the CMP application:

      ```bash
      supervisorctl restart jobengine:* && systemctl restart httpd
      ```

   **Option 2: Add SELinux entries**

   1. Refer to [How to Prepare SELinux Policies for CMP Appservers](https://support.cloudbolt.io/cloudbolt/s/article/how-to-prepare-selinux-policies-for-cmp-appservers-on-rhel-8-x--2158952449--1)

`httpd` should now be starting and healthy. Ensure there are no errors in `/var/log/cloudbolt/application.log`. Load the CMP UI.

### Firewall

1. If `httpd` is healthy and you are unable to access the CMP UI, ensure the firewall is configured to allow access on the required ports. The following instructions are for `firewalld`:

   ```bash
   firewall-cmd --permanent --add-service=http
   firewall-cmd --permanent --add-service=https
   firewall-cmd --reload
   ```

### CMP system status

Check System Status to ensure all services are green:

1. In the CMP UI, go to **Admin** > **All Admin** > **System Status**.
1. Under **Health Checks**, verify that all services are green.

## Create an Azure Load Balancer

<div class="alert alert-info" role="alert">


These instructions document how to create an Azure Load Balancer that enables SSL termination on each CMP instance rather than on the load balancer. If you require more advanced load balancing capabilities (for example, SSL termination at the load balancer), contact your Technical Account Manager for assistance with configuring an Azure Application Gateway.
</div>


1. In the Azure portal, go to **Load balancers**.
1. Select **Create** > **Standard Load Balancer**.
1. Select a **Subscription** and **Resource Group**.
1. Provide a **Name**.
1. Select the same **Region** as your VMs.
1. Next to **Type**, select **Public**.
1. Select **Next : Frontend IP Configuration >**.
   1. Select **Add a frontend IP configuration**.
      1. Provide **Name: cmp-vip**, select to create a new **public IP address**, and select **Save**.
1. Select **Next : Backend pools >**.
   1. Select **Add a backend pool**.
      1. Provide **Name: cmp-pool**, select the **instance virtual network**, **add the instances**, and select **Save**.
1. Select **Next : Inbound rules >**.
   - Select **Add a load balancing rule** to create a rule for HTTP.
     - Frontend IP address: cmp-vip
     - Backend pool: cmp-pool
     - Port: 80
     - Backend port: 80
     - Health probe: Create new
       - Name: cmp-check
       - Protocol: TCP
       - Port: 80
       - Select **Save**.
     - Session persistence: Source IP
     - Select **Save**.
   - Select **Add a load balancing rule** to create a rule for HTTPS.
     - Name: https
     - Frontend IP address: cmp-vip
     - Backend pool: cmp-pool
     - Port: 443
     - Backend port: 443
     - Health probe: cmp-check
     - Session persistence: Source IP
     - Select **Save**.
1. Select **Next : Outbound rule >**.
   - Select **Add an outbound rule**.
     - Name: cmplb-out
     - Frontend IP address: cmp-vip
     - Backend pool: cmp-pool
     - Port allocation: Use the default number of outbound ports
     - Select **Save**.
1. Select **Review + create**.
1. Select **Create**.
