> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/installation/rpm/cloud/azure.md).

# Azure

Provision Azure virtual machines, storage, networking and a load balancer for an OpenIAM RPM deployment — single node or three nodes.

## What this covers, and how long it takes

<table><thead><tr><th width="150"></th><th></th></tr></thead><tbody><tr><td><strong>You get</strong></td><td>Azure virtual machines provisioned and networked for an OpenIAM RPM build, and a load balancer in front of a three-node cluster</td></tr><tr><td><strong>Time</strong></td><td>60–90 minutes to provision, before the installation itself</td></tr><tr><td><strong>Hosts</strong></td><td>One virtual machine, or three</td></tr><tr><td><strong>Downtime</strong></td><td>None — nothing is installed here</td></tr><tr><td><strong>Reversible</strong></td><td>Yes</td></tr></tbody></table>

## Before you start

* An Azure subscription, a virtual network and subnet, and permission to create virtual machines, network security groups, a managed database and a load balancer.
* The build path for your shape: [*RPM, single node*](/installation/rpm/rpm-single-node.md) or [*RPM, three nodes*](/installation/rpm/rpm-ha.md).
* [*Managed databases*](/installation/rpm/cloud/managed-databases.md), if you are using an Azure managed database — the server parameters have to be right **before** you install.

***

## Set these first

{% code overflow="wrap" %}

```bash
export OPENIAM_URL=<the address users will type>
export NODES="<node-1> <node-2> <node-3>"   # three-node deployments only
export AZ_RG=<your resource group>
```

{% endcode %}

***

## Provision it

### 1. Choose a virtual machine size

Size against [*System requirements*](/installation/system-requirements.md): 8 vCPU, and 48 GB of memory for non-production or 62 GB for production.

<table><thead><tr><th width="151.3999786376953">Shape</th><th width="214.79998779296875">Size</th><th>Why</th></tr></thead><tbody><tr><td>Single node, non-production</td><td><code>Standard_E8as_v5</code> or <code>Standard_E8s_v5</code></td><td>8 vCPU, 64 GiB nominal — the host reports about 62 GB once firmware and kernel reserves are taken</td></tr><tr><td>Single node, production</td><td><code>Standard_E16as_v5</code>, or <code>E8as_v5</code> with no margin</td><td>64 GiB nominal sits exactly on the production figure. Size up unless the deployment is small and known</td></tr><tr><td>Three nodes</td><td>3 × the size you chose</td><td>Identical machines. Every node runs the full platform</td></tr></tbody></table>

**The memory-optimised E family rather than the general-purpose D family.** OpenIAM runs its services as separate JVMs, so the platform is memory-hungry before it is CPU-hungry; `D8` sizes provide 32 GB, which is below the requirement.

### 2. Choose an image

**Enterprise Linux 9 is the tested image.** Enterprise Linux 10 is supported by the platform. In the Marketplace, either:

* **Red Hat Enterprise Linux 9**, choosing a **RAW image with `cloud-init`**, or
* **Rocky Linux 9** for x86\_64, from the official publisher.

Confirm after deployment:

{% code overflow="wrap" %}

```bash
grep PLATFORM_ID /etc/os-release
```

{% endcode %}

**Expected:** `platform:el9` or `platform:el10`.

### 3. Size the OS disk

**The free-space check reads `/`.** Azure's default OS disk is smaller than OpenIAM needs, so set it explicitly at deployment.

| Environment    | OS disk    |
| -------------- | ---------- |
| Non-production | **128 GB** |
| Production     | **256 GB** |

Premium SSD is a reasonable default. To keep OpenIAM's data on a separate data disk, attach one and follow [*Install on a separate partition*](/installation/rpm/rpm-single-node/separate-partition.md) — but size the OS disk to the table above regardless, because that is what the check reads.

**Azure's temporary disk is not durable.** Do not place OpenIAM, its data or its logs on it.

### 4. Turn swap off

**This one catches people on Azure.** Azure's `cloud-init` images commonly enable a swap file on the temporary disk, and the installation requires swap disabled:

{% code overflow="wrap" %}

```bash
swapon --show      # expect no output
swapoff -a
```

{% endcode %}

Then stop it returning at the next boot. Which fix applies depends on what created it:

* **The Azure Linux Agent.** Set `ResourceDisk.EnableSwap=n` in `/etc/waagent.conf` — and `ResourceDisk.EnableSwapEncryption=n` if it is present — then restart `waagent`.
* **`cloud-init`.** Remove the `swap:` stanza from the cloud-init configuration and run `cloud-init clean`.

Remove any swap entry from `/etc/fstab` either way.

**Confirm after a restart**, before you install. A swap file that returns at boot stops the installation.

### 5. Place the virtual machines

**Single node:** one subnet, with the load balancer or your own routing providing the entry point.

**Three nodes:** the reference build places all three machines in **one subnet**. The three hosts share a filesystem exported from the first node and cluster over the ports in [*Ports*](/installation/rpm/rpm-ha/ports.md), both of which are sensitive to the latency between them.

Spreading the three across availability zones changes those characteristics and is an architecture decision rather than an installation one — the [Solution Architecture and Design Guide](/solution-architecture/deployment/availability-and-recovery.md) covers it. An availability set gives you fault and update domain separation within one zone without that trade-off.

### 6. Configure the network security group

<table><thead><tr><th width="123.40000915527344">Rule</th><th width="332.79998779296875">Source</th><th>Ports</th></tr></thead><tbody><tr><td>Inbound</td><td>The load balancer, or its subnet</td><td>80, 443</td></tr><tr><td>Inbound</td><td>The subnet the three machines are in — three-node only</td><td>The inter-node ports in <a href="/installation/rpm/rpm-ha/ports.md"><em>Ports</em></a></td></tr><tr><td>Inbound</td><td>Your administration network or Azure Bastion</td><td>22</td></tr><tr><td>Outbound</td><td>Internet</td><td>443</td></tr></tbody></table>

**Scope the inter-node rules to the subnet**, not to the virtual network, so the cluster ports are not reachable from anything else you run.

**Outbound HTTPS is needed during the build.** All three machines need access to your OS vendor's package repositories — the build installs packages on each of them. **Only the first machine needs `download.openiam.com`**: it retrieves the OpenIAM components once and distributes them to the other two. A single node can be built with no outbound access at all — see [*Obtain the software*](/installation/obtain-the-software.md).

### 7. Confirm hostname resolution

The three-node build addresses the hosts by name. Azure-provided DNS resolves virtual machine names within a virtual network:

{% code overflow="wrap" %}

```bash
for h in $NODES; do getent hosts "$h"; done
```

{% endcode %}

**Expected:** all three resolve, on all three hosts. Whatever names you use, use the same form everywhere — the cluster configuration and the shared filesystem both key off them.

### 8. Provision the database

[*Managed databases*](/installation/rpm/cloud/managed-databases.md) covers the supported Azure services, the server parameters that must be set before you install, and how to answer the installation's prompts.

Use a **private endpoint** and allow the engine's port from the platform machines' subnet only.

### 9. Run long steps inside a terminal multiplexer

The installation runs for most of an hour, and a dropped session ends it. This matters more on a cloud virtual machine than on a console you control:

{% code overflow="wrap" %}

```bash
dnf install -y screen
screen -S openiam-install
```

{% endcode %}

Detach with **Ctrl+A** then **D**; reattach with `screen -r openiam-install`.

***

## The load balancer, for a three-node cluster

Two options, and the choice decides where TLS is terminated.

**Application Gateway** — a layer 7 gateway. Choose this if you want TLS terminated at the edge, a WAF, or path-based routing.

<table><thead><tr><th width="238">Setting</th><th>Value</th></tr></thead><tbody><tr><td><strong>Listener</strong></td><td>443, with your certificate. Add an 80 listener with a redirect rule to 443</td></tr><tr><td><strong>Backend pool</strong></td><td>All three machines</td></tr><tr><td><strong>Backend setting</strong></td><td>HTTP, port 80</td></tr><tr><td><strong>Custom probe path</strong></td><td><code>/idp/login</code></td></tr><tr><td><strong>Probe interval</strong></td><td>30 seconds</td></tr><tr><td><strong>Probe timeout</strong></td><td>5 seconds</td></tr><tr><td><strong>Unhealthy threshold</strong></td><td>2</td></tr><tr><td><strong>Cookie-based affinity</strong></td><td>Disabled</td></tr><tr><td><strong>Request headers</strong></td><td><code>X-Forwarded-Proto: https</code></td></tr></tbody></table>

**Azure Load Balancer** — layer 4. It cannot hold a certificate, terminate TLS, redirect, or set headers, so **terminate TLS on the hosts** if you use it — [*Enable HTTPS*](/installation/rpm/rpm-single-node/enable-https.md).

<table><thead><tr><th width="215.60000610351562">Setting</th><th>Value</th></tr></thead><tbody><tr><td><strong>Backend pool</strong></td><td>All three machines, port 80 — or 443 once the hosts serve HTTPS</td></tr><tr><td><strong>Health probe</strong></td><td>HTTP on 80, path <code>/idp/login</code></td></tr><tr><td><strong>Probe interval</strong></td><td>30 seconds</td></tr><tr><td><strong>Unhealthy threshold</strong></td><td>2</td></tr><tr><td><strong>Session persistence</strong></td><td>None</td></tr></tbody></table>

**Probe `/idp/login`, not `/`.** It exercises the reverse proxy and a real application behind it, so a machine whose platform has stopped is taken out of rotation even though its proxy is still answering.

**Session affinity is not required.** Session state is shared across the three nodes by the cache tier, so any node can serve any request — [*The clustered tiers*](/installation/rpm/rpm-ha/form-the-clusters.md). Leaving persistence off is the simplest configuration. If you enable it, do not use a form that pins a client to a machine that has failed its probe.

**Wherever TLS terminates, the platform has to know.** If an Application Gateway terminates it, set `X-Forwarded-Proto` so the platform builds `https://` links — [*Configure the load balancer*](/installation/rpm/rpm-ha/load-balancer.md) has the full requirements.

Use the load balancer's DNS name, or an alias in Azure DNS, as the content provider's **Domain Pattern** in [*First sign-in*](/installation/rpm/rpm-single-node/first-sign-in.md).

***

## The entry point, for a single node

A three-node deployment reaches users through the load balancer above. **A single-node deployment needs the same four things decided, and none of them is created for you.**

### 1. Reachability

The instance sits in a private subnet, so decide how users reach it:

<table><thead><tr><th width="250.80001831054688">Option</th><th>When</th></tr></thead><tbody><tr><td><strong>An Application Gateway in front of the one instance</strong></td><td>The usual choice. Gives you an certificate in Key Vault, a stable DNS name, and a path to three nodes later without changing the published address</td></tr><tr><td><strong>A public IP on the VM</strong></td><td>Evaluation only. The instance is then directly exposed on 80 and 443</td></tr></tbody></table>

The load balancer settings above apply unchanged with a single target.

### 2. DNS

Create a record for the address users will type — an alias to the gateway, or an A record to the public IP. **This is the address that goes on the content provider during first sign-in**, so decide it before you get there; changing it later means editing the content provider.

### 3. TLS

<table><thead><tr><th width="290.79998779296875">Where TLS terminates</th><th>What to do</th></tr></thead><tbody><tr><td><strong>At the load balancer</strong>, with an certificate in Key Vault</td><td>Forward to the instance on 80. Set <code>X-Forwarded-Proto</code> so the platform builds <code>https://</code> links</td></tr><tr><td><strong>On the instance</strong></td><td><a href="/installation/rpm/rpm-single-node/enable-https.md"><em>Enable HTTPS</em></a> — put your certificate on the host</td></tr></tbody></table>

**Complete HTTPS before first sign-in.** The first sign-in sets the administrator password; doing it over plain HTTP sends that password across the network in the clear. If you must sign in before a certificate is available, do it from the host itself over an SSH tunnel and change the password again afterwards.

### 4. The published URL

{% code overflow="wrap" %}

```
https://$OPENIAM_URL/webconsole
```

{% endcode %}

Confirm it answers before going further:

{% code overflow="wrap" %}

```bash
curl -s -o /dev/null -w '%{http_code}\n' https://$OPENIAM_URL/webconsole
```

{% endcode %}

**Expected: `200`, or a `30x` redirect to a sign-in page.** Then complete [*First sign-in*](/installation/rpm/rpm-single-node/first-sign-in.md) using that DNS name.

## Verify it

Before installing anything, on each machine:

{% code overflow="wrap" %}

```bash
grep PLATFORM_ID /etc/os-release
free -g | awk '/^Mem:/ {print $2" GB memory"}'
df -h / | awk 'NR==2 {print $4" free on /"}'
swapon --show
curl -s -o /dev/null -w '%{http_code}\n' -m 10 https://download.openiam.com
```

{% endcode %}

**Expected:** an EL9 or EL10 platform, memory and disk at or above the requirement, **no swap**, and an HTTP response from the download site — or no response if you are building air-gapped, which is expected.

**Restart the machine and run the swap check again** before you install. That is the check most likely to pass now and fail later on Azure.

For a three-node build, add the checks in [*Prepare the hosts*](/installation/rpm/rpm-ha/prepare-the-hosts.md).

## If it goes wrong

| What you see                                    | What it means                                                                       | What to do                                                                                                    |
| ----------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| The installation stops on swap                  | The image re-enabled it at boot                                                     | `swapoff -a`, then disable it in `/etc/waagent.conf` and `/etc/fstab`, restart, and confirm before re-running |
| The installation stops on free space            | The OS disk is too small — the check reads `/`, not a data disk                     | Grow the OS disk and extend the filesystem, then re-run                                                       |
| The installation stops on memory                | The size family tops out below the requirement at this vCPU count                   | Move to a memory-optimised `E` size                                                                           |
| The install dies when your laptop sleeps        | The SSH session carried the run                                                     | Re-run inside `screen`                                                                                        |
| Nodes cannot reach each other                   | The security group rules are scoped too narrowly, or to the wrong subnet            | Allow the inter-node ports from the machines' own subnet                                                      |
| The load balancer marks every machine unhealthy | The probe is on the wrong port or path, or 80 is not allowed from the load balancer | Confirm HTTP on 80 to `/idp/login`, and the inbound rule                                                      |
| The database is unreachable from the machines   | The private endpoint or its DNS zone is not linked to this virtual network          | Link the private DNS zone, then re-test with the engine's client                                              |

## What this procedure does not cover

Provisioning automation, subscription and resource-group structure, and network design beyond what the platform needs. Those are your organisation's, and the [Solution Architecture and Design Guide](/solution-architecture/deployment/network-design.md) covers the design decisions.

## Related

* [*Managed databases*](/installation/rpm/cloud/managed-databases.md) — Azure managed databases, before you install
* [*RPM, single node*](/installation/rpm/rpm-single-node.md) and [*RPM, three nodes*](/installation/rpm/rpm-ha.md)
* [*Ports*](/installation/rpm/rpm-ha/ports.md) — what the network security group has to allow
* [*Configure the load balancer*](/installation/rpm/rpm-ha/load-balancer.md)

*Applies to OpenIAM 2026.8.1.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/installation/rpm/cloud/azure.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
