From Single Server to Cluster: Wazuh 4.14 High Availability Setup

Updated on Sep 28, 2026
Mila H
12 MINS READ
Table of Contents
Wazuh 4.14 High Availability Cluster

This guide shows how to build a Wazuh 4.14 cluster setup with a high availability design, with more than one manager node and more than one indexer node. If one server goes down, the rest keep working, so you do not lose security events or search access.

This is not a basic install guide. If you have not installed Wazuh before, start with the Wazuh SIEM setup guide for VPS infrastructure, which covers a single server. This guide covers many servers working as one cluster.

What Changes When You Move to a Wazuh Cluster

An all-in-one Wazuh install runs the manager, the indexer, and the dashboard on one machine. That machine is a single point of failure. One kernel panic, one disk full error, one bad update, and monitoring stops.

A Wazuh cluster setup splits the three roles onto separate machines and adds redundancy inside each role:

  • Wazuh server (manager) cluster: One master node plus one or more worker nodes. Agents connect to any node, and configuration, rules, and agent keys stay synced across all of them.
  • Wazuh indexer cluster: Three or more nodes storing and searching your alert data, with data replicated across nodes so no single disk failure erases your logs.
  • Wazuh dashboard: A single node or more, behind a load balancer, that reads from the indexer cluster.

The whole point of this setup is horizontal scale and fault tolerance for environments with many monitored servers.

Wazuh Cluster Architecture and Node Roles

A real Wazuh 4.14 cluster setup with high availability deployment needs at least six machines. You need three indexer nodes, two manager nodes (one master, one worker), and one dashboard node. You can add more manager or indexer nodes later if you monitor more agents.

Role Minimum nodes Purpose
Wazuh manager (master) 1 Coordinates the cluster, holds the single source of truth for rules and configuration
Wazuh manager (worker) 1+ Accepts agent connections and analyzes events, syncs from the master
Wazuh indexer 3+ Stores and searches alert data with data replication
Wazuh dashboard 1 Visualizes data, reads from the indexer, talks to the manager API

Note: Wazuh indexer clusters need an odd number of nodes, like 3, 5, or 7. This lets the cluster always pick one master node. It's a hard rule, not a tip; a two-node cluster can get stuck with no clear leader if the network splits.

Size Your Wazuh Cluster Nodes

Sizing depends on your agent count and events per second (EPS). Here are the safe options to start for a mid-size environment monitoring 200 to 500 agents:

Node type vCPU RAM Disk Notes
Manager (master/worker) 4 8 GB 100 GB SSD Scale CPU with agent count and rule complexity
Indexer 8 16 GB 500 GB+ SSD/NVMe Set JVM heap to half of RAM, disk grows with retention
Dashboard 2 4 GB 50 GB SSD Low load unless many concurrent users

Since each role runs on its own machine, this is a good time to use separate servers instead of one big and oversized server. PerLod's dedicated server hosting plans give you the isolated CPU, RAM, and NVMe storage that manager and indexer nodes need.

Required Network Ports for Wazuh Cluster Setup

You must open these ports between the nodes before you install anything. Missing ports are the most common reason a Wazuh cluster fails to run.

From To Port Protocol Purpose
Agents Manager nodes 1514 TCP Agent event traffic
Agents Manager nodes 1515 TCP Agent enrollment
Manager nodes Manager nodes 1516 TCP Manager cluster sync (master ↔ worker)
Dashboard, admins Manager nodes 55000 TCP Wazuh server REST API
Manager nodes (Filebeat) Indexer nodes 9200 TCP Indexer REST API / data shipping
Indexer nodes Indexer nodes 9300–9400 TCP Indexer cluster communication
Admins Dashboard node 443 TCP Dashboard web UI

Note: Only allow ports 1516 and 9300–9400 on your private network. These are internal cluster ports, so never open them to the public internet.

Build a Highly Available Wazuh 4.14 Cluster

The steps below cover every stage of a working Wazuh 4.14 cluster setup in the right order.  To build your cluster setup, follow the steps below:

Step 1: Prepare the Servers

You must set up the machines from the sizing table. Use the same Linux version on all of them, such as Ubuntu 22.04/24.04 or RHEL 8/9. Give each node a unique hostname, and make sure every node can reach every other node on the ports listed above.

Also, turn off auto-updates for the Wazuh repositories for now. You'll turn them back on later, on purpose, so every node stays on the same version. If managers drift to different versions, cluster sync breaks.

Remember to sync the clock on every node, since certificates and cluster communication are sensitive to time differences:

Bash
timedatectl set-ntp truetimedatectl status

Step 2: Generate Certificates for Every Node

Wazuh 4.14 uses a single script, wazuh-certs-tool.sh, to generate a root CA and per-node certificates for the indexer, manager, and dashboard nodes in one pass. You must run this on any one machine, not on every node individually.

Download the tool and the sample config file with:

Bash
curl -sO https://packages.wazuh.com/4.14/wazuh-certs-tool.shcurl -sO https://packages.wazuh.com/4.14/config.yml

Now open config.yml for editing and replace its content with your own node list:

Bash
nano config.yml

Paste this with your own names and IP addresses, then save and exit:

YAML
nodes:  # Wazuh indexer nodes  indexer:    - name: indexer-1      ip: "10.0.0.11"    - name: indexer-2      ip: "10.0.0.12"    - name: indexer-3      ip: "10.0.0.13"   # Wazuh server (manager) nodes  server:    - name: manager-1      ip: "10.0.0.21"      node_type: master    - name: manager-2      ip: "10.0.0.22"      node_type: worker   # Wazuh dashboard node  dashboard:    - name: dashboard-1      ip: "10.0.0.31"

Generate all certificates in one run with the command below:

Bash
bash ./wazuh-certs-tool.sh -A

This creates a wazuh-certificates/ folder with a root CA, an admin certificate, and one certificate pair per node named after the name field you set in config.yml. Compress the folder and copy it to every node with scp:

Bash
tar -cvf ./wazuh-certificates.tar -C ./wazuh-certificates/ .scp wazuh-certificates.tar root@10.0.0.11:scp wazuh-certificates.tar root@10.0.0.12:scp wazuh-certificates.tar root@10.0.0.13:scp wazuh-certificates.tar root@10.0.0.21:scp wazuh-certificates.tar root@10.0.0.22:scp wazuh-certificates.tar root@10.0.0.31:

Note: Keep the root CA files somewhere safe offline. You will need them again if you add a node later.

Step 3: Install and Configure the Wazuh Indexer Cluster

You must repeat this step on indexer-1, indexer-2, and indexer-3. First, add the Wazuh package repository. We assume you have a running Ubuntu OS:

Bash
apt install gnupg apt-transport-https -ycurl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import && chmod 644 /usr/share/keyrings/wazuh.gpgecho "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | tee -a /etc/apt/sources.list.d/wazuh.listapt-get updateapt install wazuh-indexer -y

The install creates a default opensearch.yml file. Open it for editing on each node:

Bash
nano /etc/wazuh-indexer/opensearch.yml

On indexer-1, replace the relevant lines with:

YAML
network.host: "10.0.0.11"node.name: "indexer-1"cluster.initial_master_nodes:  - "indexer-1"  - "indexer-2"  - "indexer-3"discovery.seed_hosts:  - "10.0.0.11"  - "10.0.0.12"  - "10.0.0.13"plugins.security.nodes_dn:  - "CN=indexer-1,OU=Wazuh,O=Wazuh,L=California,C=US"  - "CN=indexer-2,OU=Wazuh,O=Wazuh,L=California,C=US"  - "CN=indexer-3,OU=Wazuh,O=Wazuh,L=California,C=US"

Once you are done, save and exit. Repeat this on indexer-2 and indexer-3, only changing network.host and node.name to match each node. The cluster.initial_master_nodes, discovery.seed_hosts, and plugins.security.nodes_dn lists must be identical, with the same three entries, on all three nodes. This is exactly how the nodes discover and trust each other.

Deploy the certificates on each node; replace NODE_NAME per node:

Bash
NODE_NAME=indexer-1mkdir /etc/wazuh-indexer/certstar -xf ./wazuh-certificates.tar -C /etc/wazuh-indexer/certs/ ./$NODE_NAME.pem ./$NODE_NAME-key.pem ./admin.pem ./admin-key.pem ./root-ca.pemmv -n /etc/wazuh-indexer/certs/$NODE_NAME.pem /etc/wazuh-indexer/certs/indexer.pemmv -n /etc/wazuh-indexer/certs/$NODE_NAME-key.pem /etc/wazuh-indexer/certs/indexer-key.pemchmod 500 /etc/wazuh-indexer/certschmod 400 /etc/wazuh-indexer/certs/*chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/certs

Then, open the JVM options file and set the heap to about half the node's RAM:

Bash
nano /etc/wazuh-indexer/jvm.options

Change these two lines, example for a 16 GB node:

Bash
-Xms8g-Xmx8g

Start the service on each of the three nodes:

Bash
systemctl daemon-reloadsystemctl enable wazuh-indexersystemctl start wazuh-indexer

Step 4: Initialize the Indexer Cluster

This is the step people forget, and it is the difference between three separate indexer installs and one actual cluster. Run this command on only one of the three indexer nodes:

Bash
/usr/share/wazuh-indexer/bin/indexer-security-init.sh

Confirm all three nodes joined correctly:

Bash
curl -k -u admin https://10.0.0.11:9200/_cat/nodes?v

You should see three rows, one for each indexer node, with roles like data,ingest,master. If you only see one row, check discovery.seed_hosts and the firewall rules on ports 9300–9400. The rest of the Wazuh 4.14 cluster setup depends on this step working.

Step 5: Install and Configure the Wazuh Manager Cluster

At this point, you must repeat the repository setup and package install on manager-1 and manager-2:

Bash
apt install wazuh-manager -y

Generate a shared cluster encryption key once on the master node, and reuse the same value on every manager node:

Bash
openssl rand -hex 16

Copy the output somewhere safe, then open the manager config file on manager-1 (the master):

Bash
nano /var/ossec/etc/ossec.conf

Add this <cluster> block anywhere inside the <ossec_config> tags, then save and exit:

Bash
<cluster>  <name>wazuh</name>  <node_name>manager-1</node_name>  <node_type>master</node_type>  <key>PASTE_YOUR_GENERATED_KEY_HERE</key>  <port>1516</port>  <bind_addr>0.0.0.0</bind_addr>  <nodes>    <node>10.0.0.21</node>  </nodes>  <hidden>no</hidden>  <disabled>no</disabled></cluster>

Now open the same file on manager-2 (the worker):

Bash
nano /var/ossec/etc/ossec.conf

Use the same key and cluster name, but change the node identity and role:

Bash
<cluster>  <name>wazuh</name>  <node_name>manager-2</node_name>  <node_type>worker</node_type>  <key>PASTE_YOUR_GENERATED_KEY_HERE</key>  <port>1516</port>  <bind_addr>0.0.0.0</bind_addr>  <nodes>    <node>10.0.0.21</node>  </nodes>  <hidden>no</hidden>  <disabled>no</disabled></cluster>

The <nodes> tag always points to the master's IP, even in the master's own file. Wazuh only allows one master per cluster, so this list should have just that one address. Restart the manager service on both nodes:

Bash
systemctl restart wazuh-manager

Step 6: Connect Managers to the Indexer with Filebeat

Every manager node needs Filebeat to ship alerts to the indexer cluster. Install it and download a fresh config file on both manager-1 and manager-2:

Bash
apt install filebeat -ycurl -so /etc/filebeat/filebeat.yml https://packages.wazuh.com/4.14/tpl/wazuh/filebeat/filebeat.yml

Open the new file and point it at all three indexer nodes, not just one:

Bash
nano /etc/filebeat/filebeat.yml

Set the output block like this, then save and exit:

YAML
output.elasticsearch:  hosts: ["10.0.0.11:9200", "10.0.0.12:9200", "10.0.0.13:9200"]  protocol: https

You can store the indexer admin credentials in the Filebeat keystore instead of plain text:

Bash
filebeat keystore createecho admin | filebeat keystore add username --stdin --forceecho <YOUR_ADMIN_PASSWORD> | filebeat keystore add password --stdin --force

Then, download the alert template and the Wazuh Filebeat module:

Bash
curl -so /etc/filebeat/wazuh-template.json https://raw.githubusercontent.com/wazuh/wazuh/v4.14.7/extensions/elasticsearch/7.x/wazuh-template.jsonchmod go+r /etc/filebeat/wazuh-template.jsoncurl -s https://packages.wazuh.com/4.x/filebeat/wazuh-filebeat-0.5.tar.gz | tar -xvz -C /usr/share/filebeat/module

Create the certificate folder and copy the manager's own certificate into it, same pattern as the indexer step:

Bash
NODE_NAME=manager-1mkdir /etc/filebeat/certstar -xf ./wazuh-certificates.tar -C /etc/filebeat/certs/ ./$NODE_NAME.pem ./$NODE_NAME-key.pem ./root-ca.pemmv -n /etc/filebeat/certs/$NODE_NAME.pem /etc/filebeat/certs/filebeat.pemmv -n /etc/filebeat/certs/$NODE_NAME-key.pem /etc/filebeat/certs/filebeat-key.pemchmod 500 /etc/filebeat/certschmod 400 /etc/filebeat/certs/*chown -R root:root /etc/filebeat/certs

Repeat the certificate step with NODE_NAME=manager-2 on the second manager. Start Filebeat on both nodes and confirm the connection:

Bash
systemctl enable filebeatsystemctl start filebeatfilebeat test output

A working result ends with talk to server... OK.

Step 7: Install the Dashboard Node

On dashboard-1, you must install the package and set up its certificate folder the same way as before. Use NODE_NAME=dashboard-1, save to /etc/wazuh-dashboard/certs/, and rename the files to wazuh-dashboard.pem and wazuh-dashboard-key.pem.

Open the dashboard config file with the following command:

Bash
nano /etc/wazuh-dashboard/opensearch_dashboards.yml

Point it at your indexer cluster with:

YAML
opensearch.hosts: https://10.0.0.11:9200

Save and exit, then open the Wazuh app config file:

Bash
nano /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml

Point it at your manager cluster's master node:

YAML
hosts:  - default:      url: https://10.0.0.21      port: 55000      username: wazuh-wui      password: <WAZUH-WUI-PASSWORD>      run_as: false

Start the dashboard and browse to https://10.0.0.31:

Bash
systemctl enable wazuh-dashboardsystemctl start wazuh-dashboard

Step 8: Distribute Agent Load Across Manager Nodes

Agents can register with any manager node, but you want new agents spread evenly between manager-1 and manager-2, not stacked on just one. Wazuh 4.14 has a built-in load balancer for this, called the HAProxy helper. Open the master's config file again:

Bash
nano /var/ossec/etc/ossec.conf

Add this block inside the existing <cluster> block on the master node:

Bash
<haproxy_helper>  <haproxy_disabled>no</haproxy_disabled>  <haproxy_address>10.0.0.40</haproxy_address>  <haproxy_user>haproxy</haproxy_user>  <haproxy_password>your_haproxy_password</haproxy_password>  <haproxy_backend>wazuh_reporting</haproxy_backend>  <frequency>60</frequency>  <imbalance_tolerance>0.1</imbalance_tolerance></haproxy_helper>

This tells the master to talk to HAProxy and automatically move agents around whenever a worker has too many connections.

If you would rather not run HAProxy, just point agents at a round-robin DNS record or a Layer 4 load balancer that forwards TCP 1514/1515 to both managers. Both ways work for a Wazuh 4.14 cluster setup.

On each agent, open its config file:

Bash
nano /var/ossec/etc/ossec.conf

List every manager node so the agent can fail over if one is unreachable:

HTML/XML
<client>  <server>    <address>10.0.0.21</address>    <port>1514</port>  </server>  <server>    <address>10.0.0.22</address>    <port>1514</port>  </server></client>

Save, exit, and restart the agent service:

Bash
systemctl restart wazuh-agent

Step 9: Verify the Cluster Is Working

At this point, you can confirm both manager nodes see each other:

Bash
/var/ossec/bin/cluster_control -l

Expected output shows both nodes with a version and role:

Bash
NAME       TYPE     VERSION    ADDRESSmanager-1  master   4.14.7     10.0.0.21manager-2  worker   4.14.7     10.0.0.22

Or from the dashboard, go to Server management > Dev Tools and run:

Bash
GET /cluster/healthcheck

This shows each node's name, role, version, IP, and agent count.

Testing Node Failure for Wazuh Cluster Setup

A cluster you have not tested is not actually high availability; it is just a guess. Before putting real traffic on it, you must break it on purpose.

Stop the worker manager and watch agents reconnect to the master:

Bash
systemctl stop wazuh-manager

Run cluster_control -l from the master. The stopped worker should drop off the list within the frequency time you set earlier, 60 seconds by default. Agents that had both manager IPs should now show as connected to the surviving node in the dashboard's agent list.

Stop one indexer node and confirm the other two keep serving data:

Bash
systemctl stop wazuh-indexer

Run the cluster health check again:

Bash
curl -k -u admin https://10.0.0.12:9200/_cluster/health?pretty

The status field should show yellow, which means one copy is missing, but data is still fully searchable. If it shows red, fix your indexer replication settings. Then, bring the stopped node back and check that status returns to green.

Conclusion

A full Wazuh 4.14 HA cluster build requires extra setup time, but you get something a single server can't provide. You can lose a manager or an indexer node and keep collecting security events with no gap.

Once the certificates, manager cluster block, and three-node indexer are working, adding more capacity later just means repeating steps 3 and 5 with a new node name and IP.

We hope you enjoy this guide. For more detailed information, you can check the Wazuh indexer cluster certificate deployment documentation.