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:
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:
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:
Paste this with your own names and IP addresses, then save and exit:
1nodes:2 3 indexer:4 - name: indexer-15 ip: "10.0.0.11"6 - name: indexer-27 ip: "10.0.0.12"8 - name: indexer-39 ip: "10.0.0.13"10 11 12 server:13 - name: manager-114 ip: "10.0.0.21"15 node_type: master16 - name: manager-217 ip: "10.0.0.22"18 node_type: worker19 20 21 dashboard:22 - name: dashboard-123 ip: "10.0.0.31"
Generate all certificates in one run with the command below:
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:
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:
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:
nano /etc/wazuh-indexer/opensearch.yml
On indexer-1, replace the relevant lines with:
1network.host: "10.0.0.11"2node.name: "indexer-1"3cluster.initial_master_nodes:4 - "indexer-1"5 - "indexer-2"6 - "indexer-3"7discovery.seed_hosts:8 - "10.0.0.11"9 - "10.0.0.12"10 - "10.0.0.13"11plugins.security.nodes_dn:12 - "CN=indexer-1,OU=Wazuh,O=Wazuh,L=California,C=US"13 - "CN=indexer-2,OU=Wazuh,O=Wazuh,L=California,C=US"14 - "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:
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:
nano /etc/wazuh-indexer/jvm.options
Change these two lines, example for a 16 GB node:
Start the service on each of the three nodes:
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:
/usr/share/wazuh-indexer/bin/indexer-security-init.sh
Confirm all three nodes joined correctly:
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:
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:
Copy the output somewhere safe, then open the manager config file on manager-1 (the master):
nano /var/ossec/etc/ossec.conf
Add this <cluster> block anywhere inside the <ossec_config> tags, then save and exit:
<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):
nano /var/ossec/etc/ossec.conf
Use the same key and cluster name, but change the node identity and role:
<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:
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:
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:
nano /etc/filebeat/filebeat.yml
Set the output block like this, then save and exit:
1output.elasticsearch:2 hosts: ["10.0.0.11:9200", "10.0.0.12:9200", "10.0.0.13:9200"]3 protocol: https
You can store the indexer admin credentials in the Filebeat keystore instead of plain text:
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:
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:
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:
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:
nano /etc/wazuh-dashboard/opensearch_dashboards.yml
Point it at your indexer cluster with:
opensearch.hosts: https://10.0.0.11:9200
Save and exit, then open the Wazuh app config file:
nano /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
Point it at your manager cluster's master node:
1hosts:2 - default:3 url: https://10.0.0.214 port: 550005 username: wazuh-wui6 password: <WAZUH-WUI-PASSWORD>7 run_as: false
Start the dashboard and browse to https://10.0.0.31:
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:
nano /var/ossec/etc/ossec.conf
Add this block inside the existing <cluster> block on the master node:
<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:
nano /var/ossec/etc/ossec.conf
List every manager node so the agent can fail over if one is unreachable:
1<client>2 <server>3 <address>10.0.0.21</address>4 <port>1514</port>5 </server>6 <server>7 <address>10.0.0.22</address>8 <port>1514</port>9 </server>10</client>
Save, exit, and restart the agent service:
systemctl restart wazuh-agent
Step 9: Verify the Cluster Is Working
At this point, you can confirm both manager nodes see each other:
/var/ossec/bin/cluster_control -l
Expected output shows both nodes with a version and role:
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:
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:
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:
systemctl stop wazuh-indexer
Run the cluster health check again:
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.