> 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/rpm-ha/install.md).

# Install

Install a three-node OpenIAM cluster from the first node — the cluster tooling, infra.conf, and the run that builds all three hosts.

## What this builds, and how long it takes

<table><thead><tr><th width="149.1999969482422"></th><th></th></tr></thead><tbody><tr><td><strong>You get</strong></td><td>Three hosts running the full OpenIAM platform, with every tier clustered across them</td></tr><tr><td><strong>Time</strong></td><td>2–3 hours, most of it unattended</td></tr><tr><td><strong>Hosts</strong></td><td>All three — but you drive the whole build from one of them</td></tr><tr><td><strong>Downtime</strong></td><td>None on an existing deployment. Plan one restart per host afterwards</td></tr><tr><td><strong>Reversible</strong></td><td>Partly. Removing the package does not undo everything it changed</td></tr></tbody></table>

**You run this once, from one host.** OpenIAM provides cluster tooling that installs and configures all three hosts over SSH. You do not repeat the procedure on each node — that is the single most useful thing to know before starting.

This guide calls the host you work from the **first node**. It is also the node that the cluster tooling treats as the shared-storage server and the starting point for each tier's cluster.

## Before you start

**Done already**

* [*Prepare the hosts*](/installation/rpm/rpm-ha/prepare-the-hosts.md) completed on all three, including the SSH trust from the first node to all three.
* Each host meets [*System requirements*](/installation/system-requirements.md) individually. The installation checks memory, free space on `/` and swap on the host you run it from; confirm the other two yourself before starting.

**Have ready**

* **The cluster installation tooling for your release**, obtained with your other OpenIAM artefacts — see [*Obtain the software*](/installation/obtain-the-software.md). It is a Git repository; check out the exact revision issued for this release.
* **Outbound HTTPS from the first node** to `download.openiam.com`. The first node downloads the artefacts once and distributes them to the other two.
* **A decision on the database.** The tooling can build a MariaDB Galera cluster across the three hosts, or you can point the deployment at your own database server. Most production deployments use an external database with its own availability arrangement — see [*Use a remote database*](/installation/rpm/rpm-single-node/use-a-remote-database.md).
* **A decision on shared storage.** Three directories are shared across the cluster: the upload area, the generated configuration, and the secret store's certificates. NFS is the default and the recommended choice.
* **`root` on all three hosts.**
* **SELinux disabled on all three hosts**, per [*Prepare the hosts*](/installation/rpm/rpm-ha/prepare-the-hosts.md) step 3. The build sets it if you have not, but doing it beforehand keeps the change deliberate and lets you fold the restart into the one in step 5.

***

## Set these first

The cluster tooling reads these from `infra.conf`; the checks on this page use the same names:

{% code overflow="wrap" %}

```bash
export NODE1=<the first node, the one you run the build from>
export NODE2=<the second node>
export NODE3=<the third node>
export SSH_PORT=22
```

{% endcode %}

`CLUSTER_NODES` and `CLUSTER_IPS` are set in `infra.conf` in step 2 below, as shell arrays indexed from `1`. They must line up index for index.

***

## Build it

### 1. Get the cluster tooling onto the first node

{% code overflow="wrap" %}

```bash
dnf install git -y
git clone <the repository URL from your account team> openiam-cluster-rpm
cd openiam-cluster-rpm
git checkout <the revision issued for this release>
```

{% endcode %}

**Use the revision issued for this release.** The tooling tracks the platform release, and the tag is what pins the two together — [*Obtain the software*](/installation/obtain-the-software.md) covers where to get both.

### 2. Configure the cluster in `infra.conf`

This one file describes your cluster to the tooling. Edit it before running anything:

{% code overflow="wrap" %}

```bash
vi ./infra.conf
```

{% endcode %}

**Set these to your environment:**

<table><thead><tr><th width="235.60000610351562">Setting</th><th>What to set it to</th></tr></thead><tbody><tr><td><code>OPENIAM_VERSION</code></td><td>The version you are installing</td></tr><tr><td><code>OPENIAM_ENV</code></td><td><code>release</code>, unless OpenIAM has told you otherwise</td></tr><tr><td><code>INST_HOME</code></td><td>The full path you cloned the tooling into</td></tr><tr><td><code>CLUSTER_NODES</code></td><td>The three host names, as <code>( [1]=node1 [2]=node2 [3]=node3 )</code></td></tr><tr><td><code>CLUSTER_IPS</code></td><td>The three addresses, in the same order</td></tr><tr><td><code>NFS_SERVER</code></td><td>The address of the host that exports the shared directories. Use the first node</td></tr><tr><td><code>NETWORK</code></td><td>The CIDR the three hosts sit in — this is what the shared export is restricted to</td></tr><tr><td><code>GALERA_CLUSTER_ADDRESS</code></td><td><code>gcomm://node1,node2,node3</code>, using your host names. Only used if you build the database on the cluster</td></tr><tr><td><code>SSH_PORT</code></td><td><code>22</code>, unless your hosts listen elsewhere</td></tr><tr><td><code>INTERNET_AVAILABLE</code></td><td><code>true</code></td></tr></tbody></table>

**Leave these unless a port is already taken on your hosts:**

<table><thead><tr><th>Setting</th><th width="146.5999755859375" align="center">Default</th><th>What it fronts</th></tr></thead><tbody><tr><td><code>HAPROXY_UI_PORT</code></td><td align="center"><code>8087</code></td><td>The interface tier across all three nodes</td></tr><tr><td><code>HAPROXY_ESB_PORT</code></td><td align="center"><code>9081</code></td><td>The enterprise service bus across all three nodes</td></tr><tr><td><code>HAPROXY_VAULT_PORT</code></td><td align="center"><code>8200</code></td><td>The secret store</td></tr><tr><td><code>HAPROXY_JANUS_PORT</code></td><td align="center"><code>8183</code></td><td>The graph tier</td></tr><tr><td><code>HAPROXY_ES_PORT</code></td><td align="center"><code>9201</code></td><td>The search tier</td></tr><tr><td><code>HAPROXY_RABBIT_PORT</code></td><td align="center"><code>5673</code></td><td>The message broker</td></tr><tr><td><code>HAPROXY_RABBIT_UI_PORT</code></td><td align="center"><code>5002</code></td><td>The broker's management interface</td></tr></tbody></table>

`CLUSTER_NODES` and `CLUSTER_IPS` must line up index for index — entry `[2]` in one is the same host as entry `[2]` in the other. Everything the tooling generates is keyed off that pairing.

**Check your entries before running:**

{% code overflow="wrap" %}

```bash
. ./infra.conf
for i in 1 2 3; do
  printf '%-20s %-16s ' "${CLUSTER_NODES[$i]}" "${CLUSTER_IPS[$i]}"
  ssh -p ${SSH_PORT} -o BatchMode=yes "${CLUSTER_IPS[$i]}" hostname
done
```

{% endcode %}

**Expected:** three rows, each ending in the host name you paired with that address. A mismatch here is much cheaper to fix now than after the build.

### 3. Run the installation

**Run it inside a terminal multiplexer.** The build takes hours and a dropped session ends it:

{% code overflow="wrap" %}

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

{% endcode %}

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

{% code overflow="wrap" %}

```bash
./install.sh
```

{% endcode %}

Everything is written to `install.log` in the tooling directory as well as to your terminal.

**What it does, in order:**

<table><thead><tr><th width="239.60000610351562">Stage</th><th>What happens</th></tr></thead><tbody><tr><td>Host preparation</td><td>Name entries distributed to all three, a <code>cluster</code> command installed for running work on every node</td></tr><tr><td>Shared storage</td><td>The export configured on the first node and mounted on all three, with entries added to <code>/etc/fstab</code></td></tr><tr><td>Package installation</td><td>The platform package installed on all three hosts</td></tr><tr><td>Firewall</td><td>The inter-node and user-facing ports opened on each host, where firewalld is running</td></tr><tr><td>Component load balancing</td><td>HAProxy installed on every node, fronting each clustered tier</td></tr><tr><td>Database</td><td>The Galera cluster, if you asked for one</td></tr><tr><td>Infrastructure tiers</td><td>Secret store backend, secret store, search, broker, cache — each installed and joined into a cluster</td></tr><tr><td>Schemas</td><td>The database schemas created and migrated</td></tr><tr><td>Graph tier</td><td>Graph storage and the graph engine, brought up one node at a time</td></tr><tr><td>Reverse proxy</td><td>Apache <code>httpd</code> with <code>mod_openiam</code> on all three hosts</td></tr><tr><td>Services</td><td>The platform services enabled and started on all three, then a status listing</td></tr><tr><td>Replication</td><td>Graph storage set to three replicas, search indexes to three copies</td></tr></tbody></table>

[*The clustered tiers*](/installation/rpm/rpm-ha/form-the-clusters.md) describes what each of those produced and how to confirm it.

### 4. Answer the prompts

The build stops for input at a few points. Between them it runs unattended.

1. **Build a MariaDB Galera cluster?** — `y` builds the database across the three hosts and takes you through `mariadb-secure-installation`; set and record a root password when it asks. Answer `n` to use your own database server.
2. **The credentials the platform will use.** A `CRITICAL SECTION` banner marks this block. You are asked for a username and password for each of the eight schemas, then a password for the message broker, the cache and the cache's failover watchers, then the search tier's username and password. Each prompt offers a default — **type your own values.** They become the live credentials for the life of the deployment and are written into the secret store. Your typing is not echoed, and the build prints the collected values once for you to confirm; treat that screen as sensitive.

   **Decide these before you start the run**, so a two-hour build is not waiting on you.
3. **Database type and connection details** — the engine, host, port and schema names. The engine prompt offers `mysql`; type your choice rather than pressing Enter. Host and port are asked once per schema, eight times. The defaults for the schema names are recommended.
4. **Install the OpenIAM reverse proxy module?** — answer `y`. This installs Apache `httpd` with `mod_openiam` on all three hosts, which is how users reach the platform.

**Record the secret store's unseal keys and root token, and the initial administrator account.** The build prints them once, on the first node, and writes them to `install.log` in the cluster tooling directory. They are what opens the secret store if it is ever sealed, and what you sign in with. Keep them where your organisation keeps break-glass credentials, and treat `install.log` as sensitive.

### 5. Restart each host

The package raises the file-descriptor limits to 65536, and those take effect at the next restart. **The cluster build does not restart the hosts** — unlike a single-node installation, where the package restarts the host a minute after it is installed. On a cluster the restart is yours to schedule, so you can take the hosts one at a time and keep the platform serving throughout.

**Restart the hosts one at a time**, at a point that suits you, confirming the platform is healthy again before moving to the next:

{% code overflow="wrap" %}

```bash
# On the host being restarted
openiam-cli stop
shutdown -r now
```

{% endcode %}

**Stop the platform before restarting the host.** The secret store seals if it is stopped without a clean shutdown, and the services cannot read their credentials from a sealed store.

After it comes back:

{% code overflow="wrap" %}

```bash
ulimit -Hn        # expect 65536
openiam-cli start
```

{% endcode %}

Then confirm that node has rejoined every tier before restarting the next — [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md) has the per-tier checks.

### 6. Verify

Go to [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md). On a cluster the question is not only "is it running" but "is every tier genuinely clustered", and those are different checks.

***

## Running commands across the cluster

The build installs a `cluster` command on the first node. It runs whatever follows it on all three hosts in turn:

{% code overflow="wrap" %}

```bash
cluster openiam-cli status
cluster systemctl status opensearch
```

{% endcode %}

Without it, `openiam-cli` and `systemctl` act on the local host only. This is the difference between starting one node and starting the cluster:

{% code overflow="wrap" %}

```bash
openiam-cli start           # this host
cluster openiam-cli start   # all three
```

{% endcode %}

## What the installation changes on each host

Listed so nothing surprises you afterwards.

<table><thead><tr><th width="182.80001831054688">Change</th><th>Detail</th></tr></thead><tbody><tr><td>Kernel settings</td><td><code>vm.max_map_count</code>, IPv6 disabled, non-local bind enabled where the database cluster is built</td></tr><tr><td>Limits</td><td><code>nofile</code> raised to 65536 — applied at the restart in step 5</td></tr><tr><td>SELinux</td><td>Set to <code>disabled</code> in <code>/etc/selinux/config</code>, if you have not already. Required by the clustered cache — <a href="/installation/rpm/rpm-ha/prepare-the-hosts.md"><em>Prepare the hosts</em></a> step 3</td></tr><tr><td>Name resolution</td><td>The three hosts added to <code>/etc/hosts</code> on every node</td></tr><tr><td>Mounts</td><td>Three shared directories added to <code>/etc/fstab</code> on every node</td></tr><tr><td>Firewall</td><td>Inter-node and user-facing ports opened where firewalld is running</td></tr><tr><td>Accounts</td><td>The <code>openiam</code> service account, and system accounts for the infrastructure components</td></tr></tbody></table>

## Verify it

From the first node:

{% code overflow="wrap" %}

```bash
cluster rpm -q openiam
cluster pgrep -c -u openiam java
```

{% endcode %}

**Expected:** the package installed on all three hosts, and a comparable process count on each.

**This is a smoke test, not the verification.** Go to [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md), which confirms each tier is genuinely clustered — a different question from whether the build completed.

## If it goes wrong

| What you see                                              | What it means                                                              | What to do                                                                                                                                                          |
| --------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Not enough free disk space` / `Not enough available RAM` | The host you ran it from is below the threshold                            | Provision to [*System requirements*](/installation/system-requirements.md) on all three                                                                             |
| `Disable the swap and run openiam-cli init again`         | A swap device is active                                                    | `swapoff -a` on all three, remove the `/etc/fstab` entry, re-run                                                                                                    |
| SSH prompts for a password partway through                | The trust is not in place for that host                                    | Finish [*Prepare the hosts*](/installation/rpm/rpm-ha/prepare-the-hosts.md) step 6 — the SSH trust from the first node to all three, including itself — then re-run |
| A stage fails on one host only                            | Usually that host's firewall, mounts or resources                          | `cluster df -h /usr/local/openiam/conf` and `cluster systemctl status <unit>` compare all three at once                                                             |
| The build stops during graph storage                      | The graph tier is started one node at a time by design, with waits between | Confirm with `cluster nodetool status` before re-running; the waits are long but normal                                                                             |
| The shared directories are empty on nodes 2 and 3         | The mount did not take on those hosts                                      | `cluster mount -a`, then `cluster ls /usr/local/openiam/conf`                                                                                                       |
| The run ends but a node is not serving                    | One node's services did not start                                          | [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md) isolates which; [*Troubleshoot*](/installation/rpm/rpm-ha/troubleshoot.md) has the remedies      |

**Repair a failed stage rather than re-running the whole build.** Each tier has its own `init.sh` in the cluster tooling — `vault/init.sh`, `opensearch/init.sh`, `rabbitmq/init.sh` and so on, in the order listed above. Fix what failed, run that tier's script, then continue with the ones after it. A full re-run of `./install.sh` expects hosts in their pre-build state.

## What to do next

The cluster is built. These are the remaining steps to a production deployment, in the order most teams take them:

* **Confirm every tier is clustered** — [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md) steps 1 to 5. Not optional.
* **Put a load balancer in front of the three hosts** — [*Configure the load balancer*](/installation/rpm/rpm-ha/load-balancer.md).
* **Complete first sign-in** — [*First sign-in*](/installation/rpm/rpm-single-node/first-sign-in.md), using the load balancer's name as the published address.
* **Prove the cluster survives a node loss** — [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md), the final section. Do this before the deployment carries anything real.
* **Serve the platform over HTTPS** — [*Enable HTTPS*](/installation/rpm/rpm-single-node/enable-https.md), applied to each of the three hosts.
* **Arrange availability for your database**, where you supplied your own server.
* **Size the deployment for your load.** The build starts from shipped defaults; the *Solution Architecture and Design Guide* covers sizing.
* **Take a backup before the deployment carries anything real** — [*Back up and restore*](/installation/rpm/rpm-single-node/back-up-and-restore.md).

**Upgrades** are covered in [*Upgrading OpenIAM*](/installation/rpm/rpm-upgrade.md).

## What this procedure does not cover

Provisioning the three hosts, the load balancer, and the availability of the database. Cluster formation is [*The clustered tiers*](/installation/rpm/rpm-ha/form-the-clusters.md), and the load balancer is [*Configure the load balancer*](/installation/rpm/rpm-ha/load-balancer.md).

## Related

* [*The clustered tiers*](/installation/rpm/rpm-ha/form-the-clusters.md) — what the build produced, tier by tier
* [*Configure the load balancer*](/installation/rpm/rpm-ha/load-balancer.md) — what goes in front of the three hosts
* [*Start and verify*](/installation/rpm/rpm-ha/start-and-verify.md) — the next page, and not optional
* [*Ports*](/installation/rpm/rpm-ha/ports.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/rpm-ha/install.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.
