Build a Simple Wazuh SIEM Lab
Deploy Wazuh with Docker on Fedora and detect a live SSH brute-force attack.
Introduction
30 Second Summary
Every time a hacker breaks into a system, the warning signs were already there. Failed logins, suspicious traffic, modified files. A SIEM catches those signs before real damage is done.
In this project, you will deploy a Wazuh SIEM stack using Docker on a Fedora host, connect a Debian-based VM (like Linux Mint) as a monitored endpoint, and catch a brute-force SSH attack in real time.
What You'll Build
You will run an SSH brute-force attack against your own machine, switch to the Wazuh dashboard, and watch the alerts fire in real time.
By the end of this project, you'll have:
- A live Wazuh dashboard running in Docker with three containers (manager, indexer, dashboard) streaming security events in real time.
- A monitored VM agent enrolled and reporting authentication events, service activity, and system logs to your SIEM.
- Brute-force detection that catches a live SSH dictionary attack and fires Wazuh's built-in correlation rules automatically.
- Secret Mission: Configure Active Response to automatically block attacker IPs when a brute-force is detected.
Are there any prerequisites?
This project assumes you have a Fedora host with Docker installed and a Debian-based VM (such as Linux Mint or Ubuntu) with 2-3 GB of RAM allocated. You should also be comfortable running basic Linux commands in the terminal.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters.
You're going to deploy a real SIEM platform, connect a live endpoint to it, simulate actual attacks, and write your own detection rules. Take a moment to commit to the goal before any hands-on work begins.
Deploy the Wazuh Stack with Docker
A SIEM is only useful if it is actually running and collecting data. Right now you have nothing deployed. No server, no indexer, no dashboard.
In this step, you will deploy the entire Wazuh server stack using Docker Compose. This gives you three containers: the manager (which analyzes events), the indexer (which stores them), and the dashboard (which visualizes them). By the end of this step, you will have a working SIEM dashboard you can log into.
In this step, get ready to:
- Set a required kernel parameter and clone the Wazuh Docker repository.
- Generate TLS certificates and start the full Docker Compose stack.
- Access the Wazuh dashboard and confirm you can log in.
Set the kernel parameter and clone the repository
The Wazuh indexer is built on OpenSearch, which requires a higher-than-default limit on memory-mapped areas. Without this, the indexer container will crash on startup.
- Open a terminal on your Fedora host.
- Set the required kernel parameter by running this command:
sudo sysctl -w vm.max_map_count=262144
What does this command do?
The vm.max_map_count parameter controls how many memory map areas a process can use. The Wazuh indexer needs at least 262144. This command sets the value immediately for the current session.
- Confirm the value was set by running:
sysctl vm.max_map_count
You should see vm.max_map_count = 262144 (or a higher number if your Fedora already ships a larger default).
Already above 262144?
Fedora 39 and later ship with vm.max_map_count set to 1048576 by default. If your output already shows a value at or above 262144, you are good to go. The sysctl command above is a no-op in that case.
- Move to your Desktop by running this command:
cd ~/Desktop
- Clone the Wazuh Docker repository at the v4.14.7 tag by running this command:
git clone https://github.com/wazuh/wazuh-docker.git -b v4.14.7
This downloads the full Docker Compose configuration for Wazuh 4.14.7 into a folder called wazuh-docker.
- Navigate into the single-node deployment directory by running:
cd wazuh-docker/single-node
- Confirm you are in the right directory by running:
ls
You should see files including docker-compose.yml and generate-indexer-certs.yml.
Don't see these files?
Make sure the git clone command completed without errors. Check that you navigated into wazuh-docker/single-node (not just wazuh-docker).
help me clone the Wazuh Docker repository on Fedora
Generate certificates and start the stack
The Wazuh components communicate over TLS. Before you can start the stack, you need to generate the certificates that secure those internal connections.
- Generate the TLS certificates by running this command:
docker compose -f generate-indexer-certs.yml run --rm generator
What does this command do?
This spins up a temporary container that generates self-signed TLS certificates for the indexer, manager, and dashboard. The certificates are stored in a Docker volume that the main stack will use. The container removes itself after finishing (--rm).
You should see output showing certificate generation completing successfully.
- Start the full Wazuh stack by running:
docker compose up -d
This starts three containers in the background: the Wazuh manager, the Wazuh indexer, and the Wazuh dashboard.
- Confirm all three containers are running by executing:
docker compose ps
You should see three services listed with a status of running (or Up): single-node-wazuh.manager-1, single-node-wazuh.indexer-1, and single-node-wazuh.dashboard-1.
Containers not running or restarting?
If the indexer container keeps restarting, check that vm.max_map_count is set correctly by running sysctl vm.max_map_count again. The value must be at least 262144.
If you see port conflicts, make sure nothing else is using port 443 or 9200 on your Fedora host.
help me troubleshoot my Wazuh Docker containers
Access the Wazuh dashboard
The indexer takes approximately one minute to fully initialize. Give it a moment before trying to access the dashboard.
- Wait about 60 seconds for the indexer to finish starting up.
- Open your browser on the Fedora host and navigate to:
https://localhost:443
Seeing a security warning?
Your browser will warn you about an untrusted certificate. This is expected because the certificates are self-signed. Click Advanced and then Accept the Risk and Continue (Firefox) or Proceed to localhost (Chrome).
Before you log in, what do you think the default credentials might be for a Docker deployment?
- Log in with the default Docker deployment credentials:
- Username: admin
- Password: SecretPassword
You should see the Wazuh dashboard home page with a summary panel. There are no agents connected yet, so most panels will show zero events.
Where do these credentials come from?
The username and password are defined in the docker-compose.yml file as environment variables (INDEXER_USERNAME and INDEXER_PASSWORD). For a production deployment, you would change these immediately. For this lab, the defaults are fine.
🙋♀️ Dashboard not loading?
If you see a blank page or connection refused, the indexer may still be initializing. Run docker compose logs wazuh.indexer and look for a line confirming the node is ready. Wait another minute and try again.
help me access the Wazuh dashboard in my browser
Your SIEM infrastructure is live. Next up, you will enroll your VM as a monitored agent so Wazuh has something to watch.
Enroll Your Kali VM as a Monitored Agent
Enroll Your Linux Mint VM as a Monitored Agent
Your Wazuh stack is up and running, with the dashboard ready to receive security data. But right now it has zero endpoints feeding it information.
A SIEM without monitored endpoints is like a security camera with no lens. In this step, you will install the Wazuh agent on your VM so it starts sending logs and events back to your manager.
In this step, get ready to:
- Install the Wazuh agent on your VM using the official APT repository.
- Enroll the agent with your Wazuh manager and confirm it shows as Active.
- Observe default security events flowing into the dashboard from your endpoint.
Add the Wazuh repository and install the agent
The Wazuh agent is what gives your manager visibility into everything happening on your VM. You will install it using Wazuh's official APT repository (works on any Debian-based distro).
- Switch to your VM terminal.
- Open a root shell so all installation commands run with the correct privileges:
sudo su
All commands in this substep run inside this root shell on your VM.
- Before installing the agent, you need to know your Fedora host's IP address so the agent knows where to report. On your Fedora host terminal, find the IP by running:
hostname -I
You will see one or more IP addresses printed. Note the first one. This is the address your VM will use to reach the Wazuh manager.
Which IP do I use?
Use the IP address on the network interface that your VM can reach. If your Fedora host and VM are on the same NAT or bridged network, the first IP shown by hostname -I is usually correct.
You can verify connectivity by running ping <fedora-ip> from your VM before proceeding.
- Back in your VM root shell, import the Wazuh GPG key by running:
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
What does this command do?
This downloads Wazuh's official GPG signing key and stores it in a keyring file. APT uses this key to verify that packages you download actually come from Wazuh and have not been tampered with.
- Add the Wazuh APT repository to your sources list by running:
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | tee -a /etc/apt/sources.list.d/wazuh.list
- Update your package index to pull in the new repository metadata by running:
apt-get update
You should see a line referencing packages.wazuh.com in the output, confirming APT recognizes the new repository.
Seeing a GPG error?
If apt-get update reports a GPG key error, the keyring file may not have the correct permissions. Re-run the chmod 644 command from the GPG import step and try again.
Help me troubleshoot this GPG key error
- Install the Wazuh agent package, setting WAZUH_MANAGER to your Fedora host IP so the agent knows where to connect:
WAZUH_MANAGER="[[FEDORA_IP="your Fedora host IP address"]]" apt-get install wazuh-agent
What does WAZUH_MANAGER do?
Setting this environment variable during installation tells the agent the IP address of your Wazuh manager. The agent writes this value into its configuration file so it can connect automatically on startup.
When the installation finishes, you will see a confirmation message indicating the wazuh-agent package is installed.
Installation failed?
If you see an error about the package not being found, confirm the APT repository was added correctly by checking /etc/apt/sources.list.d/wazuh.list exists and contains the Wazuh repository URL. Then run apt-get update again.
Help me fix the Wazuh agent installation on my VM
Start the agent and confirm enrollment
The package is installed, but the agent service is not running yet. You need to enable it and start it so it begins reporting to your Wazuh manager.
- Enable and start the Wazuh agent service by running:
systemctl daemon-reload && systemctl enable wazuh-agent && systemctl start wazuh-agent
What does this command do?
This reloads systemd's configuration, sets the agent to start automatically on boot, and starts it immediately. Once started, the agent initiates a connection to your Wazuh manager and begins sending logs.
- Verify the agent is running by checking its status:
systemctl status wazuh-agent
You should see active (running) in the output.
Agent not running?
If the status shows failed or inactive, the agent likely cannot reach your Wazuh manager. Confirm your Fedora host IP is correct and that port 1514 is reachable from your VM.
You can test connectivity by running curl -v telnet://<your-fedora-ip>:1514 from your VM. If the connection is refused, check that the Docker stack is still running on your Fedora host.
Help me get my Wazuh agent connected to the manager
Now comes the moment of truth. Before you check the dashboard, what do you expect to see in the agents list?
- Return to the Wazuh dashboard in your browser on the Fedora host.
- Click the menu icon in the upper-left corner.
- Navigate to Agents management and select Summary.
Your agent should appear in the list with an Active status. This confirms the agent successfully connected to the manager and is reporting in.
Agent not showing as Active?
Give it 30-60 seconds after starting the service. The agent needs time to complete its initial handshake with the manager.
If the agent still does not appear, restart the Wazuh manager container on your Fedora host by running docker restart single-node-wazuh.manager-1 and then restart the agent on your VM with systemctl restart wazuh-agent.
Help me get my agent to show as Active in the Wazuh dashboard
Confirm default events are flowing
An active agent is good, but you need to confirm it is actually sending useful data. Default events include system logs and authentication activity that Wazuh collects without any extra configuration.
- In the Wazuh dashboard, click the menu icon in the upper-left corner.
- Navigate to Threat Intelligence and select Threat Hunting.
- In the agent filter at the top, select your agent to scope the view to its events only.
You should see events populating the timeline. These are real security-relevant events from your endpoint, including authentication attempts and system service activity.
- Click on any event row to expand its details.
- Observe the fields shown: rule.description tells you what happened, rule.level shows severity, and agent.name confirms it came from your VM.
What are these default events?
Without any custom configuration, the Wazuh agent collects and forwards syslog data, authentication logs, and service state changes. These provide baseline visibility into your endpoint's security posture.
In the next step, you will simulate a brute-force SSH attack and see how Wazuh detects it automatically.
Make sure you selected the correct agent in the filter. Also check that the time range in the top-right corner covers the last 15-30 minutes.
If the timeline is completely empty, the agent may not be forwarding logs. On your VM, confirm the agent is still running with systemctl status wazuh-agent.
Help me figure out why no events are showing in Threat Hunting
Your endpoint is now fully enrolled and reporting to your SIEM. Next up, you will simulate a real brute-force attack and watch Wazuh catch it live.
Catch a Brute-Force Attack in Real Time
Your agent is enrolled and reporting default events to the dashboard. But so far, those events are just routine system activity.
In this step, you will simulate a real brute-force SSH attack using Hydra and watch Wazuh's built-in correlation rules detect it live in the dashboard. By the end, you will discover an important gap in detection-only security.
In this step, get ready to:
- Launch a brute-force SSH attack with Hydra against your VM.
- Observe Rules 5551 and 5712 fire in the Wazuh dashboard.
- Identify the gap between detection and prevention.
Start SSH and create a password wordlist
Hydra needs a target service to attack. You will install the SSH server and Hydra on your VM, then create a small wordlist of fake passwords for Hydra to try.
- On your Linux Mint VM, install the SSH server and Hydra by running this command:
sudo apt-get install -y openssh-server hydra
- Start the SSH service and confirm it is running:
sudo systemctl start ssh && sudo systemctl status ssh
You should see a green "active (running)" status in the output.
SSH not starting?
If you see "Unit ssh.service not found", try running sudo systemctl start sshd instead. Some Debian-based distros use sshd as the service name.
Help me troubleshoot SSH on my Linux Mint VM
- Create a password wordlist with 15 common (wrong) passwords by running this command:
cat << 'EOF' > ~/passwords.txt
password
123456
admin
letmein
welcome
monkey
dragon
master
qwerty
login
princess
football
shadow
sunshine
trustno1
EOF
What does this do?
This creates a file at ~/passwords.txt containing 15 commonly-used passwords. None of these match the actual password for the target user, so every attempt will fail. That is exactly what triggers the brute-force detection rules.
- Confirm your wordlist was created by running:
wc -l ~/passwords.txt
You should see 15 followed by the file path, confirming the file has 15 passwords.
Launch the brute-force attack with Hydra
Now you will use Hydra to rapidly try every password in your wordlist against the SSH service. This simulates what a real attacker does when trying to guess credentials.
- Create a test user that Hydra will target by running:
sudo useradd -m testuser
Why create a separate user?
Targeting a dedicated testuser account keeps the attack isolated. Every password attempt against this user will fail (since we never set a password for it), generating a clean stream of authentication failures for Wazuh to detect.
Before you run the next command, what do you think will happen? Will Hydra find a valid password, or will every attempt fail?
- Launch the Hydra brute-force attack against localhost SSH by running this command:
hydra -l testuser -P ~/passwords.txt ssh://127.0.0.1 -t 4
What does this command do?
- -l testuser targets the testuser account.
- -P ~/passwords.txt feeds your 15-password wordlist to Hydra.
- ssh://127.0.0.1 tells Hydra to attack the local SSH service.
- -t 4 limits Hydra to 4 parallel connection attempts. This is the recommended setting for SSH.
Hydra will print each attempt and finish with a summary showing 0 valid passwords found. That is expected.
Hydra showing connection errors?
If you see "Connection refused" errors, SSH is not running. Go back and run sudo systemctl start ssh again, then retry the Hydra command.
If Hydra is not found, install it with sudo apt-get install hydra. You should have installed it earlier in this step, but double-check if it is missing.
Help me fix Hydra connection errors
Watch the alerts fire in real time
The Wazuh agent on your VM captured every failed SSH login attempt and forwarded it to the manager. Those events trigger Wazuh's built-in correlation rules.
Before you check the dashboard, what do you expect to see? Think about how many failed logins you just generated and whether Wazuh should have noticed.
- Switch back to the Wazuh dashboard in your browser at https://localhost:443.
- Click the hamburger menu (three lines) in the top left corner.
- Click Threat Hunting under the Threat intelligence section.
- In the search bar at the top, type rule.id: 5712 and press Enter to filter the results.
You should see one or more alerts with the description "SSHD brute force trying to get access to the system" along with the source IP and target username.
- Clear the search bar and type rule.id: 5551 to see the precursor alerts that fired first.
How do these rules work together?
Rule 5551 fires when multiple SSH authentication failures happen in a short time window. It acts as the first warning.
Rule 5712 is a higher-level correlation rule that fires when 5551 triggers repeatedly. It escalates the alert from "multiple failures" to "brute force detected." This escalation chain is built into Wazuh's default ruleset.
Identify the detection gap
Wazuh successfully detected your brute-force attack. But here is the critical question.
- Think about this: what action did Wazuh take to stop the attack while it was happening?
The answer is nothing. Wazuh watched the entire attack happen, logged every failed attempt, and raised an alert. But the attacker could keep trying passwords indefinitely. If your wordlist had 10,000 entries instead of 15, Wazuh would have watched all 10,000 attempts without lifting a finger.
Why does this matter?
Detection without response is just watching yourself get hacked. A real SOC needs both detection (knowing an attack is happening) and response (doing something about it). Right now, your Wazuh deployment is detection-only.
This gap is exactly what Active Response fills. It turns Wazuh from a passive alert system into an active defense that can automatically block attacker IPs when brute-force rules fire.
Your SIEM now detects brute-force attacks in real time. Wazuh saw every failed login and raised the alarm. But it did nothing to stop the attacker. If you want to close that gap, the Secret Mission configures Active Response to automatically block attacker IPs.
Secret mission
Automated Threat Containment with Active Response
In Step 3, you watched Wazuh detect a brute-force attack but do nothing to stop it. The attacker could keep trying forever. In this secret mission, you will configure Active Response to automatically block the attacker's IP address when the brute-force rule fires, turning Wazuh from a passive observer into an active defense system.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally using Docker and a VM, so there are no ongoing cloud costs.
Resources you used:
- Docker containers running the Wazuh stack on your Fedora host (manager, indexer, dashboard). Uses approximately 4-5 GB RAM while active.
- Cloned wazuh-docker repository on your Fedora host.
- Wazuh agent installed on your Kali VM.
Keep everything running
No action needed. Choose this if you plan to continue experimenting with your SIEM lab, writing more custom rules, or testing new attack simulations.
- The Docker stack continues running and uses approximately 4-5 GB of RAM on your Fedora host.
- The Wazuh agent on Kali continues reporting events to the manager.
- Your configuration and any Active Response settings persist.
Pause - I'll come back to this later
Shut down the Docker stack to free up RAM on your Fedora host. Your data persists in Docker volumes so you can restart anytime without losing anything.
- On your Fedora host, navigate to the wazuh-docker/single-node/ directory and run:
docker compose down
- On your Kali VM, stop the agent service by running:
sudo systemctl stop wazuh-agent
When you are ready to resume, navigate back to wazuh-docker/single-node/ on your Fedora host and run:
docker compose up -d
Then start the agent again on Kali with sudo systemctl start wazuh-agent. Your configuration and Active Response settings will all be intact.
Delete - I don't want to use this again
Remove all project resources and start fresh. This deletes containers, data volumes, configuration changes, and the agent installation.
- On your Fedora host, navigate to the wazuh-docker/single-node/ directory and remove all containers and volumes by running:
docker compose down -v
- Remove the cloned repository from your Fedora host by running:
rm -rf ~/Desktop/wazuh-docker
- On your Kali VM, disable and remove the Wazuh agent by running:
sudo systemctl disable wazuh-agent
sudo systemctl daemon-reload
sudo apt-get remove --purge wazuh-agent
- Remove any leftover Wazuh files on Kali by running:
sudo rm -rf /var/ossec
- Stop the SSH service on Kali if you no longer need it by running:
sudo systemctl stop ssh
sudo systemctl disable ssh
Your Fedora host and Kali VM are now back to their pre-project state.
Nice Work!
Nice Work!
You just built a working SIEM threat detection lab from scratch. Your Fedora host is running a Wazuh stack in Docker, your Kali VM is reporting security events in real time, and you caught a live brute-force attack in the dashboard.
You've learned how to:
- Deploy a full Wazuh SIEM stack (manager, indexer, dashboard) using Docker Compose on a Fedora host.
- Enroll a Kali Linux VM as a monitored agent and confirm security events flowing into the dashboard.
- Simulate an SSH brute-force attack with Hydra and watch Wazuh's built-in correlation rules (5551 and 5712) fire in real time.
- Secret Mission: Configured Active Response to automatically block attacker IPs via firewall-drop when a brute-force rule fires, turning passive detection into active defense.
Ready to quiz yourself?