> 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/prepare-the-hosts.md).

# Prepare the hosts

Three hosts, name resolution, the inter-node firewall rules and the trust relationship the installation uses.

## What this covers, and how long it takes

<table><thead><tr><th width="170"></th><th></th></tr></thead><tbody><tr><td><strong>You get</strong></td><td>Three hosts confirmed ready, able to resolve and reach each other</td></tr><tr><td><strong>Time</strong></td><td>45 minutes</td></tr><tr><td><strong>Hosts</strong></td><td>All 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

Three hosts provisioned to [*System requirements*](/installation/system-requirements.md) — **each meeting the figures individually**: 8 vCPU, 48 GB memory for non-production or 62 GB for production, and 80 GB or 200 GB of free space.

Decide which host you will work from. That host runs the installation for the whole cluster, exports the shared directories the other two mount, and is where you will keep the cluster tooling. This guide calls it the **first node**.

Have the cluster installation tooling to hand before you start — see [*Obtain the software*](/installation/obtain-the-software.md). [*Install*](/installation/rpm/rpm-ha/install.md) begins by cloning it onto the first node.

## Set these first

Fill this in once, on the first node. Every command on this page uses it.

{% code overflow="wrap" %}

```bash
export NODE1=<first node — also the shared-storage host>
export NODE2=<second node>
export NODE3=<third node>
export NODES="$NODE1 $NODE2 $NODE3"
```

{% endcode %}

Use the same form of name everywhere — fully qualified or short, but consistently. The cluster configuration and the shared filesystem both key off these names.

***

## Check it

Run [*Prepare the host*](/installation/rpm/rpm-single-node/prepare-the-host.md) on **each of the three hosts** — the operating system, memory, disk, swap, ports, and clock checks are identical. Come back here for what is specific to a cluster.

### 1. Every host resolves and reaches the other two

Name resolution matters more here than on a single node: the tiers address each other by name.

On each host:

{% code overflow="wrap" %}

```bash
for h in $NODES; do
  printf '%-20s %s\n' "$h" "$(getent hosts "$h" | awk '{print $1}')"
done
```

{% endcode %}

**Expected:** all three resolve, on all three hosts, to the addresses you expect. Use fully qualified names or short names consistently — whichever you choose, use the same form everywhere, including in `env.conf` later.

If you are not using DNS, add all three to `/etc/hosts` on every host:

{% code overflow="wrap" %}

```
10.0.0.11   node1.example.com  node1
10.0.0.12   node2.example.com  node2
10.0.0.13   node3.example.com  node3
```

{% endcode %}

Then confirm reachability:

{% code overflow="wrap" %}

```bash
for h in $NODES; do ping -c1 -W2 "$h" >/dev/null && echo "$h ok"; done
```

{% endcode %}

### 2. Clocks are synchronised across all three

{% code overflow="wrap" %}

```bash
for h in $NODES; do
  echo "$h $(ssh "$h" date -Is)"
done
```

{% endcode %}

**Expected:** within a second or two of each other. Cluster protocols and certificate validation both depend on it, and clock drift produces failures that look like something else entirely.

### 3. SELinux is disabled on all three hosts

**A three-node deployment requires SELinux to be disabled.** This is a requirement of the clustered cache rather than a general one — a single-node deployment runs with SELinux enforcing, and the installation sets the contexts, port labels and booleans it needs there.

The reason is the cache's failover mechanism. In a cluster the cache runs a watcher process on each node (Redis Sentinel) which **rewrites its own configuration file at runtime** as the cluster's topology changes, listens on a port outside SELinux's cache port label, and replicates across routable node addresses rather than the loopback interface. Under an enforcing policy the watcher cannot persist the topology it discovers, and failover stops working in ways that surface later as unexplained session loss rather than as an obvious error at install time.

The cluster installation sets this for you, but **set it before you start** so the change is deliberate, reviewed, and applied with the restart you are already planning:

{% code overflow="wrap" %}

```bash
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
getenforce
```

{% endcode %}

**Expected: `Permissive` now, and `Disabled` after the host next restarts.** Run this on all three hosts.

**Raise it with your security team before the build, not after.** Organisations with a hardening standard that mandates SELinux usually compensate at the layer around the cluster — the three hosts sit on their own segment, reachable only on 80 and 443 from the load balancer, with the inter-node ports closed to everything else. [*Ports*](/installation/rpm/rpm-ha/ports.md) is written to support exactly that conversation.

### 4. Nothing sits between the hosts that would block cluster traffic

**The installation opens the ports on each host for you**, where firewalld is running — both the inter-node ports and the user-facing 80 and 443. You do not need to add those rules yourself.

What the installation cannot do is open a firewall it does not run on. **If a network firewall or a security group sits between the three hosts, allow the inter-node matrix in** [***Ports***](/installation/rpm/rpm-ha/ports.md) **between them before you start.** The hosts should be able to reach each other freely on those ports and nothing outside the three should reach them at all.

Confirm the path is clear:

{% code overflow="wrap" %}

```bash
for peer in $NODE2 $NODE3; do   # run on NODE1; use the other two on each host
  timeout 2 bash -c "</dev/tcp/${peer}/22" 2>/dev/null \
    && echo "$peer reachable" || echo "$peer BLOCKED"
done
```

{% endcode %}

The cluster ports themselves show as closed until the services behind them exist — you are confirming here that the hosts can reach each other at all, and re-checking the rest after the build.

### 5. User-facing ports

**Only 80 and 443 face users**, and only in front of the load balancer. Each host needs them open so the load balancer can reach it, and the installation opens them when you install the reverse proxy.

### 6. The first node can reach the other two over SSH

The installation coordinates work across the cluster from the first node, using key-based SSH.

On the **first node**, generate a key if there is not one already:

{% code overflow="wrap" %}

```bash
ssh-keygen -t rsa -b 4096
```

{% endcode %}

Accept the defaults; leave the passphrase empty so unattended steps are not blocked.

Then authorise it on all three hosts — including the first node itself:

{% code overflow="wrap" %}

```bash
for h in $NODES; do ssh-copy-id "root@$h"; done
```

{% endcode %}

**Confirm it works without a prompt:**

{% code overflow="wrap" %}

```bash
for h in $NODES; do
  ssh -o BatchMode=yes "root@$h" hostname
done
```

{% endcode %}

**Expected:** three hostnames, no password prompts.

The account is set by `SERVICE_ACCOUNT` in `env.conf`, and defaults to `root`.

***

## Verify it

From the first node, a single pass:

{% code overflow="wrap" %}

```bash
for h in $NODES; do
  echo "=== $h"
  ssh -o BatchMode=yes "root@$h" '
    echo "  os:    $(grep -o "platform:el[0-9]*" /etc/os-release)"
    echo "  mem:   $(free -g | awk "/^Mem:/ {print \$2}") GB"
    echo "  disk:  $(df -h / | awk "NR==2 {print \$4}") free"
    echo "  swap:  $(swapon --show | wc -l) devices"
    echo "  clock: $(date -Is)"'
done
```

{% endcode %}

**Expected:** three hosts, all meeting the requirements, no swap, clocks aligned. Keep the output with your build record.

## If it goes wrong

| What you see                             | What it means                                               | What to do                                                                                                                                         |
| ---------------------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| A host does not resolve the others       | DNS or `/etc/hosts` incomplete                              | Add all three everywhere, in a consistent name form                                                                                                |
| SSH prompts for a password               | The key is not authorised on that host                      | Re-run `ssh-copy-id` and confirm with `ssh -o BatchMode=yes`                                                                                       |
| Clocks differ by more than a few seconds | Time synchronisation is not running                         | `timedatectl set-ntp true` and confirm before continuing                                                                                           |
| A host is unreachable from the others    | A network firewall or security group between them           | Allow the inter-node matrix in [*Ports*](/installation/rpm/rpm-ha/ports.md); confirm with your network team if the hosts are on different segments |
| `getenforce` still reports `Enforcing`   | `setenforce 0` was not run, or the config edit did not take | Re-run both commands in step 3 and confirm before starting the build                                                                               |

## What this procedure does not cover

Provisioning the three hosts, your network design, and your organisation's hardening baseline. On AWS and Azure, [*AWS*](/installation/rpm/cloud/aws.md) and [*Azure*](/installation/rpm/cloud/azure.md) cover instance sizing and placement. Installation begins on [*Install*](/installation/rpm/rpm-ha/install.md).

## Related

* [*Prepare the host*](/installation/rpm/rpm-single-node/prepare-the-host.md) — the per-host checks
* [*Ports*](/installation/rpm/rpm-ha/ports.md)
* [*Install*](/installation/rpm/rpm-ha/install.md) — the next page

*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/prepare-the-hosts.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.
