Before you pick a Wazuh installation method, decide whether this server will ever be more than one box. The installation assistant is the quickest route to a working SIEM, but it hides every decision it makes, and the first time you need to move the indexer to its own node or replace a certificate you end up reverse engineering a script you never read.
This guide is the Wazuh server installation on Ubuntu 24.04 LTS done step by step, the way the Wazuh documentation calls the manual method: we generate the certificates ourselves, then install and configure the Wazuh indexer, the Wazuh manager with Filebeat, and the Wazuh dashboard one package at a time. After that we lock the setup down with rotated passwords, a correctly sized and memory-locked indexer heap, password-protected agent enrollment, and file integrity monitoring pushed from the manager. We ran all of it on Ubuntu 24.04.4 LTS with Wazuh 4.14.8, so the outputs, timings and errors below are the ones we actually hit, and when we rechecked the Wazuh repository in November 2026 it was serving 4.14.9, which the version detection in the variables step picks up on its own. The one exception is public certificate issuance: our lab has no public IP, so we ran the certificate deploy hook against a locally signed certificate rather than a live Let’s Encrypt order. If you want the one-command route instead, the Wazuh all-in-one install on Ubuntu 26.04 uses the assistant and covers its quirks.
What a step-by-step Wazuh server installation gives you
Every component in this build gets its own certificate and its own node name, so the single server you end up with is already shaped like a cluster of one. That is the real reason to do it by hand, and it is worth the extra time only if growth is on the roadmap.

Agents reach the manager on 1514 for events and 1515 for enrollment, and the browser only ever touches the dashboard on 443. The detail that matters for later is that the indexer binds the LAN address of the server instead of loopback, and Filebeat and the manager reach it over TLS with their own certificate plus keystore credentials, so moving the indexer to another machine means editing a few hostnames rather than reinstalling. What you pay for that flexibility is about forty extra commands compared with the assistant, and every one of them is shown below with the output we got.
Size the server before you start
Wazuh load comes from two numbers: how many events per second your agents send, which drives manager CPU and indexer heap, and how many days of alerts you keep searchable, which drives disk. The Wazuh quickstart puts a single node serving up to 25 agents at 4 vCPU, 8 GB of RAM and 50 GB of disk for 90 days of alerts, and 51 to 100 agents at 8 vCPU, 8 GB and 200 GB. In practice we’d give a single node 16 GB as soon as it serves more than a few dozen chatty servers, because the indexer heap should be half the RAM and the manager, Filebeat and dashboard still need room next to it.
Our lab server was a 4 vCPU, 8 GB VM with a 60 GB disk named siem-eu-west-1a at 192.168.1.138, plus a 2 GB Ubuntu 24.04 VM called app-eu-west-1a at 192.168.1.171 as the agent. Treat that as a floor for following along, not a production recommendation. You also need a DNS name with an A record for the dashboard if you want a trusted certificate (any DNS provider works), and nothing else bound to port 443 on the server.
Work from a root shell and set the variables
Nearly every command in the Wazuh manual install runs as root and several of them pipe into tar or tee, so we do the server side from a root shell instead of prefixing everything with sudo:
sudo -i
Three values repeat through the whole build, so we set them once. HOST_IP is the address the components use to find each other, so use the LAN IP of the server from hostname -I, not 127.0.0.1. The version is detected from GitHub, filtered to the newest stable 4.x tag so release candidates never slip in, and WAZUH_MINOR is the matching branch on the Wazuh package server:
export HOST_IP="192.168.1.138"
export WAZUH_VER=$(curl -s "https://api.github.com/repos/wazuh/wazuh/releases?per_page=30" | grep -oE '"tag_name": "v4\.[0-9]+\.[0-9]+"' | grep -oE '4\.[0-9]+\.[0-9]+' | sort -V | tail -1)
export WAZUH_MINOR="${WAZUH_VER%.*}"
echo "IP: ${HOST_IP} Wazuh: ${WAZUH_VER} docs branch: ${WAZUH_MINOR}"
All three should be filled in before you continue:
IP: 192.168.1.138 Wazuh: 4.14.8 docs branch: 4.14
Exports do not survive a new SSH session, so if you reconnect halfway through, run sudo -i and this block again before picking up where you left off, along with ADMIN_PASS and SITE_DOMAIN once you reach the steps that set them. Refresh the package lists and install the packages the three components depend on while you’re here:
apt-get update && apt-get install -y debconf adduser procps curl gnupg apt-transport-https debhelper tar libcap2-bin
With the dependencies in place, the server is ready for the certificates every Wazuh component needs.
Generate the certificates for every node
Wazuh components only talk to each other over TLS, and the certificates tool builds a private CA plus one certificate per node from a small config.yml. Download both into the home directory of root, which is where every later command expects them to be:
cd /root
curl -sO "https://packages.wazuh.com/${WAZUH_MINOR}/wazuh-certs-tool.sh"
curl -sO "https://packages.wazuh.com/${WAZUH_MINOR}/config.yml"
The template names three nodes (node-1 for the indexer, wazuh-1 for the manager, dashboard for the web UI) and leaves their IPs as placeholders. On a single server all three get the same address, so one sed fills them in:
sed -i -e "s/<indexer-node-ip>/${HOST_IP}/g" -e "s/<wazuh-manager-ip>/${HOST_IP}/g" -e "s/<dashboard-node-ip>/${HOST_IP}/g" config.yml
grep -E 'name:|ip:' config.yml | grep -v '#'
Each active node now carries the server IP. The commented lines for node-2 and wazuh-2 are where a cluster would grow later:
- name: node-1
ip: "192.168.1.138"
- name: wazuh-1
ip: "192.168.1.138"
- name: dashboard
ip: "192.168.1.138"
Generate everything with -A, then pack it into one archive and delete the loose files:
bash ./wazuh-certs-tool.sh -A
tar -cvf ./wazuh-certificates.tar -C ./wazuh-certificates/ .
rm -rf ./wazuh-certificates
The tool finishes in about two seconds and prints one line per certificate it creates:
07/10/2026 23:01:54 INFO: Verbose logging redirected to /root/wazuh-certificates-tool.log
07/10/2026 23:01:54 INFO: Generating the root certificate.
07/10/2026 23:01:54 INFO: Generating Admin certificates.
07/10/2026 23:01:54 INFO: Admin certificates created.
07/10/2026 23:01:55 INFO: Generating Wazuh indexer certificates.
07/10/2026 23:01:55 INFO: Wazuh indexer certificates created.
07/10/2026 23:01:55 INFO: Generating Filebeat certificates.
07/10/2026 23:01:55 INFO: Wazuh Filebeat certificates created.
07/10/2026 23:01:55 INFO: Generating Wazuh dashboard certificates.
07/10/2026 23:01:56 INFO: Wazuh dashboard certificates created.
The archive holds root-ca.key, which can sign a certificate any Wazuh component will trust. Copy wazuh-certificates.tar somewhere safe off the server before you go further, because you need it again for every node you add.
Add the Wazuh APT repository
All four packages come from one repository, so import the signing key and add the source once for the whole server:
curl -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.gpg
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list
apt-get update
Confirm the candidate versions before installing anything, since the indexer, manager and dashboard must all match:
apt-cache policy wazuh-indexer wazuh-manager wazuh-dashboard filebeat | grep -E '^[a-z]|Candidate'
Filebeat stays on the OSS 7.10.2 build that Wazuh supports, while the three Wazuh packages share one version:
wazuh-indexer:
Candidate: 4.14.8-1
wazuh-manager:
Candidate: 4.14.8-1
wazuh-dashboard:
Candidate: 4.14.8-1
filebeat:
Candidate: 7.10.2-2
If the three Wazuh candidates show different versions, stop here and fix the repository before installing anything.
Install and initialize the Wazuh indexer
The indexer is the OpenSearch-based store for alerts and inventory, and it has to be running before anything else can connect to it. The package took 75 seconds to install on our VM:
apt-get -y install wazuh-indexer
The default opensearch.yml already names the node node-1 and lists it as the initial cluster manager, which matches our config.yml. The one value to change is network.host, which ships as 0.0.0.0. Pin it to the server IP so the indexer answers on the same address its certificate was issued for:
sed -i "s/^network.host: .*/network.host: \"${HOST_IP}\"/" /etc/wazuh-indexer/opensearch.yml
grep -E '^(network.host|node.name)' /etc/wazuh-indexer/opensearch.yml
Both lines should now read as follows, and the node name must match the name used in config.yml:
network.host: "192.168.1.138"
node.name: "node-1"
Unpack the certificate for this node, the admin certificate and the CA into the certs directory of the indexer. The renames matter, because the config expects the files to be called indexer.pem and indexer-key.pem:
NODE_NAME=node-1
mkdir /etc/wazuh-indexer/certs
tar -xf ./wazuh-certificates.tar -C /etc/wazuh-indexer/certs/ ./$NODE_NAME.pem ./$NODE_NAME-key.pem ./admin.pem ./admin-key.pem ./root-ca.pem
mv -n /etc/wazuh-indexer/certs/$NODE_NAME.pem /etc/wazuh-indexer/certs/indexer.pem
mv -n /etc/wazuh-indexer/certs/$NODE_NAME-key.pem /etc/wazuh-indexer/certs/indexer-key.pem
chmod 500 /etc/wazuh-indexer/certs
chmod 400 /etc/wazuh-indexer/certs/*
chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/certs
Start the service, then run the security init script once. It loads the users, roles and certificate DNs into the cluster, and nothing can log in until it has run:
systemctl daemon-reload
systemctl enable --now wazuh-indexer
/usr/share/wazuh-indexer/bin/indexer-security-init.sh
It ends with Done with success. Query the node with the default admin:admin credentials, which we rotate later. If the first call returns OpenSearch Security not initialized., wait five seconds and try again; we got that once, straight after the init finished:
curl -sk -u admin:admin "https://${HOST_IP}:9200"
curl -sk -u admin:admin "https://${HOST_IP}:9200/_cat/nodes?v"
The version field reports 7.10.2 for Filebeat compatibility, and the node list shows one node holding every role:
{
"name" : "node-1",
"cluster_name" : "wazuh-cluster",
"cluster_uuid" : "4uKsI1wbQFWyUoZ3XCvKjg",
"version" : {
"number" : "7.10.2",
"build_type" : "deb",
"build_hash" : "9f4796b8738969ac50ea8b6d23cdea5ce1a8565a",
"build_date" : "2026-09-18T11:18:26.846334859Z",
"build_snapshot" : false,
"lucene_version" : "9.12.3",
"minimum_wire_compatibility_version" : "7.10.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "The OpenSearch Project: https://opensearch.org/"
}
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role node.roles cluster_manager name
192.168.1.138 39 57 24 1.27 0.60 0.29 dimr cluster_manager,data,ingest,remote_cluster_client * node-1
The asterisk marks node-1 as the elected cluster manager, so the indexer is up as a cluster of one.
Install the Wazuh manager and Filebeat
The manager analyzes agent events and writes alerts, and Filebeat ships those alerts into the indexer. Install both:
apt-get -y install wazuh-manager
apt-get -y install filebeat
Wazuh publishes a ready Filebeat configuration for each release branch. Download it and point its output at the LAN address of the indexer instead of the default 127.0.0.1, which our indexer no longer listens on:
curl -so /etc/filebeat/filebeat.yml "https://packages.wazuh.com/${WAZUH_MINOR}/tpl/wazuh/filebeat/filebeat.yml"
sed -i "s/127.0.0.1:9200/${HOST_IP}:9200/" /etc/filebeat/filebeat.yml
After the edit, /etc/filebeat/filebeat.yml on our server read as follows:
# Wazuh - Filebeat configuration file
output.elasticsearch:
hosts: ["192.168.1.138:9200"]
protocol: https
username: ${username}
password: ${password}
ssl.certificate_authorities:
- /etc/filebeat/certs/root-ca.pem
ssl.certificate: "/etc/filebeat/certs/filebeat.pem"
ssl.key: "/etc/filebeat/certs/filebeat-key.pem"
setup.template.json.enabled: true
setup.template.json.path: '/etc/filebeat/wazuh-template.json'
setup.template.json.name: 'wazuh'
setup.ilm.overwrite: true
setup.ilm.enabled: false
filebeat.modules:
- module: wazuh
alerts:
enabled: true
archives:
enabled: false
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
permissions: 0644
logging.metrics.enabled: false
seccomp:
default_action: allow
syscalls:
- action: allow
names:
- rseq
The ${username} and ${password} placeholders resolve from a Filebeat keystore, so the credentials never sit in the YAML. Create it with the default credentials for now, then fetch the alerts index template for the exact manager version and install the Wazuh Filebeat module:
filebeat keystore create
echo admin | filebeat keystore add username --stdin --force
echo admin | filebeat keystore add password --stdin --force
curl -so /etc/filebeat/wazuh-template.json "https://raw.githubusercontent.com/wazuh/wazuh/v${WAZUH_VER}/extensions/elasticsearch/7.x/wazuh-template.json"
chmod go+r /etc/filebeat/wazuh-template.json
curl -s https://packages.wazuh.com/4.x/filebeat/wazuh-filebeat-0.5.tar.gz | tar -xvz -C /usr/share/filebeat/module
Filebeat authenticates to the indexer with the wazuh-1 certificate, renamed to the file names its config expects:
NODE_NAME=wazuh-1
mkdir /etc/filebeat/certs
tar -xf ./wazuh-certificates.tar -C /etc/filebeat/certs/ ./$NODE_NAME.pem ./$NODE_NAME-key.pem ./root-ca.pem
mv -n /etc/filebeat/certs/$NODE_NAME.pem /etc/filebeat/certs/filebeat.pem
mv -n /etc/filebeat/certs/$NODE_NAME-key.pem /etc/filebeat/certs/filebeat-key.pem
chmod 500 /etc/filebeat/certs
chmod 400 /etc/filebeat/certs/*
chown -R root:root /etc/filebeat/certs
The manager also talks to the indexer directly for vulnerability detection. It keeps its own keystore, and its ossec.conf points at https://0.0.0.0:9200 by default, which has to become the real indexer address:
echo admin | /var/ossec/bin/wazuh-keystore -f indexer -k username
echo admin | /var/ossec/bin/wazuh-keystore -f indexer -k password
sed -i "s|<host>https://0.0.0.0:9200</host>|<host>https://${HOST_IP}:9200</host>|" /var/ossec/etc/ossec.conf
Start both services and test the path from Filebeat to the indexer, which checks DNS, TLS and authentication in one go so that you do not have to debug them separately:
systemctl daemon-reload
systemctl enable --now wazuh-manager
systemctl enable --now filebeat
filebeat test output
Every stage should say OK, with full certificate chain verification enabled:
elasticsearch: https://192.168.1.138:9200...
parse url... OK
connection...
parse host... OK
dns lookup... OK
addresses: 192.168.1.138
dial up... OK
TLS...
security: server's certificate chain verification is enabled
handshake... OK
TLS version: TLSv1.3
dial up... OK
talk to server... OK
version: 7.10.2
One oddity if you run /var/ossec/bin/wazuh-control info: the stable manager package reports WAZUH_REVISION="rc2". It appears to be a build revision carried into the final package rather than a sign you pulled a release candidate, and WAZUH_VERSION="v4.14.8" on the line above it is the one that counts.
Install and wire up the Wazuh dashboard
The dashboard is the last package and the slowest to start:
apt-get -y install wazuh-dashboard
Its certificate goes in the same way as the others. These are the lines from the Wazuh documentation verbatim, including the guards that skip the rename if the file already exists:
NODE_NAME=dashboard
mkdir /etc/wazuh-dashboard/certs
tar -xf ./wazuh-certificates.tar -C /etc/wazuh-dashboard/certs/ ./$NODE_NAME.pem ./$NODE_NAME-key.pem ./root-ca.pem
[ ! -e /etc/wazuh-dashboard/certs/dashboard.pem ] && mv -n /etc/wazuh-dashboard/certs/$NODE_NAME.pem /etc/wazuh-dashboard/certs/dashboard.pem
[ ! -e /etc/wazuh-dashboard/certs/dashboard-key.pem ] && mv -n /etc/wazuh-dashboard/certs/$NODE_NAME-key.pem /etc/wazuh-dashboard/certs/dashboard-key.pem
chmod 500 /etc/wazuh-dashboard/certs
chmod 400 /etc/wazuh-dashboard/certs/*
chown -R wazuh-dashboard:wazuh-dashboard /etc/wazuh-dashboard/certs
Before starting it, fix the indexer address, because the package ships with opensearch.hosts: https://localhost:9200, and because our indexer binds the LAN IP, a dashboard left on localhost only returns Wazuh dashboard server is not ready yet with HTTP 503. We left it on the default first to see exactly that, and the error is listed at the end. Set it to the server IP so the dashboard talks to the same address the certificate covers:
sed -i "s|^opensearch.hosts: .*|opensearch.hosts: https://${HOST_IP}:9200|" /etc/wazuh-dashboard/opensearch_dashboards.yml
grep ^opensearch.hosts /etc/wazuh-dashboard/opensearch_dashboards.yml
The line now carries the LAN address:
opensearch.hosts: https://192.168.1.138:9200
Start the dashboard next. The file that tells it where the manager API lives, wazuh.yml, only appears after the first start, so point it at the manager afterwards and restart once more:
systemctl daemon-reload
systemctl enable --now wazuh-dashboard
for i in $(seq 1 60); do [ -f /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml ] && break; sleep 5; done
sed -i "s|url: https://localhost|url: https://${HOST_IP}|" /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
grep -E 'url:|port:' /usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml | grep -v '#'
systemctl restart wazuh-dashboard
The loop waits up to five minutes. If sed then reports that it cannot read wazuh.yml, the dashboard did not start, and journalctl -u wazuh-dashboard -n 50 shows why (a certificate permission or a typo in opensearch.hosts are the usual causes). The API entry now points at the manager on the LAN address:
url: https://192.168.1.138
port: 55000
The login page answered with HTTP 200 about 15 seconds after the restart on our VM.
All four packages are now installed. Disable the Wazuh repository so a routine apt upgrade cannot move the indexer, manager and dashboard out of step; you re-enable it on purpose when you plan an upgrade:
sed -i 's/^deb /#deb /' /etc/apt/sources.list.d/wazuh.list && apt-get update
grep wazuh /etc/apt/sources.list.d/wazuh.list
The grep shows the source line commented out:
#deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main
From now on an apt upgrade leaves the Wazuh packages alone until you uncomment that line.
Replace the default passwords
At this point the indexer admin account is still admin:admin and the API users carry their default passwords too, so this step is not optional on anything that is reachable from another machine. The passwords tool rotates every internal user and the two API users in one run, and the --admin-user wazuh --admin-password wazuh pair is the default API admin it authenticates with:
/usr/share/wazuh-indexer/plugins/opensearch-security/tools/wazuh-passwords-tool.sh --api --change-all --admin-user wazuh --admin-password wazuh
It prints each new password once, so copy them into your password manager immediately (masked here):
07/10/2026 23:15:35 INFO: Updating the internal users.
07/10/2026 23:15:38 INFO: A backup of the internal users has been saved in the /etc/wazuh-indexer/internalusers-backup folder.
07/10/2026 23:15:47 INFO: The filebeat.yml file has been updated to use the Filebeat Keystore username and password.
07/10/2026 23:16:08 INFO: The password for user admin is ********
07/10/2026 23:16:08 INFO: The password for user anomalyadmin is ********
07/10/2026 23:16:08 INFO: The password for user kibanaserver is ********
07/10/2026 23:16:08 INFO: The password for user kibanaro is ********
07/10/2026 23:16:08 INFO: The password for user logstash is ********
07/10/2026 23:16:08 INFO: The password for user readall is ********
07/10/2026 23:16:08 INFO: The password for user snapshotrestore is ********
07/10/2026 23:16:08 WARNING: Wazuh indexer passwords changed. Remember to update the password in the Wazuh dashboard, Wazuh server, and Filebeat nodes if necessary, and restart the services.
07/10/2026 23:16:11 INFO: The password for Wazuh API user wazuh is ********
07/10/2026 23:16:12 INFO: The password for Wazuh API user wazuh-wui is ********
07/10/2026 23:16:12 INFO: Updated wazuh-wui user password in wazuh dashboard. Remember to restart the service.
On a single node the tool also updates everything that stores those passwords: the Filebeat keystore, the manager keystore that vulnerability detection reads, and the dashboard keystore and wazuh-wui entry. We restarted the three services anyway so they pick up the new values together, then checked the cluster with the new admin password. Set ADMIN_PASS to the value the tool printed for admin, since later steps use it:
export ADMIN_PASS='paste-the-new-admin-password-here'
systemctl restart filebeat wazuh-manager wazuh-dashboard
curl -sk -u "admin:${ADMIN_PASS}" "https://${HOST_IP}:9200/_cluster/health?pretty" | grep -E 'status|number_of_nodes'
curl -sk -o /dev/null -w 'admin:admin -> %{http_code}\n' -u admin:admin "https://${HOST_IP}:9200"
The cluster is green under the new password, and the old default is refused:
"status" : "green",
"number_of_nodes" : 1,
admin:admin -> 401
If you want to manage the indexer users afterwards, our walkthrough on creating and updating OpenSearch users applies to the Wazuh indexer as well, since it is the same security plugin.
Open the firewall and log in
UFW is installed but inactive on Ubuntu 24.04, so allow SSH first to make sure enabling it does not cut your session, then allow the dashboard and the two agent ports. The OpenSSH profile covers port 22 only, so if SSH listens elsewhere add a line such as ufw allow 2222/tcp with your port before the enable, and open the same ports in any cloud security group in front of the server:
ufw allow OpenSSH
ufw allow 443/tcp comment 'Wazuh dashboard'
ufw allow 1514/tcp comment 'Wazuh agent events'
ufw allow 1515/tcp comment 'Wazuh agent enrollment'
ufw --force enable
ufw status
The status listing should show SSH plus the three Wazuh ports and nothing else:
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
443/tcp ALLOW Anywhere # Wazuh dashboard
1514/tcp ALLOW Anywhere # Wazuh agent events
1515/tcp ALLOW Anywhere # Wazuh agent enrollment
Port 9200 and 55000 stay closed because every consumer of them lives on this host. When you split the indexer out later, open 9200 to the manager and dashboard nodes only, not to the world.
Browse to https://192.168.1.138 for now (after the certificate step you switch to the DNS name) and sign in as admin with the new password. Under Server management > Status you can confirm every daemon the single node needs is running. The red ones (cluster, mail, integrator, agentless, report, csyslog) are off by default and stay off until you enable those features:

That screenshot was taken after the agent from the next sections enrolled, and that is why it already shows one active agent.
Size the indexer heap and lock its memory
A fresh package install leaves the indexer at a 1 GB heap, which is fine for the first boot and nowhere near enough once agents are writing. The rule is half the RAM, Xms equal to Xmx, and the heap locked into memory so it never swaps. On our 8 GB server that’s 4 GB, which is also the largest value we would run next to the other components. Locking needs a systemd override as well as the setting in opensearch.yml:
sed -i '$a bootstrap.memory_lock: true' /etc/wazuh-indexer/opensearch.yml
mkdir -p /etc/systemd/system/wazuh-indexer.service.d/
printf '[Service]\nLimitMEMLOCK=infinity\n' | tee /etc/systemd/system/wazuh-indexer.service.d/wazuh-indexer.conf
sed -i -e 's/^-Xms1g/-Xms4g/' -e 's/^-Xmx1g/-Xmx4g/' /etc/wazuh-indexer/jvm.options
systemctl daemon-reload
systemctl restart wazuh-indexer
We use sed '$a' rather than echo ... >> on purpose. The shipped opensearch.yml has no trailing newline, so an append glues the new setting onto the last line and the indexer refuses to start. That cost us a failed restart, and the exact error is in the troubleshooting list. Once it’s back up, check that the lock took and the heap is the size you asked for:
curl -sk -u "admin:${ADMIN_PASS}" "https://${HOST_IP}:9200/_nodes?filter_path=**.mlockall&pretty"
curl -sk -u "admin:${ADMIN_PASS}" "https://${HOST_IP}:9200/_cat/nodes?v&h=name,heap.max,heap.percent,ram.percent"
Both read as expected, with the lock active and a 4 GB heap:
{
"nodes" : {
"CIXB1AQuQmCZf9iFbAWpRA" : {
"process" : {
"mlockall" : true
}
}
}
}
name heap.max heap.percent ram.percent
node-1 4gb 14 98
The cost angle: with the heap locked, free -m on our 8 GB host dropped from 5.3 GB available to 2.1 GB, and the resident memory of the indexer went from 1.6 GB to 4.9 GB, while the dashboard, wazuh-modulesd, Filebeat and wazuh-analysisd together held about 450 MB. That’s why we’d move to 16 GB well before the quickstart table says you have to.

We took that capture at the end of the build, so it already shows the agent you enroll in a later section. The check combines the heap, the Filebeat path and the agent list in one place, and it is a health snapshot we would keep as a small script that runs after every upgrade.
Serve the dashboard with a Let’s Encrypt certificate
The dashboard certificate we generated is signed by our private CA, so browsers warn on every visit. Because the dashboard terminates TLS itself on 443 and nothing on the server uses port 80, certbot can run its own HTTP-01 listener and a deploy hook can copy the result into place. Set the DNS name first; its A record must already point at a public address of this server:
export SITE_DOMAIN="siem.example.com"
Open port 80, install certbot and request the certificate with your own email. If port 80 cannot be reached from the internet, skip to the DNS-01 alternative below instead:
ufw allow 80/tcp comment 'Lets Encrypt HTTP-01'
apt-get install -y certbot
certbot certonly --standalone -d "${SITE_DOMAIN}" --non-interactive --agree-tos -m [email protected]
This build names the dashboard files dashboard.pem and dashboard-key.pem, which you can confirm with grep ^server.ssl /etc/wazuh-dashboard/opensearch_dashboards.yml. Create a deploy hook that overwrites them and restarts the dashboard:
vim /etc/letsencrypt/renewal-hooks/deploy/wazuh-dashboard-cert.sh
Add the following:
#!/bin/bash
set -euo pipefail
CERT_DIR=/etc/wazuh-dashboard/certs
install -m 400 -o wazuh-dashboard -g wazuh-dashboard "${RENEWED_LINEAGE}/fullchain.pem" "${CERT_DIR}/dashboard.pem"
install -m 400 -o wazuh-dashboard -g wazuh-dashboard "${RENEWED_LINEAGE}/privkey.pem" "${CERT_DIR}/dashboard-key.pem"
systemctl restart wazuh-dashboard
Make it executable, run it once against the new certificate, and dry-run a renewal so you know the timer will work in 60 days:
chmod 755 /etc/letsencrypt/renewal-hooks/deploy/wazuh-dashboard-cert.sh
RENEWED_LINEAGE="/etc/letsencrypt/live/${SITE_DOMAIN}" /etc/letsencrypt/renewal-hooks/deploy/wazuh-dashboard-cert.sh
certbot renew --dry-run
Keep root-ca.pem where it is, since the dashboard still uses it to verify the indexer. Only the browser-facing certificate changes, so from now on open the dashboard as https://siem.example.com; the bare IP gives a name mismatch.
Alternative: DNS-01 when port 80 isn’t reachable
A server on a private network or behind NAT cannot answer HTTP-01, so certbot proves ownership through a DNS TXT record instead, and you can skip the port 80 rule. Set SITE_DOMAIN as above, then install the plugin for your DNS provider (python3-certbot-dns-cloudflare, -route53, -digitalocean, -google or -rfc2136 for your own BIND). The Cloudflare example below works the same way for the others with their package, flag and credentials file. Create a root-only directory for the credentials:
mkdir -p -m 700 /root/.secrets
Then the credentials file itself:
vim /root/.secrets/cloudflare.ini
It holds one line, an API token that can edit DNS for the zone:
dns_cloudflare_api_token = your-token-here
Lock it down and request the certificate with the plugin flag in place of --standalone:
chmod 600 /root/.secrets/cloudflare.ini
apt-get install -y python3-certbot-dns-cloudflare
certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d "${SITE_DOMAIN}" --non-interactive --agree-tos -m [email protected]
Then create the same deploy hook and run it once, exactly as in the HTTP-01 path. When DNS-01 fails, the cause is nearly always an API token that can’t edit the zone, whereas HTTP-01 failures come down to port 80 being blocked upstream or the A record not resolving yet.
Require a password for agent enrollment
By default wazuh-authd registers any machine that can reach port 1515, which on a flat network means anyone can add an agent and flood the manager. A shared enrollment password closes that. Generate one, store it where authd looks, and switch the option on:
openssl rand -hex 16 > /var/ossec/etc/authd.pass
chmod 640 /var/ossec/etc/authd.pass
chown root:wazuh /var/ossec/etc/authd.pass
sed -i 's|<use_password>no</use_password>|<use_password>yes</use_password>|' /var/ossec/etc/ossec.conf
systemctl restart wazuh-manager
grep -i "password" /var/ossec/logs/ossec.log | tail -2
The log shows authd before and after the change, and the second line is the one you want to see:
2026/10/07 23:16:37 wazuh-authd: INFO: Accepting connections on port 1515. No password required.
2026/10/07 23:26:17 wazuh-authd: INFO: Accepting connections on port 1515. Using password specified on file: etc/authd.pass
Run cat /var/ossec/etc/authd.pass and keep the value handy for the agent.
Enroll an Ubuntu agent with the password
Switch to the machine you want to monitor, because everything in this section happens on the agent. These commands run as a normal user with sudo. Pin the agent to the manager version, which you can read on the server with dpkg-query -W -f='${Version}\n' wazuh-manager (ours printed 4.14.8-1), then add the same repository and install the agent, passing the manager address and a name at install time:
export WAZUH_AGENT_VER="4.14.8-1" #https://github.com/wazuh/wazuh/releases
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import
sudo chmod 644 /usr/share/keyrings/wazuh.gpg
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | sudo tee /etc/apt/sources.list.d/wazuh.list
sudo apt-get update
sudo WAZUH_MANAGER="192.168.1.138" WAZUH_AGENT_NAME="app-eu-west-1a" apt-get install -y wazuh-agent="${WAZUH_AGENT_VER}"
The package does not start the agent, which gives you a window to drop the enrollment password in first, and that is exactly what we want here. Put the value from the manager into the authd.pass file on the agent, which uses the same path as the manager:
echo "paste-the-enrollment-password-here" | sudo tee /var/ossec/etc/authd.pass >/dev/null
sudo chmod 640 /var/ossec/etc/authd.pass
sudo chown root:wazuh /var/ossec/etc/authd.pass
sudo systemctl daemon-reload
sudo systemctl enable --now wazuh-agent
Within a few seconds the agent log shows the key exchange and the connection on 1514:
sudo grep -E "Valid key|Connected to the server" /var/ossec/logs/ossec.log | tail -2
The two lines you are looking for:
2026/10/07 23:27:53 wazuh-agentd: INFO: Valid key received
2026/10/07 23:28:13 wazuh-agentd: INFO: (4102): Connected to the server ([192.168.1.138]:1514/tcp).
Wazuh supports agents on the same version as the manager or older, never newer, so stop the agent from moving ahead on a routine upgrade by disabling its repository now:
sudo sed -i 's/^deb /#deb /' /etc/apt/sources.list.d/wazuh.list && sudo apt-get update
We started our first agent without the file on purpose, and it did not fail quietly: it retried every few seconds with Invalid password. Unable to add agent (from manager) until the file was in place, so a typo here fails loudly rather than silently. Under Agents management > Summary the dashboard lists the agent as active, with its operating system and version picked up from the first keepalive:

For more than a handful of hosts, the Ansible Wazuh deployment writes authd.pass and installs the agent across an inventory, and the Rocky Linux and AlmaLinux setup covers RPM-based agents.
Push file integrity monitoring from the manager
Syscheck can only watch and baseline a directory that exists, so create the test directory and a starting config file on the agent first:
sudo mkdir -p /opt/app/config
echo "db_host=10.0.2.15" | sudo tee /opt/app/config/app.ini
Editing ossec.conf on each agent does not scale past a few hosts, and it is easy for one host to drift from the rest. Agent groups solve it: anything in /var/ossec/etc/shared/default/agent.conf on the manager is synced to every agent in the default group. We’ll watch an application config directory in real time, with content diffs. Back on the manager, still in the root shell:
vim /var/ossec/etc/shared/default/agent.conf
Replace the placeholder content with the following block, which watches one directory:
<agent_config>
<syscheck>
<directories realtime="yes" check_all="yes" report_changes="yes">/opt/app/config</directories>
</syscheck>
</agent_config>
Validate the file before the agents pull it, because a broken shared config can stop them reloading:
/var/ossec/bin/verify-agent-conf
A clean file prints OK:
verify-agent-conf: Verifying [etc/shared/default/agent.conf]
verify-agent-conf: OK
Our agent picked the change up about 15 seconds later and restarted its syscheck module on its own. Check the agent log to confirm the directory is under real-time monitoring:
sudo grep "/opt/app/config" /var/ossec/logs/ossec.log
Both lines should appear:
2026/10/07 23:28:56 wazuh-syscheckd: INFO: (6003): Monitoring path: '/opt/app/config', with options 'size | permissions | owner | group | mtime | inode | hash_md5 | hash_sha1 | hash_sha256 | report_changes | realtime'.
2026/10/07 23:28:56 wazuh-syscheckd: INFO: (6016): Directory set for real time monitoring: '/opt/app/config'.
Give the agent a few seconds to record its baseline, then change the existing file and create a new one:
echo "db_host=203.0.113.66" | sudo tee /opt/app/config/app.ini
echo "debug=true" | sudo tee /opt/app/config/override.ini
Both events reached the manager within a second. On the manager, pull them out of the current alerts.json:
grep -E '"id":"(550|554)"' /var/ossec/logs/alerts/alerts.json | python3 -c 'import sys,json; [print(a["timestamp"], a["agent"]["name"], a["rule"]["id"], a["rule"]["level"], a["syscheck"]["event"], a["syscheck"]["path"], repr(a["syscheck"].get("diff", ""))) for a in map(json.loads, sys.stdin)]' | tail -2
Rule 550 flags the modified file at level 7 and carries the diff, while rule 554 reports the new file at level 5:
2026-10-08T00:20:55.829+0000 app-eu-west-1a 550 7 modified /opt/app/config/app.ini '1c1\n< db_host=10.0.2.15\n---\n> db_host=203.0.113.66\n'
2026-10-08T00:20:55.871+0000 app-eu-west-1a 554 5 added /opt/app/config/override.ini ''
In the dashboard, open Endpoint security > File Integrity Monitoring and switch to the Events tab to see the same two changes. This capture is from our first FIM run, a few minutes before the command-line run above:

Real-time mode uses inotify, so keep it on directories that change rarely. For busy paths, the default scheduled scan is cheaper on the agent.
Errors we hit during the manual install
[ConnectionError]: connect ECONNREFUSED ::1:9200
This filled the dashboard journal while the browser showed Wazuh dashboard server is not ready yet (HTTP 503). The dashboard still had the packaged opensearch.hosts: https://localhost:9200, localhost resolved to IPv6 ::1, and our indexer only listens on the LAN address. Setting opensearch.hosts to https://${HOST_IP}:9200 and restarting fixed it. The same applies to Filebeat and the manager <indexer> block, which is why we changed all three.
Caused by: mapping values are not allowed here
The indexer failed to start right after we enabled memory locking. The journal pointed at the end of the file:
Caused by: mapping values are not allowed here
in 'reader', line 42, column 72:
... rsion: truebootstrap.memory_lock: true
We had appended the setting with tee -a, and because opensearch.yml ships without a trailing newline it landed on the same line as compatibility.override_main_response_version: true. Split the line by hand, or use sed -i '$a ...' as shown above, which adds the newline for you.
ERROR: Invalid password. Unable to add agent (from manager)
The agent log repeats this every few seconds when the manager requires a password and the agent has none, or a different one. Put the exact value from /var/ossec/etc/authd.pass on the manager into the same path on the agent and restart wazuh-agent; the next attempt prints Valid key received.
OpenSearch Security not initialized.
Returned once by our first curl to port 9200, issued in the same second that indexer-security-init.sh finished. It cleared on retry five seconds later, so treat it as a timing issue first. If it persists, the init script didn’t run or failed, so run it again and read its output.
Scaling path: from one node to a real cluster
The reason we built this by hand pays off here. When one server stops being enough, the indexer is almost always the first thing to outgrow it, because heap and disk grow with retention while manager CPU grows with event rate, and those rarely peak together. Our recommended order of operations, based on which part usually runs out of headroom first, looks like this:
- Move the indexer first. Add a
node-2entry toconfig.yml, generate its certificate with the same CA, installwazuh-indexeron the new host and add it todiscovery.seed_hosts,cluster.initial_master_nodesandplugins.security.nodes_dn. Point Filebeat, the manager<indexer>block andopensearch.hostsat the new addresses. - Go to three indexer nodes, not two. Two nodes cannot hold a quorum after one fails, so we’d skip straight to three identically sized nodes on a low-latency network, since the cluster runs at the pace of its slowest member.
- Add manager workers when event rate climbs. Enable the
<cluster>block with a shared 32-character key fromopenssl rand -hex 16, make this server the master, and put a TCP load balancer in front of 1514 and 1515 so agents spread across the nodes. Workers forward enrollment requests to the master, so 1515 can sit behind the same balancer. - Keep the dashboard light. It rarely needs its own box until you have many concurrent analysts, so it can stay with the master manager for a long time.
The cost angle is straightforward: three 16 GB indexer nodes plus a manager pair is roughly five times the spend of this single server, so we’d only make that move once retention or ingest has demonstrably outgrown one 16 GB node. Until then, the setup above with a bigger heap and a retention policy will carry a surprising number of agents, and if you also need log search outside Wazuh, Graylog on Ubuntu can share the same certificate habits. For the detection theory and SOC workflow this build leaves out, our picks of books on SIEM and Wazuh are where we’d start reading. Whichever way you grow, keep the repository commented out between planned upgrades and upgrade the indexer, then the manager, then the dashboard, with agents last.
Very nice how to, but I did run into a problem. At the kibana install, after I downloaded the config, I ran
sudo chown -R kibana:kibana /usr/share/kibana/optimize
I get “chown: cannot access ‘/usr/share/kibana/optimize’: No such file or directory”
But I think more importantly when I try in download the plugin with’
cd /usr/share/kibana
sudo -u kibana /usr/share/kibana/bin/kibana-plugin install https://packages.wazuh.com/4.x/ui/kibana/wazuh_kibana-4.0.4_7.9.1-1.zip
I get,
Plugin installation was unsuccessful due to error “No kibana plugins found in archive”
Any thought on how to get this plugin installed?
Thanks
Hi Dan, check the updated link for the plugin in the article.
For me, “sudo systemctl enable –now elasticsearch” results in:
Synchronizing state of elasticsearch.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable elasticsearch
Job for elasticsearch.service failed because a timeout was exceeded.
See “systemctl status elasticsearch.service” and “journalctl -xe” for details.
HI,
I am getting following ERROR how to proceed to next step
wazuh@wazuh:/home$ sudo mkdir /etc/elasticsearch/certs && cd /etc/elasticsearch/certs
bash: cd: /etc/elasticsearch/certs: Permission denied
This is now fixed. Follow along updated contents.
i am stucked on this stage as well. could you advise please?
See updated guide
HI,
I am getting following error
wazuh@wazuh:/etc/elasticsearch/certs$ sudo systemctl enable –now elasticsearch Synchronizing state of elasticsearch.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable elasticsearch
Job for elasticsearch.service failed because a timeout was exceeded.
See “systemctl status elasticsearch.service” and “journalctl -xe” for details.
wazuh@wazuh:/etc/elasticsearch/certs$ systemctl status elasticsearch.service
● elasticsearch.service – Elasticsearch
Loaded: loaded (/lib/systemd/system/elasticsearch.service; enabled; vendor preset: enabled)
Active: failed (Result: timeout) since Tue 2022-02-15 04:57:03 UTC; 16s ago
Docs: https://www.elastic.co
Process: 77555 ExecStart=/usr/share/elasticsearch/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid –quiet (code=exited, sta>
Main PID: 77555 (code=exited, status=143)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:161)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareComm>
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:127)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.cli.Command.main(Command.java:90)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:126)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:92)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: For complete error details, refer to the log at /var/log/elasticsearch/elasticsearch.>
Feb 15 04:57:03 wazuh systemd[1]: elasticsearch.service: start operation timed out. Terminating.
Feb 15 04:57:03 wazuh systemd[1]: elasticsearch.service: Failed with result ‘timeout’.
Feb 15 04:57:03 wazuh systemd[1]: Failed to start Elasticsearch.
lines 1-17/17 (END)
● elasticsearch.service – Elasticsearch
Loaded: loaded (/lib/systemd/system/elasticsearch.service; enabled; vendor preset: enabled)
Active: failed (Result: timeout) since Tue 2022-02-15 04:57:03 UTC; 16s ago
Docs: https://www.elastic.co
Process: 77555 ExecStart=/usr/share/elasticsearch/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid –quiet (code=exited, stat>
Main PID: 77555 (code=exited, status=143)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:161)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareComma>
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:127)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.cli.Command.main(Command.java:90)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:126)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:92)
Feb 15 04:55:57 wazuh systemd-entrypoint[77555]: For complete error details, refer to the log at /var/log/elasticsearch/elasticsearch.l>
Feb 15 04:57:03 wazuh systemd[1]: elasticsearch.service: start operation timed out. Terminating.
Feb 15 04:57:03 wazuh systemd[1]: elasticsearch.service: Failed with result ‘timeout’.
Feb 15 04:57:03 wazuh systemd[1]: Failed to start Elasticsearch.
try updated article and let us know if it works for you.
Hi,
I am getting following error
wazuhadmin@wazuh:/home$ sudo mkdir /etc/elasticsearch/certs && cd /etc/elasticsearch/certs
bash: cd: /etc/elasticsearch/certs: Permission denied
wazuhadmn@wazuh:/home$
Thank you
Please check updated post.
al reiniciar mi servidor no cargar mi la interfaz web del wazuh, que puede estar pasando.
¿Verificó el estado de su servicio después de reiniciar el servidor y si está vinculado al puerto?
Seguramente que elasticsearch no está activo:
sudo systemctl status elasticsearch
Si sale inactivo o con algún error entonces:
sudo systemctl restart elasticsearch
Y ya podrá acceder a la interfaz web
Un saludo
Hello,
I get the error that the wazuh api is offline (invalid credentials)
All is started do you have any idea?
I get this error: INFO: Checking API host id [default]…
INFO: Could not connect to API id [default]: 3099 – ERROR3099 – Invalid credentials
I get to:
Run the Elasticsearch securityadmin script to load the new certificates information and start the cluster:
export JAVA_HOME=/usr/share/elasticsearch/jdk/ && /usr/share/elasticsearch/plugins/opendistro_security/tools/securityadmin.sh -cd /usr/share/elasticsearch/plugins/opendistro_security/securityconfig/ -nhnv -cacert /etc/elasticsearch/certs/root-ca.pem -cert /etc/elasticsearch/certs/admin.pem -key /etc/elasticsearch/certs/admin-key.pem
And get:
Open Distro Security Admin v7
Will connect to localhost:9300 … done
18:49:26.405 [elasticsearch[_client_][transport_worker][T#1]] ERROR com.amazon.opendistroforelasticsearch.security.ssl.transport.OpenDistroSecuritySSLNettyTransport – Exception during establishing a SSL connection: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[?:?]
at sun.security.ssl.TransportContext.fatal(TransportContext.java:369) ~[?:?]
at sun.security.ssl.TransportContext.fatal(TransportContext.java:312) ~[?:?]
at sun.security.ssl.TransportContext.fatal(TransportContext.java:307) ~[?:?]
at sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357) ~[?:?]
at sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232) ~[?:?]
at sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175) ~[?:?]
at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396) ~[?:?]
at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:480) ~[?:?]
at sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1267) ~[?:?]
at sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1254) ~[?:?]
at java.security.AccessController.doPrivileged(AccessController.java:691) ~[?:?]
at sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1199) ~[?:?]
at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1542) ~[netty-handler-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1556) ~[netty-handler-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1440) ~[netty-handler-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1267) ~[netty-handler-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1314) ~[netty-handler-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501) ~[netty-codec-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440) ~[netty-codec-4.1.49.Final.jar:4.1.49.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) [netty-transport-4.1.49.Final.jar:4.1.49.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) [netty-common-4.1.49.Final.jar:4.1.49.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.49.Final.jar:4.1.49.Final]
at java.lang.Thread.run(Thread.java:832) [?:?]
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439) ~[?:?]
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) ~[?:?]
at sun.security.validator.Validator.validate(Validator.java:264) ~[?:?]
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:285) ~[?:?]
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) ~[?:?]
at sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1335) ~[?:?]
… 31 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[?:?]
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[?:?]
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[?:?]
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434) ~[?:?]
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) ~[?:?]
at sun.security.validator.Validator.validate(Validator.java:264) ~[?:?]
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:285) ~[?:?]
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) ~[?:?]
at sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1335) ~[?:?]
… 31 more
ERR: Cannot connect to Elasticsearch. Please refer to elasticsearch logfile for more information
Trace:
NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{-efRmOx6SQmGbg5Z3hRirA}{localhost}{127.0.0.1:9300}]]
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:352)
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:248)
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:57)
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:391)
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:412)
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:401)
at com.amazon.opendistroforelasticsearch.security.tools.OpenDistroSecurityAdmin.execute(OpenDistroSecurityAdmin.java:524)
at com.amazon.opendistroforelasticsearch.security.tools.OpenDistroSecurityAdmin.main(OpenDistroSecurityAdmin.java:157)
Hi, I’m not getting any data from the agents, only the inventory, but non file integrity events, someone have the solution?
I am also getting an error when trying to start elastic search daemon. I never liked elastic search, it is a pain to get it up and running no matter in what format.
× elasticsearch.service – Elasticsearch
Loaded: loaded (/lib/systemd/system/elasticsearch.service; enabled; preset:
enabled)
Active: failed (Result: timeout) since Sat 2024-04-13 15:14:09 CEST; 16s ago
Docs: https://www.elastic.co
Process: 1339431 ExecStart=/usr/share/elasticsearch/bin/systemd-entrypoint -p ${PID_DIR}/elasticsearch.pid –quiet (code=exited, status=143)
Main PID: 1339431 (code=exited, status=143)
CPU: 30.801s
Apr 13 15:13:02 systemd-entrypoint[1339431]: at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:86)
Apr 13 15:13:02 systemd-entrypoint[1339431]: at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:127)
Apr 13 15:13:02 systemd-entrypoint[1339431]: at org.elasticsearch.cli.Command.main(Command.java:90)
Apr 13 15:13:02 systemd-entrypoint[1339431]: at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:126)
Apr 13 15:13:02 systemd-entrypoint[1339431]: at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:92)
Apr 13 15:13:02 systemd-entrypoint[1339431]: For complete error details, refer to the log at /var/log/elasticsearch/elasticsearch.log
Apr 13 15:14:09 systemd[1]: elasticsearch.service: start operation timed out. Terminating.
Apr 13 15:14:09 systemd[1]: elasticsearch.service: Failed with result ‘timeout’.
Apr 13 15:14:09 systemd[1]: Failed to start elasticsearch.service – Elasticsearch.
Apr 13 15:14:09 systemd[1]: elasticsearch.service: Consumed 30.801s CPU time.
and the logfile as instructed in systemctl status is not there