Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Wazuh Ubuntu
GUIDEInstall Guides

How to Install Wazuh on Ubuntu 24.04 VPS: Open-Source SIEM & XDR for Self-Hosted Security

28 min read

How to Install Wazuh on Ubuntu 24.04 VPS: Open-Source SIEM & XDR for Self-Hosted Security

If your security stack currently stops at fail2ban and a few grep pipelines on /var/log/auth.log, you are only seeing a fraction of what happens on your servers. A proper Security Information and Event Management (SIEM) platform correlates logs across every host, flags anomalies against rule libraries, maps detections to MITRE ATT&CK tactics, and triggers automated response actions — all from a single dashboard. Wazuh is the leading open-source SIEM/XDR and the most practical way to get enterprise-grade detection without an enterprise-grade invoice.

This guide walks you through installing Wazuh 4.x on a single Ubuntu 24.04 LTS VPS, enrolling Linux and Windows agents, enabling file integrity monitoring, vulnerability detection, and MITRE ATT&CK rule mappings, wiring up integrations with Slack, VirusTotal, and Shuffle SOAR, publishing the dashboard behind Nginx with TLS, and setting up a solid backup routine.

Want the managed platform instead? Deploy a hardened Ubuntu 24.04 VPS sized for SIEM workloads in a couple of clicks. CloudCore Business on vps-server.host gives you the CPU, RAM, and NVMe headroom Wazuh's indexer actually needs.

Table of Contents

  • What is Wazuh?
  • Why Self-Host a SIEM Instead of Paying for Splunk or Elastic Cloud?
  • Prerequisites
  • Step 1: Prepare Ubuntu 24.04
  • Step 2: Install Wazuh (All-in-One with wazuh-install.sh)
  • Step 2 (Alternative): Install Wazuh with Docker Compose
  • Step 3: First Dashboard Login
  • Step 4: Enroll Linux Agents
  • Step 5: Enroll Windows Agents
  • Step 6: Tune Rules and Decoders
  • Step 7: Enable File Integrity Monitoring (FIM)
  • Step 8: Enable Vulnerability Detection
  • Step 9: Use the MITRE ATT&CK Module
  • Step 10: Configure Active Response
  • Step 11: Integrations — Slack, VirusTotal, Shuffle SOAR
  • Step 12: Publish the Dashboard Behind Nginx + TLS
  • Step 13: Backups and Upgrades
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Wazuh?

    Wazuh is an open-source security platform originally forked from OSSEC that has grown into a full SIEM and XDR. It ingests logs from agents and cloud APIs, applies thousands of correlation rules, stores events in a Wazuh Indexer (an OpenSearch fork), and surfaces everything through a Kibana-style dashboard. The full platform is licensed under AGPLv2 with no agent limits, no ingest caps, and no paid tier — what you self-host is what paying Wazuh Cloud customers get.

    A Wazuh deployment has three server-side components:

    • Wazuh manager — Receives events from agents, applies decoders and rules, stores alerts, triggers active responses, and exposes the management API.
    • Wazuh indexer — OpenSearch-based search and analytics engine that stores alerts, file integrity events, vulnerability data, and raw events with full-text search.
    • Wazuh dashboard — Web UI for querying data, building visualizations, managing agents, and operating integrations.
    On the endpoint side, the Wazuh agent is a lightweight daemon that runs on Linux, Windows, macOS, Solaris, AIX, and HP-UX. It collects logs, monitors file integrity, detects rootkits, runs configuration assessments against CIS benchmarks, inventories installed software for vulnerability scanning, and executes active responses issued by the manager.

    Typical use cases include regulated-industry compliance (PCI DSS, HIPAA, GDPR, NIST 800-53, TSC), MITRE ATT&CK-aligned threat hunting, container and Kubernetes runtime security, cloud workload protection for AWS, Azure, GCP, and GitHub audit logs, and replacing point products like OSSEC, Tripwire, or commercial EDR.

    Why Self-Host a SIEM Instead of Paying for Splunk or Elastic Cloud?

    Running your own Wazuh cluster instead of buying Splunk Cloud, Elastic Cloud, Datadog Cloud SIEM, or Microsoft Sentinel comes with concrete advantages:

    • Flat, predictable cost — A CloudCore Business VPS is a fixed monthly price regardless of ingest volume. Splunk Cloud starts at roughly $1,800/mo for 5 GB/day and scales to five-figure monthly bills fast. Elastic Cloud and Datadog meter both ingest and retention.
    • No per-agent licensing — Wazuh supports unlimited agents. Microsoft Sentinel, SentinelOne, and CrowdStrike all charge per endpoint per month.
    • Full data sovereignty — Every byte of telemetry stays on infrastructure you control. This matters for GDPR, SOC 2, regulated finance, healthcare, and defense workloads where shipping raw logs to a US cloud vendor is a non-starter.
    • Unlimited retention — Cloud SIEMs charge premium rates for data older than 30 days. On your own VPS with NVMe storage you decide how long you keep data.
    • Hack-friendly — You own the rule files, the decoders, the API. You can fork them, write custom decoders for proprietary apps, and contribute upstream.
    • No vendor lock-in — Alerts live in an OpenSearch index and can be reindexed, exported, or migrated without vendor cooperation.

    Cost Comparison: Wazuh Self-Hosted vs. Managed SIEMs

    Scenario (10 GB/day ingest, 50 endpoints, 30-day retention)Splunk CloudElastic Cloud (Security)Microsoft SentinelSelf-Hosted Wazuh (VPS)
    Typical monthly cost$3,000 – $6,000$1,200 – $2,500$2,300 – $4,000EUR 29.99/mo (flat)
    Per-agent licensingBundledBundledYes (per node)None
    Retention beyond 30 daysPaid tierPaid tierPaid tierUnlimited (disk-bound)
    Data leaves your infrastructure?YesYesYesNo
    MITRE ATT&CK mappingYesYesYesYes
    Open-source rulesNoPartiallyNoYes
    Custom decodersVia SPLLimitedLimitedUnlimited
    For most teams below a few hundred endpoints, self-hosted Wazuh on a properly sized VPS pays for itself within a single billing cycle.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access and at least 50 GB of NVMe storage.
    • SSH access to the server.
    • At least 8 vCPU and 16 GB of RAM for the all-in-one install with 25–100 agents. For 150+ agents, split components across two or three nodes.
    • A public DNS record such as wazuh.yourdomain.com pointing at the VPS (for TLS on the dashboard).
    • Ports open: 1514/tcp+udp (agent events), 1515/tcp (agent enrollment), 55000/tcp (manager API), 9200/tcp (indexer, localhost only), 443/tcp (dashboard — via Nginx).
    Recommended Plan: CloudCore Business
    >
    Wazuh's indexer is memory-hungry. The CloudCore Business plan gives you a comfortable runway:
    >
    - 8 vCPU cores
    - 24 GB RAM
    - 200 GB NVMe SSD
    - Unmetered bandwidth
    - Flat monthly price
    >
    This supports 100+ agents, 30 days of hot retention at ~10 GB/day, and leaves headroom for Filebeat buffering and dashboard queries. For larger deployments, see our higher-tier plans at vps-server.host/store/vps.

    Connect to your server via SSH to get started:

    bash
    ssh root@your-server-ip

    Step 1: Prepare Ubuntu 24.04

    Start by updating packages and installing helper tools:

    bash
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl gnupg apt-transport-https ca-certificates \
        software-properties-common ufw jq unzip

    Set a descriptive hostname (this shows up in agent and alert metadata):

    bash
    sudo hostnamectl set-hostname wazuh.yourdomain.com

    The Wazuh indexer needs a raised memory map count to avoid swap thrashing:

    bash
    echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
    sudo sysctl -p

    Configure the firewall. Lock down the indexer and manager API to localhost; only expose what must be public:

    bash
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 22/tcp                 # SSH
    sudo ufw allow 443/tcp                # Dashboard via Nginx
    sudo ufw allow 1514/tcp               # Agent events
    sudo ufw allow 1514/udp               # Agent events (syslog)
    sudo ufw allow 1515/tcp               # Agent enrollment
    sudo ufw --force enable

    Disable swap (the indexer does not play well with swap):

    bash
    sudo swapoff -a
    sudo sed -i '/ swap / s/^/#/' /etc/fstab

    Reboot before continuing if the kernel was upgraded:

    bash
    sudo reboot

    Step 2: Install Wazuh (All-in-One with wazuh-install.sh)

    The fastest path to a working Wazuh server is the official assistant script, which installs and wires up the manager, indexer, and dashboard on a single host.

    Download the installer and configuration template:

    bash
    curl -sO https://packages.wazuh.com/4.11/wazuh-install.sh
    curl -sO https://packages.wazuh.com/4.11/config.yml

    Edit config.yml to set the server name and (optionally) the node IP:

    bash
    sudo nano config.yml

    Change the nodes section to match your host:

    yaml
    nodes:
      indexer:
        - name: wazuh-indexer
          ip: "127.0.0.1"
      server:
        - name: wazuh-server
          ip: "127.0.0.1"
      dashboard:
        - name: wazuh-dashboard
          ip: "127.0.0.1"

    Generate the certificate bundle:

    bash
    sudo bash wazuh-install.sh --generate-config-files

    Run the unified install (this single command deploys the indexer, the server, and the dashboard):

    bash
    sudo bash wazuh-install.sh -a

    Expected output (trimmed):

    text
    15/04/2026 10:15:04 INFO: Starting Wazuh installation assistant.
    15/04/2026 10:15:04 INFO: Verbose logging redirected to /var/log/wazuh-install.log
    15/04/2026 10:15:22 INFO: --- Dependencies ---
    15/04/2026 10:15:48 INFO: --- Wazuh indexer ---
    15/04/2026 10:16:02 INFO: Starting service wazuh-indexer.
    15/04/2026 10:17:41 INFO: Initializing Wazuh indexer cluster security settings.
    15/04/2026 10:18:09 INFO: --- Wazuh server ---
    15/04/2026 10:19:55 INFO: Starting service wazuh-manager.
    15/04/2026 10:20:07 INFO: --- Wazuh dashboard ---
    15/04/2026 10:21:30 INFO: Starting service wazuh-dashboard.
    15/04/2026 10:21:55 INFO: Installation finished.
    15/04/2026 10:21:55 INFO: You can access the web interface https://<wazuh-dashboard-ip>
        User: admin
        Password: <SuperSecureGeneratedPassword>

    Record the admin password from the output — you will need it for first login.

    Verify the three services are running:

    bash
    sudo systemctl status wazuh-manager wazuh-indexer wazuh-dashboard --no-pager

    All three should show active (running). The API listens on 127.0.0.1:55000, the indexer on 9200, and the dashboard on 443.

    Step 2 (Alternative): Install Wazuh with Docker Compose

    If you prefer container isolation, reproducible deployments, or you run Wazuh alongside other Dockerized services, use the official Compose stack.

    Install Docker Engine and the Compose plugin (skip if already present — see our Docker Compose guide):

    bash
    curl -fsSL https://get.docker.com | sh
    sudo systemctl enable --now docker

    Clone the Wazuh Docker repository:

    bash
    git clone https://github.com/wazuh/wazuh-docker.git -b v4.11.0
    cd wazuh-docker/single-node

    Generate the internal certificate bundle:

    bash
    docker compose -f generate-indexer-certs.yml run --rm generator

    Edit the credentials in docker-compose.yml:

    yaml
    services:
      wazuh.manager:
        environment:
          - INDEXER_URL=https://wazuh.indexer:9200
          - INDEXER_USERNAME=admin
          - INDEXER_PASSWORD=ChangeMeStrong123!
          - FILEBEAT_SSL_VERIFICATION_MODE=full
      wazuh.indexer:
        environment:
          - "OPENSEARCH_JAVA_OPTS=-Xms4g -Xmx4g"
      wazuh.dashboard:
        environment:
          - WAZUH_API_URL=https://wazuh.manager
          - DASHBOARD_USERNAME=kibanaserver
          - DASHBOARD_PASSWORD=ChangeMeStrong456!

    Bring the stack up:

    bash
    docker compose up -d
    docker compose ps

    The dashboard is published on https://<server-ip>:443. Default credentials are admin / SecretPassword unless you change them in internal_users.yml (strongly recommended before any production use).

    Step 3: First Dashboard Login

    Open a browser to https://<your-server-ip>/ (accept the self-signed warning — we replace the cert with Let's Encrypt in Step 12).

    Log in with:

    • Username: admin
    • Password: the string printed by wazuh-install.sh (or the one you set in Compose)
    You land on the Wazuh overview page with tiles for Threat Intelligence, Security Operations, Cloud Security, Endpoint Security, and Configuration.

    Immediately rotate the default passwords using the built-in helper:

    bash
    sudo /usr/share/wazuh-indexer/plugins/opensearch-security/tools/wazuh-passwords-tool.sh -au admin -ac

    You will be prompted for the current admin password and a new one. Repeat for kibanaserver, wazuh, and any other internal users the tool lists.

    Restart the indexer and dashboard so the new hash takes effect:

    bash
    sudo systemctl restart wazuh-indexer wazuh-dashboard

    Step 4: Enroll Linux Agents

    Agents are how Wazuh gets eyes on your monitored hosts. Install the agent on every server you want to protect — web hosts, database nodes, mail servers, Kubernetes worker nodes, developer workstations.

    On each monitored Ubuntu/Debian host, add the Wazuh repository:

    bash
    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 update

    Install the agent, pointing at the manager IP/hostname:

    bash
    sudo WAZUH_MANAGER="wazuh.yourdomain.com" WAZUH_AGENT_NAME="$(hostname)" \
        apt install -y wazuh-agent

    Enable and start:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable --now wazuh-agent

    For RHEL/AlmaLinux/Rocky, use the yum repo:

    bash
    sudo rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH
    cat <<EOF | sudo tee /etc/yum.repos.d/wazuh.repo
    [wazuh]
    gpgcheck=1
    gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH
    enabled=1
    name=EL-\$releasever - Wazuh
    baseurl=https://packages.wazuh.com/4.x/yum/
    protect=1
    EOF
    sudo WAZUH_MANAGER="wazuh.yourdomain.com" yum install -y wazuh-agent
    sudo systemctl enable --now wazuh-agent

    Back on the manager, confirm the agent has registered:

    bash
    sudo /var/ossec/bin/agent_control -l

    Expected output:

    text
    Wazuh agent_control. List of available agents:
       ID: 000, Name: wazuh-server (server), IP: 127.0.0.1, Active/Local
       ID: 001, Name: web01, IP: 10.0.0.11, Active
       ID: 002, Name: db01,  IP: 10.0.0.12, Active

    Or browse to Endpoints summary in the dashboard to see the same list with OS, version, and last-seen timestamps.

    Step 5: Enroll Windows Agents

    Wazuh's Windows agent collects Event Log, Sysmon, and PowerShell channels — which is where almost every interesting Windows-side detection happens.

    On the Windows target (Server 2016+ or Windows 10/11), open an elevated PowerShell:

    powershell
    Invoke-WebRequest -Uri https://packages.wazuh.com/4.x/windows/wazuh-agent-4.11.0-1.msi 
        -OutFile $env:TEMP\wazuh-agent.msi

    msiexec.exe /i $env:TEMP\wazuh-agent.msi /q WAZUH_MANAGER="wazuh.yourdomain.com" WAZUH_AGENT_NAME=&quot;$env:COMPUTERNAME&quot; WAZUH_REGISTRATION_SERVER="wazuh.yourdomain.com"

    NET START WazuhSvc

    To collect Sysmon events (highly recommended — it is the single biggest uplift for Windows detection quality), install Sysmon with a well-known config such as SwiftOnSecurity's:

    powershell
    Invoke-WebRequest -Uri https://live.sysinternals.com/Sysmon64.exe -OutFile C:\Windows\Sysmon64.exe
    Invoke-WebRequest -Uri https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml -OutFile C:\sysmonconfig.xml
    C:\Windows\Sysmon64.exe -accepteula -i C:\sysmonconfig.xml

    Then tell the Wazuh agent to forward the Sysmon channel. Edit C:\Program Files (x86)\ossec-agent\ossec.conf and add inside the <ossec_config> block:

    xml
    <localfile>
      <location>Microsoft-Windows-Sysmon/Operational</location>
      <log_format>eventchannel</log_format>
    </localfile>

    Restart the service:

    powershell
    Restart-Service -Name WazuhSvc

    The agent now appears in the dashboard alongside Linux hosts, and Sysmon events flow into the default Wazuh ruleset which has hundreds of Sysmon-aware detections.

    Step 6: Tune Rules and Decoders

    Wazuh ships with a base ruleset of ~3,000 rules and ~600 decoders under /var/ossec/ruleset/. Never edit those files — they are overwritten on upgrade. Put custom rules and decoders in /var/ossec/etc/rules/ and /var/ossec/etc/decoders/.

    Create a custom rule that fires on repeated SSH failures from the same IP (an example — the default ruleset already covers this, but the pattern is the thing):

    bash
    sudo nano /var/ossec/etc/rules/local_rules.xml
    xml
    <group name="local,syslog,sshd,">
      <rule id="100100" level="10" frequency="8" timeframe="120">
        <if_matched_sid>5716</if_matched_sid>
        <same_source_ip />
        <description>Custom: 8 SSH auth failures from same IP in 2 minutes</description>
        <mitre>
          <id>T1110.001</id>
        </mitre>
        <group>authentication_failures,pci_dss_10.2.4,</group>
      </rule>
    </group>

    Validate and reload:

    bash
    sudo /var/ossec/bin/wazuh-logtest
    sudo systemctl restart wazuh-manager

    Paste a sample sshd failure line into wazuh-logtest — it will show you which decoder parsed it and which rule chain it matched.

    For a custom application (say, a Node.js app logging JSON to /var/log/myapp/app.log), add a decoder in /var/ossec/etc/decoders/local_decoder.xml and a matching rule set. Reference the Wazuh ruleset docs for the full syntax.

    Step 7: Enable File Integrity Monitoring (FIM)

    FIM ("syscheck") hashes critical files and alerts on any change — the classic detection for webshells, cryptominers, and backdoored binaries.

    On the manager, edit /var/ossec/etc/ossec.conf and adjust the <syscheck> block:

    xml
    <syscheck>
      <disabled>no</disabled>
      <frequency>43200</frequency>            <!-- 12h full scan -->
      <scan_on_start>yes</scan_on_start>

    <!-- Realtime monitoring on high-value directories --> <directories realtime="yes" check_all="yes" report_changes="yes">/etc,/bin,/sbin,/usr/bin,/usr/sbin</directories> <directories realtime="yes" check_all="yes" report_changes="yes">/var/www</directories> <directories realtime="yes" check_all="yes" report_changes="yes">/root/.ssh,/home/*/.ssh</directories>

    <!-- Weekly whole-disk baseline --> <directories check_all="yes">/usr/lib,/opt</directories>

    <ignore>/etc/mtab</ignore> <ignore>/etc/hosts.deny</ignore> <ignore type="sregex">.log$|.swp$</ignore>

    <nodiff>/etc/ssl/private.key</nodiff> </syscheck>

    Push the shared config to all agents by bumping the centralized-config version:

    bash
    sudo systemctl restart wazuh-manager

    Agents pull the new config within seconds. In the dashboard under Endpoint Security → File Integrity Monitoring you will see the initial baseline populate, then diffs as files change. The report_changes="yes" attribute makes Wazuh ship the textual diff of modified files — gold for web server and config file tampering.

    For Windows agents, add equivalent <directories realtime="yes">C:\Windows\System32\drivers\etc</directories> and similar lines, plus a <registry> block to watch Run keys.

    Step 8: Enable Vulnerability Detection

    Wazuh's vulnerability detector correlates each agent's installed-package inventory against CVE feeds (NVD, Canonical, Red Hat, Debian, Microsoft, ALAS) and raises alerts mapped to the affected hosts.

    In Wazuh 4.8+, vulnerability detection is enabled via the vulnerability-detection module in /var/ossec/etc/ossec.conf:

    xml
    <vulnerability-detection>
      <enabled>yes</enabled>
      <index-status>yes</index-status>
      <feed-update-interval>60m</feed-update-interval>
    </vulnerability-detection>

    <indexer> <enabled>yes</enabled> <hosts> <host>https://127.0.0.1:9200</host> </hosts> <ssl> <certificate_authorities> <ca>/etc/filebeat/certs/root-ca.pem</ca> </certificate_authorities> <certificate>/etc/filebeat/certs/filebeat.pem</certificate> <key>/etc/filebeat/certs/filebeat-key.pem</key> </ssl> </indexer>

    Restart the manager:

    bash
    sudo systemctl restart wazuh-manager

    On each agent, make sure the Syscollector module is running (it is enabled by default and populates the package inventory):

    xml
    <wodle name="syscollector">
      <disabled>no</disabled>
      <interval>1h</interval>
      <packages>yes</packages>
      <os>yes</os>
      <hardware>yes</hardware>
      <ports>yes</ports>
      <processes>yes</processes>
    </wodle>

    Within 60 minutes the dashboard's Vulnerability Detection module populates with CVE IDs, CVSS scores, affected packages, fixed versions, and per-agent exposure. Use it to prioritize patch windows — a Wazuh CVE report is usually faster to act on than a generic OS-update notice.

    Step 9: Use the MITRE ATT&CK Module

    Every rule in the default ruleset is tagged with the MITRE ATT&CK technique it detects. In the dashboard, open Threat Intelligence → MITRE ATT&CK to see a coverage matrix: Initial Access, Execution, Persistence, Privilege Escalation, Defense Evasion, Credential Access, Discovery, Lateral Movement, Collection, Command and Control, Exfiltration, Impact.

    Clicking any technique (for example, T1110 – Brute Force) shows every alert Wazuh has recorded that maps to it, the rule IDs, and the affected agents. You can pivot from technique to rule to raw event and back.

    To add ATT&CK tagging to your own custom rules, include <mitre> IDs as shown in Step 6. The dashboard will automatically incorporate them into the coverage heatmap.

    The Intelligence panel in the same section lets you search Mitigations and Data Sources — useful when a detection fires and you need to look up defensive recommendations for that tactic.

    Step 10: Configure Active Response

    Active Response lets Wazuh execute commands on the agent in response to specific alerts — block an IP in iptables, disable a user account, kill a process, run a forensic capture script. Used carefully, this is the "R" in XDR.

    Define a command and a response in /var/ossec/etc/ossec.conf on the manager:

    xml
    <command>
      <name>firewall-drop</name>
      <executable>firewall-drop</executable>
      <timeout_allowed>yes</timeout_allowed>
    </command>

    <active-response> <command>firewall-drop</command> <location>local</location> <rules_id>5712,5763,100100</rules_id> <timeout>600</timeout> </active-response>

    This blocks the attacking IP via iptables on the affected agent for 600 seconds whenever rule 5712 (multiple auth failures), 5763 (brute-force), or our custom 100100 fires. The firewall-drop script is shipped with the agent at /var/ossec/active-response/bin/firewall-drop.

    Restart the manager to push the config:

    bash
    sudo systemctl restart wazuh-manager

    Trigger a test: from a disposable IP, attempt 10 failed SSH logins to a monitored host. Within seconds you should see the IP appear in sudo iptables -L INPUT -n --line-numbers and an active-response alert in the dashboard. After 600 seconds, the block automatically expires.

    For higher-value responses (disabling a user, wiping a compromised service account session, isolating a host from the network), write custom response scripts in /var/ossec/active-response/bin/ and point to them the same way. See the Wazuh active response docs for recipes.

    Step 11: Integrations — Slack, VirusTotal, Shuffle SOAR

    Wazuh can push alerts to external systems via the <integration> block in /var/ossec/etc/ossec.conf.

    Slack notifications

    Create an Incoming Webhook in Slack, then add:

    xml
    <integration>
      <name>slack</name>
      <hook_url>https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX</hook_url>
      <level>10</level>
      <alert_format>json</alert_format>
    </integration>

    Only alerts at level 10 or higher are shipped (keeps Slack sane). Restart the manager; the next high-severity event will land in the configured channel with host, rule, and description.

    VirusTotal file hash enrichment

    Pair VirusTotal with FIM so every new or modified binary is queried against 70+ AV engines:

    xml
    <integration>
      <name>virustotal</name>
      <api_key>YOUR_VT_API_KEY</api_key>
      <group>syscheck</group>
      <alert_format>json</alert_format>
    </integration>

    When FIM reports a new file, Wazuh submits the SHA256 to VirusTotal. A positive detection triggers rule 87105 — which you can chain into an active response (for example, quarantine the file) or a Slack alert.

    Shuffle SOAR playbooks

    Shuffle is an open-source SOAR platform that pairs well with Wazuh for building alert-to-playbook automation (ticket creation, threat intel lookup, EDR containment).

    xml
    <integration>
      <name>shuffle</name>
      <hook_url>https://shuffler.io/api/v1/hooks/webhook_YOUR_ID</hook_url>
      <level>8</level>
      <alert_format>json</alert_format>
    </integration>

    In Shuffle, trigger a workflow from the webhook and chain tasks — create a Jira ticket, run a whois on the source IP, post to an incident channel, or call a cloud API to isolate an EC2 instance. This is the cheapest open-source path to genuine SOC automation.

    Restart the manager after adding integrations:

    bash
    sudo systemctl restart wazuh-manager

    Step 12: Publish the Dashboard Behind Nginx + TLS

    Running the Wazuh dashboard on port 443 directly works, but a dedicated Nginx reverse proxy gives you a real Let's Encrypt certificate, custom security headers, optional IP allowlisting, and a clean path to run other services on the same host.

    Point the dashboard at localhost only. Edit /etc/wazuh-dashboard/opensearch_dashboards.yml:

    yaml
    server.host: "127.0.0.1"
    server.port: 5601

    Restart the dashboard:

    bash
    sudo systemctl restart wazuh-dashboard

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Create the site config:

    bash
    sudo tee /etc/nginx/sites-available/wazuh > /dev/null <<'EOF'
    server {
        listen 80;
        server_name wazuh.yourdomain.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; server_name wazuh.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/wazuh.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/wazuh.yourdomain.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; add_header X-Frame-Options DENY always; add_header X-Content-Type-Options nosniff always; add_header Referrer-Policy strict-origin-when-cross-origin always;

    client_max_body_size 50m;

    location / { proxy_pass https://127.0.0.1:5601; proxy_ssl_verify off; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 600s; } } EOF

    sudo ln -s /etc/nginx/sites-available/wazuh /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t

    Obtain the certificate (Certbot will autowire the cert paths above):

    bash
    sudo certbot --nginx -d wazuh.yourdomain.com
    sudo systemctl reload nginx

    Visit https://wazuh.yourdomain.com — you should now see the Wazuh dashboard behind a green padlock.

    For extra hardening, restrict dashboard access by source IP:

    nginx
    location / {
        allow 203.0.113.0/24;   # Office network
        allow 198.51.100.42;    # VPN exit
        deny all;
        # ...proxy_pass block...
    }

    Step 13: Backups and Upgrades

    A SIEM is useless without its data. Back up three things: the manager configuration, the indexer data, and the shared agent configs.

    Daily configuration backup

    Create /usr/local/bin/wazuh-backup.sh:

    bash
    #!/usr/bin/env bash
    set -euo pipefail

    BACKUP_DIR="/var/backups/wazuh/$(date +%Y-%m-%d)" mkdir -p "$BACKUP_DIR"

    Manager config & rules

    tar czf "$BACKUP_DIR/ossec-etc.tar.gz" /var/ossec/etc tar czf "$BACKUP_DIR/ossec-ruleset.tar.gz" /var/ossec/ruleset tar czf "$BACKUP_DIR/filebeat.tar.gz" /etc/filebeat

    Indexer snapshot (register repo once, snapshot nightly)

    curl -sk -u admin:$INDEXER_ADMIN_PASSWORD \ -X PUT "https://127.0.0.1:9200/_snapshot/wazuh_fs" \ -H 'Content-Type: application/json' -d '{ "type": "fs", "settings": { "location": "/mnt/backups/wazuh-snapshots" } }' || true

    curl -sk -u admin:$INDEXER_ADMIN_PASSWORD \ -X PUT "https://127.0.0.1:9200/_snapshot/wazuh_fs/snap-$(date +%Y%m%d)?wait_for_completion=false"

    Retention: keep last 14 days

    find /var/backups/wazuh -maxdepth 1 -type d -mtime +14 -exec rm -rf {} +

    Make executable and schedule via cron:

    bash
    sudo chmod +x /usr/local/bin/wazuh-backup.sh
    echo "0 3   * root INDEXER_ADMIN_PASSWORD='YourAdminPassword' /usr/local/bin/wazuh-backup.sh" | \
        sudo tee /etc/cron.d/wazuh-backup

    Ship /mnt/backups/wazuh-snapshots offsite (rclone to S3/B2, rsync to a second VPS, restic to a backup repo).

    Upgrades

    Wazuh releases patch versions monthly. Before any upgrade, take a full backup. For the all-in-one install:

    bash
    sudo apt update
    sudo apt install --only-upgrade wazuh-manager wazuh-indexer wazuh-dashboard

    Agents upgrade themselves when their host runs apt upgrade (provided the Wazuh repo is configured). For major upgrades (4.x → 5.x when it ships), read the migration notes first — breaking rule or indexer schema changes occasionally require reindexing.

    Troubleshooting

    ProblemCauseSolution
    wazuh-install.sh exits at "Wazuh indexer" stepvm.max_map_count too low or insufficient RAMRun sudo sysctl -w vm.max_map_count=262144 and verify the VPS has 8 GB+ free.
    Dashboard shows "No results found"Filebeat not forwarding to the indexersudo filebeat test output and sudo systemctl status filebeat. Fix cert paths in /etc/filebeat/filebeat.yml.
    Agent stays in Never connectedPort 1514/1515 blocked or wrong manager addresstelnet wazuh.yourdomain.com 1514 from the agent. Fix UFW or cloud firewall.
    Agent registered but no eventsShared ruleset not pushed or time skewCheck /var/ossec/logs/ossec.log on the agent. Run sudo timedatectl set-ntp true on both sides.
    High indexer RAM use / OOM killsDefault JVM heap too large for VPSEdit /etc/wazuh-indexer/jvm.options, set -Xms2g / -Xmx2g for an 8 GB VPS.
    Vulnerability detection emptySyscollector disabled or feed download failedCheck /var/ossec/logs/ossec.log for vulnerability-detector errors. Confirm outbound HTTPS to feed.wazuh.com is allowed.
    Slack integration silent<level> too high or webhook URL wrongLower level temporarily to 3, trigger an alert, check /var/ossec/logs/integrations.log.
    Dashboard 502 behind NginxDashboard bound to wrong host or cert mismatchConfirm server.host: "127.0.0.1" in opensearch_dashboards.yml, then curl -kI https://127.0.0.1:5601.

    Useful log files

    • /var/ossec/logs/ossec.log — manager, decoders, rules, active response
    • /var/ossec/logs/api.log — management API requests
    • /var/log/wazuh-indexer/wazuh-cluster.log — indexer
    • /var/log/wazuh-dashboard/wazuh-dashboard.log — dashboard
    • /var/log/filebeat/filebeat — indexer forwarding
    Tail everything at once during troubleshooting:

    bash
    sudo journalctl -u wazuh-manager -u wazuh-indexer -u wazuh-dashboard -u filebeat -f

    FAQ

    What is the difference between Wazuh SIEM and Wazuh XDR?

    They are the same product used differently. As a SIEM, Wazuh centralizes and correlates logs, raises alerts, and feeds compliance reports. As an XDR, it uses the agent to detect threats on endpoints and execute active responses. Because both capabilities ship in the same server and agent, you get SIEM and XDR from a single install — and the line between them is increasingly blurry across the industry.

    How many agents can one Wazuh server handle?

    An all-in-one node on 8 vCPU and 16 GB RAM comfortably supports 50–150 agents with the default ruleset and moderate log volume. Beyond 150 agents or 10 GB/day of ingest, split the manager, indexer, and dashboard onto dedicated VPSes and consider clustering the indexer. Wazuh's own reference architecture runs up to 25,000 agents on a distributed cluster.

    Is Wazuh really free? What is "Wazuh Cloud"?

    The Wazuh platform is 100% open-source (AGPLv2) with no feature gating. Wazuh Cloud is Wazuh Inc's managed hosting of the exact same platform — convenient if you do not want to operate the stack, but not required. Self-hosting on your own VPS gives you the full feature set at a fraction of the cost.

    Can Wazuh replace CrowdStrike or SentinelOne?

    Wazuh overlaps significantly with commercial EDRs: host-based IDS, file integrity monitoring, vulnerability detection, active response, cloud workload protection. What it lacks out of the box is kernel-level behavioral detection and the curated, vendor-maintained threat intel that commercial EDRs invest in. For many SMBs, defense-in-depth teams, and regulated shops that need auditable open-source tooling, Wazuh is a legitimate replacement. For APT-grade threat hunting in a large enterprise, Wazuh is often deployed alongside a commercial EDR rather than in place of it.

    How does Wazuh compare to the ELK/Elastic SIEM?

    Under the hood Wazuh forked OpenSearch (which itself forked Elasticsearch 7.10) and bundles a purpose-built security UI, agent, and ruleset. Elastic SIEM is the counterpart on the Elasticsearch side, with its own detection rules engine. Elastic SIEM is more tightly integrated with Elastic's broader observability stack; Wazuh is more focused and has stronger out-of-the-box compliance, FIM, and active response capabilities. If you are already running the Elastic Stack, layering Wazuh on top (forwarding Wazuh alerts into Elasticsearch) is a common pattern. If you are starting fresh, Wazuh is usually less work.

    Can I combine Wazuh with Fail2ban, CrowdSec, or Graylog?

    Yes, and it is a popular pattern. Fail2ban and CrowdSec give you immediate reflexive blocking at the host and edge; Wazuh correlates everything into a single pane of glass and keeps historical evidence. For high-volume log storage beyond Wazuh's security focus, pair it with Graylog for general-purpose log aggregation and pipelines.

    Next Steps

    Now that Wazuh is humming along, here is where to go next:

    • Layer in edge protection with CrowdSec — Complement Wazuh's host-level detection with a behavior-based firewall at the edge. See our CrowdSec install guide.
    • Add Fail2ban for fast reflexive blocking — Simple, effective, and a great companion to Wazuh's longer-horizon correlation. See Fail2ban on Ubuntu.
    • Deploy Graylog for general log aggregation — Use Wazuh for security-grade events and Graylog for application, access, and audit logs.
    • Wire up cloud security — Enable Wazuh's AWS, Azure, GCP, GitHub, and Office 365 modules to ingest cloud audit trails alongside host telemetry.
    • Build dashboards — The Wazuh dashboard uses OpenSearch Dashboards under the hood. Author custom visualizations and saved searches for the detections that matter to your business.
    • Read the upstream docs — The official Wazuh documentation is comprehensive; the Proof of Concept section in particular has great hands-on exercises for red-team-style detection tuning.

    Run Wazuh on a VPS Built for SIEM Workloads
    >
    Wazuh's indexer is CPU- and RAM-hungry, and logs eat NVMe for breakfast. Our CloudCore Business plan is sized for the job — generous cores, enough RAM to let the JVM breathe, and fast NVMe for hot retention.
    >
    - 8 vCPU cores
    - 24 GB RAM
    - 200 GB NVMe SSD
    - Unmetered bandwidth
    - Flat monthly price, no ingest fees, no per-agent licensing
    >
    Deploy Your Wazuh VPS Now and have a production SIEM stack running in under an hour.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket