DockerSelf-Hosting

Wazuh with Docker: free security monitoring (SIEM/XDR) for your home lab (Linux, Windows, Mac)

Before you start

  • 21 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

Wazuh is a free, open-source security platform that collects logs and file-change data from your computers, checks them against detection rules and shows alerts in a web dashboard. Think of it as a security camera system for your machines: an agent on each PC or server reports in, and you see failed logins, changed system files, known-vulnerable software and misconfigurations in one place.

Wazuh official logo

Logo: the official Wazuh project (wazuh.com, as shown in the wazuh-dashboard-plugins README)

It is an enterprise tool, so it is heavy: three containers (indexer, manager, dashboard) and, per the docs, 4 CPU cores and 8 GB of RAM for the Docker host. A spare mini PC or a VM is fine; a Raspberry Pi with 4 GB is not.

WhatValue (official docs, read November 2026)
Current versionWazuh 4.14.9, released October 2026 (latest stable). 5.0.0 is still a release candidate
Images to pinwazuh/wazuh-manager, wazuh/wazuh-indexer, wazuh/wazuh-dashboard, all :4.14.9 (tags checked on Docker Hub)
Time neededAbout 30 minutes plus the image download (our estimate, not measured)
Host needs (single node)4 CPU cores, 8 GB RAM, 50 GB disk; Linux or Windows (Docker Desktop with WSL 2); AMD64 or ARM64
Ports443 dashboard, 1514 and 1515 agents, 55000 server API, 9200 indexer API, 514/udp syslog
LicenceGPLv2 and Apache 2.0 (the quickstart page and the LICENSE file at the release tag)
Official docsdocumentation.wazuh.com and github.com/wazuh/wazuh

Screenshot of the Wazuh dashboard modules overview with counts of total, active and disconnected agents and tiles for security events, integrity monitoring, vulnerabilities and compliance

Image: the official Wazuh project (wazuh-dashboard-plugins at v4.14.9). It comes from an older release, so the 4.14.9 dashboard looks a little different.

At a glance:

  • What it is: an agent on every machine, a manager that analyses events, an indexer that stores alerts and a dashboard to read them.
  • Project status: active and maintained. Stable is 4.14.9; 4.14.10 and 5.0.0 are release candidates. This guide stays on 4.14.9.
  • Not a firewall: Wazuh watches and alerts. To block bad IPs at your web server, use our CrowdSec guide; the two work well together.
  • Passwords: the Docker files ship with public default passwords. Changing them is a required step here, not an extra.
  • Platforms: the stack runs on Linux, or on Windows with Docker Desktop. macOS is not a documented host. Agents run natively on Linux, Windows and macOS.
  • Privacy: everything stays on your machine. The agent talks only to your manager.

How it fits together#

Agents send events to the manager. The manager hands alerts to the indexer. You open the dashboard, which reads the indexer.

Two-lane diagram: on the left an agent on each PC or server sends events to the wazuh.manager container, which sends alerts to the wazuh.indexer container that stores them in Docker volumes; on the right you reach the wazuh.dashboard container in a browser, optionally through Caddy or Traefik on port 443, and the dashboard queries the indexer

Drawn for this guide from the official single-node compose file at v4.14.9. The proxy (dashed) is optional.

Before you start#

You need one machine for the stack and, later, the machines you want to watch.

ItemSingle-node stack (official)
CPU and RAMAt least 4 cores and 8 GB for the Docker host
DiskAt least 50 GB for images and volumes
ArchitectureAMD64 or ARM64
OSLinux (Docker Engine) or Windows (Docker Desktop with WSL 2)
SoftwareDocker, Docker Compose, Git

For monitoring up to 25 agents with 90 days of alerts, the quickstart page lists 4 vCPU, 8 GiB and 50 GB. The jump to 100 agents needs 8 vCPU and 200 GB.

Linux:

Run in terminalbash
docker --version
docker compose version
git --version

Windows (PowerShell): Docker Desktop must use the WSL 2 backend.

Run in terminalpowershell
docker --version
docker compose version
git --version

Mac (Terminal): the docs list Linux and Windows hosts only. A Mac is fine as a browser and as an agent (Step 6), but run the stack on Linux or Windows.

Checklist:

  • [ ] 8 GB of RAM free for Docker (close other heavy programs)
  • [ ] 50 GB of free disk
  • [ ] Internet access: the certificate tool downloads a script from packages.wazuh.com
  • [ ] Ports 443, 1514 and 1515 free on the host
  • [ ] A password manager open: you will create three new passwords
  • [ ] For the HTTPS section only: a DNS record and ports 80 and 443

Tested by DIY Lab Hub: not yet. Every command comes from the official docs and raw files read in November 2026. We did not run them.

Step 1: Set vm.max_map_count on the Docker host#

The indexer needs more memory-mapped areas than Linux allows by default. The docs say the indexer can fail without this.

Linux#

Run in terminalbash
sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee /etc/sysctl.d/99-wazuh-max-map-count.conf
sudo sysctl --system

Windows (PowerShell)#

The docs say to run sysctl "within the WSL 2 environment". Elastic's docs (the indexer is built on the same family of software) name the Docker Desktop instance, so we use that. It is not kept after a restart of Docker Desktop.

Run in terminalpowershell
wsl -d docker-desktop -u root
sysctl -w vm.max_map_count=262144
exit

Mac (Terminal)#

Not a documented host. Do this step on your Linux or Windows machine.

Check it worked. On Linux:

Run in terminalbash
sysctl vm.max_map_count

Expected: vm.max_map_count = 262144.

Tip: On Windows, repeat this after every Docker Desktop restart. A missing setting is the classic reason the indexer will not start.

Step 2: Download the official files at the right tag and make certificates#

Wazuh keeps its Docker files in a Git repository. Clone the exact release tag, never the default branch: main is the development branch.

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/wazuh
cd ~/docker_volumes/wazuh
git clone https://github.com/wazuh/wazuh-docker.git -b v4.14.9
cd wazuh-docker/single-node
docker compose -f generate-indexer-certs.yml run --rm generator
ls config/wazuh_indexer_ssl_certs

Windows (PowerShell)#

Codepowershell
New-Item -ItemType Directory -Force "$HOME\docker_volumes\wazuh" | Out-Null
Set-Location "$HOME\docker_volumes\wazuh"
git clone https://github.com/wazuh/wazuh-docker.git -b v4.14.9
Set-Location wazuh-docker\single-node
docker compose -f generate-indexer-certs.yml run --rm generator
Get-ChildItem config\wazuh_indexer_ssl_certs

Mac (Terminal)#

Not a documented host. One open issue (number 2045) reports Permission denied from this certificate step on macOS with Colima.

Check it worked. The folder lists root-ca.pem, root-ca-manager.pem, wazuh.indexer.pem, wazuh.manager.pem, wazuh.dashboard.pem, admin.pem and the matching -key.pem files. These are self-signed certificates for traffic between the containers.

The official compose file keeps Wazuh's data in Docker named volumes, which Docker stores itself. Configuration and certificates live in the folder you just created, ~/docker_volumes/wazuh/wazuh-docker/single-node.

Tip: Never share the config folder. It holds the root CA private key and, after Step 5, your password hashes.

Step 3: Keep the admin ports private#

The official file publishes the indexer API (9200) and the server API (55000) on every interface, with default passwords. Only agents (1514, 1515) and your browser (443) need to reach the host. A Compose override file changes this without editing the official file. It is read automatically and needs Docker Compose 2.24.4 or newer for !override.

Linux#

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
cat > docker-compose.override.yml << 'EOF'
services:
  wazuh.manager:
    ports: !override
      - "1514:1514"
      - "1515:1515"
      - "127.0.0.1:55000:55000"
  wazuh.indexer:
    ports: !override
      - "127.0.0.1:9200:9200"
EOF
docker compose config --quiet && echo "compose file OK"

This also drops the 514/udp syslog port. Add "514:514/udp" back to the manager list if you want devices to send syslog to Wazuh.

Windows (PowerShell)#

Codepowershell
Set-Location "$HOME\docker_volumes\wazuh\wazuh-docker\single-node"
@'
services:
  wazuh.manager:
    ports: !override
      - "1514:1514"
      - "1515:1515"
      - "127.0.0.1:55000:55000"
  wazuh.indexer:
    ports: !override
      - "127.0.0.1:9200:9200"
'@ | Set-Content -Encoding utf8 docker-compose.override.yml
docker compose config --quiet; if ($?) { "compose file OK" }

Mac (Terminal)#

Not a documented host; see Step 1.

Check it worked. The command prints compose file OK. If you see an error about an unknown tag, update Docker Compose.

Tip: Docker publishes ports around host firewalls such as ufw. Binding to 127.0.0.1 in the file is the reliable way to keep a port private.

Step 4: Start the stack and open the dashboard#

Linux#

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
docker compose up -d
docker compose ps

Windows (PowerShell)#

Codepowershell
Set-Location "$HOME\docker_volumes\wazuh\wazuh-docker\single-node"
docker compose up -d
docker compose ps

Mac (Terminal)#

Not a documented host. Open the dashboard from your Mac in a browser (next paragraph).

Open https://<DOCKER_HOST_IP> (or https://localhost on the same machine). The browser warns about the certificate because it is self-signed; that is expected until you add real HTTPS below. The docs give the default login: user admin, password SecretPassword.

Check it worked. The indexer needs about a minute to start. Until then the dashboard container logs Wazuh dashboard server is not ready yet, and you may see Failed to connect to Wazuh indexer port 9200. The docs call this normal. docker compose ps should show three running containers, and you can log in.

Tip: Log in once to see it work, then do Step 5 straight away. Do not leave SecretPassword on a machine other people can reach.

Step 5: Change the default passwords#

Three accounts matter: admin and kibanaserver (indexer users) and wazuh-wui (server API user). The docs warn that you can change only one indexer user at a time. Follow the order exactly: a changed password in the compose file alone does nothing (issue 838).

  1. Log out of the dashboard first, or old session cookies cause errors.
  2. In docker-compose.yml, replace every SecretPassword (admin) with your new one, in both the manager and the dashboard sections. If it contains $, double it (Secret$$Password).
  3. Stop the stack and make a hash of the new password.
  4. Put the hash into config/wazuh_indexer/internal_users.yml, under admin: (hash: "<NEW_HASH>").
  5. Start the stack and apply the change inside the indexer container.

Linux#

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
docker compose down
docker run --rm -ti wazuh/wazuh-indexer:4.14.9 bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/hash.sh
nano config/wazuh_indexer/internal_users.yml
docker compose up -d
docker compose exec wazuh.indexer bash

Enter the new password at the hash prompt and copy the hash. Inside the indexer container, wait one to five minutes after start, then run the docs' commands:

Run in terminalbash
export INSTALLATION_DIR=/usr/share/wazuh-indexer
export CONFIG_DIR=$INSTALLATION_DIR/config
CACERT=$CONFIG_DIR/certs/root-ca.pem
KEY=$CONFIG_DIR/certs/admin-key.pem
CERT=$CONFIG_DIR/certs/admin.pem
export JAVA_HOME=/usr/share/wazuh-indexer/jdk
bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -cd $CONFIG_DIR/opensearch-security/ -nhnv -cacert $CACERT -cert $CERT -key $KEY -p 9200 -icl
exit

For wazuh-wui, change API_PASSWORD in the manager and dashboard sections of docker-compose.yml and password: in config/wazuh_dashboard/wazuh.yml, then docker compose down and docker compose up -d. The docs require 8 to 64 characters with an upper-case letter, a lower-case letter, a number and a symbol; otherwise the manager will not start.

Windows (PowerShell)#

Edit the two files in Notepad (notepad docker-compose.yml, notepad config\wazuh_indexer\internal_users.yml). The Docker commands are the same as on Linux:

Run in terminalpowershell
docker compose down
docker run --rm -ti wazuh/wazuh-indexer:4.14.9 bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/hash.sh
docker compose up -d
docker compose exec wazuh.indexer bash

Then run the export and securityadmin.sh block from the Linux tab inside the container.

Mac (Terminal)#

Not a documented host.

Check it worked. Refresh the dashboard and log in as admin with the new password. The old one is refused.

Tip: internal_users.yml also ships demo users (kibanaro, logstash, readall, snapshotrestore). The docs only walk through admin and kibanaserver. If you do not need the others, delete their blocks before you run the apply step; custom users you want to keep must stay in that file.

Step 6: Connect your first agent#

The agent is the part that watches a machine. It talks to the manager on port 1515 once (enrolment) and then on 1514. Use the Docker host's address as <DOCKER_HOST_IP>. The manager must be the same version as the agent or newer, so install 4.14.9 agents.

Linux#

Debian and Ubuntu, as root (the docs also cover Yum, DNF and ZYpp):

Run in terminalbash
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="<DOCKER_HOST_IP>" apt-get install wazuh-agent
sudo systemctl daemon-reload
sudo systemctl enable --now wazuh-agent

Windows (PowerShell)#

Run PowerShell as administrator:

Codepowershell
Invoke-WebRequest -Uri https://packages.wazuh.com/4.x/windows/wazuh-agent-4.14.9-1.msi -OutFile wazuh-agent-4.14.9-1.msi
msiexec.exe /i .\wazuh-agent-4.14.9-1.msi /q WAZUH_MANAGER="<DOCKER_HOST_IP>"
Start-Service wazuhsvc

Mac (Terminal)#

Apple silicon shown; for Intel use the intel64 file name (macOS Big Sur or later for Apple silicon).

Run in terminalbash
curl -O https://packages.wazuh.com/4.x/macos/wazuh-agent-4.14.9-1.arm64.pkg
echo "WAZUH_MANAGER='<DOCKER_HOST_IP>'" > /tmp/wazuh_envs && sudo installer -pkg wazuh-agent-4.14.9-1.arm64.pkg -target /
sudo launchctl bootstrap system /Library/LaunchDaemons/com.wazuh.agent.plist

Check it worked. On the Docker host:

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
docker compose exec wazuh.manager /var/ossec/bin/agent_control -l

Your machine appears as Active. In the dashboard, open Agents; the docs also point you there. The docs' expected format is ID: 001, Name: <host>, IP: <ip>, Active.

Tip: Do not run the agent as a container on your Docker host and expect it to watch the host. The docs say the containerized agent cannot monitor the host system. Install it natively, as above.

Put it behind HTTPS (with or without Traefik)#

The dashboard already speaks HTTPS, but with Wazuh's own certificate, so browsers warn. A reverse proxy in front gives you a trusted certificate and one clean address. Skip this section if you only use the dashboard at home and accept the warning. Both routes need a DNS name that points to the Docker host.

The dashboard listens with HTTPS on 5601 inside the container, so the proxy must connect to it over HTTPS and trust Wazuh's root CA. Both routes use the same Compose change. Replace docker-compose.override.yml with this (it keeps Step 3 and removes the dashboard's host port):

File contentyaml
services:
  wazuh.manager:
    ports: !override
      - "1514:1514"
      - "1515:1515"
      - "127.0.0.1:55000:55000"
  wazuh.indexer:
    ports: !override
      - "127.0.0.1:9200:9200"
  wazuh.dashboard:
    ports: !reset []
    networks:
      - default
      - proxy

networks:
  proxy:
    external: true

Create the shared network once, then restart: docker network create proxy and docker compose up -d.

With Traefik#

On a server that already runs Traefik v3 (v3.7.17 is current) with the Docker and File providers. Add these labels to wazuh.dashboard in the override file, using your own entrypoint name and domain:

File contentyaml
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.wazuh.rule=Host(`wazuh.<your-domain>`)"
      - "traefik.http.routers.wazuh.entrypoints=https"
      - "traefik.http.routers.wazuh.tls=true"
      - "traefik.http.services.wazuh.loadbalancer.server.port=5601"
      - "traefik.http.services.wazuh.loadbalancer.server.scheme=https"
      - "traefik.http.services.wazuh.loadbalancer.serverstransport=wazuh@file"

Traefik's docs say a ServersTransport must be defined with the File provider, not labels. Copy config/wazuh_indexer_ssl_certs/root-ca.pem into the Traefik container (for example at /certs/wazuh-root-ca.pem) and add this to your dynamic configuration folder:

File contentyaml
http:
  serversTransports:
    wazuh:
      serverName: "wazuh.dashboard"
      rootCAs:
        - "/certs/wazuh-root-ca.pem"

The certificate Wazuh's tool creates for the dashboard names wazuh.dashboard, which is why serverName is set. We read this in the tool's script; we did not run it.

Check it worked. curl -I https://wazuh.<your-domain>/ returns an HTTP status over HTTPS, and the browser shows a valid padlock.

Without Traefik: Caddy#

Choose this if you have no Traefik. Caddy gets and renews its own certificates: Let's Encrypt for a public domain, or tls internal for a local one at home.

Run in terminalbash
mkdir -p ~/docker_volumes/caddy/{conf,data,config}
cp ~/docker_volumes/wazuh/wazuh-docker/single-node/config/wazuh_indexer_ssl_certs/root-ca.pem ~/docker_volumes/caddy/conf/wazuh-root-ca.pem

Save ~/docker_volumes/caddy/docker-compose.yml. It mounts the whole conf folder, because Caddy's Docker docs warn against single-file mounts. The image tag 2.11.8 exists on Docker Hub (2.11.9 was released today but was not yet published as an image):

File contentyaml
services:
  caddy:
    image: caddy:2.11.8
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
      - "443:443/udp"
    volumes:
      - ./conf:/etc/caddy
      - ./data:/data
      - ./config:/config
    networks:
      - proxy

networks:
  proxy:
    external: true

Save ~/docker_volumes/caddy/conf/Caddyfile. Caddy's docs show tls_trust_pool and tls_server_name for an HTTPS upstream you trust:

File contenttext
wazuh.example.com {
    reverse_proxy https://wazuh.dashboard:5601 {
        transport http {
            tls_trust_pool file /etc/caddy/wazuh-root-ca.pem
            tls_server_name wazuh.dashboard
        }
    }
}

For a home-only name, add tls internal as the first line inside the block (use a name like wazuh.home.arpa). Start it:

Run in terminalbash
cd ~/docker_volumes/caddy && docker compose up -d

On Windows run the same files from $HOME\docker_volumes\caddy with Docker Desktop; on a Mac, use a Linux or Windows host. For a home-only certificate, copy Caddy's root (docker exec caddy find /data -name root.crt, then docker cp) to each device and trust it: on Windows in "Trusted Root Certification Authorities", on macOS in Keychain Access, on Linux in your CA store. Those OS steps are not from Caddy's docs.

Check it worked. curl -I https://wazuh.example.com/ returns an HTTP status line. We did not test this proxy setup, so if the login page loops, check docker logs caddy --tail 50.

Tip: Do not use tls_insecure_skip_verify to "make the error go away". Caddy's docs call it not recommended; the trust pool above takes two lines.

Security and testing#

A SIEM that is easy to break into is worse than none. Check these.

ControlHow
Default passwordsChanged in Step 5 for admin, kibanaserver and wazuh-wui
Indexer and server APIBound to 127.0.0.1 (Step 3); never forward 9200 or 55000 on your router
Agent ports1514 and 1515 only to your own network; never forward them to the internet
Config folderHolds the root CA key and hashes: readable only by you (chmod -R go-rwx config on Linux)
DashboardOnly through HTTPS; the compose file sets a 15-minute session
RepositoryAgents' package repo disabled after install, as the docs advise, so upgrades are your decision

Tests after each change:

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
docker compose ps
docker compose logs --tail=100 wazuh.manager
docker compose logs --tail=100 wazuh.indexer
curl -I https://wazuh.<your-domain>/

Windows and Mac can use curl.exe -I (PowerShell) or curl -I (Terminal) against the dashboard address; run the Docker commands in the stack folder.

What to try first#

Make a failed SSH login on a Linux agent and look in Security events a minute later. Wazuh's active response can block such a source automatically; the docs have an SSH brute-force example. We did not test it.

Common mistakes#

These come from the official docs and real reports in the wazuh-docker issue tracker.

MistakeWhy it happensDo this instead
Cloning without -b v4.14.9The repository's default branch is development (README "Branch Convention"). Issues 2742 and 2792 show 5.0 images use other credential filesAlways clone with -b v4.14.9 and use docs for the same version
Skipping vm.max_map_countThe setting is not a Docker setting; it belongs to the kernel of the host or WSL 2 VMDo Step 1; on Windows repeat it after Docker Desktop restarts
Starting with too little RAMIssue 1699 shows wazuh.indexer exited with code 137 followed by endless "not ready yet"Give Docker at least 8 GB; check docker stats and docker compose logs wazuh.indexer
Leaving SecretPasswordThe docs list it as the default; issue 906's author wanted to expose the dashboard publiclyDo Step 5 before anything else can reach the host
Changing the password only in the compose fileThe indexer stores a hash. Issue 838: the password "did not get used"; maintainers say follow the full procedureHash it, edit internal_users.yml, run securityadmin.sh
Debugging the dashboard in the first minuteThe docs say the indexer needs about a minute, and the log shows "not ready yet" meanwhileWait two minutes first. If it persists (issues 999 and 1699), read the indexer log
Skipping the firewall check for the certificate stepIssue 736: certificates failed when firewalld started after the Docker network existedRestart Docker after changing the firewall, and make sure the host reaches packages.wazuh.com
Installing an agent newer than the managerThe docs guarantee compatibility only when the manager is the same or newerInstall 4.14.9 agents; disable the package repository after installing
Running docker compose down -vThe uninstall docs: -v deletes all Wazuh data, configurations and logsUse down without -v, except when you want to start fresh
AI assistants: mixing install routesAssistants copy the assisted installer's random password from wazuh-passwords.txt, /var/ossec host paths or wazuh-install.sh into a Docker answerIn Docker the default is admin / SecretPassword; run manager tools with docker compose exec
AI assistants: suggesting 5.x or Elastic namesAssistants mention Kibana, ELASTIC_PASSWORD or 5.0 file namesUse only the 4.14.9 file names in this guide

Tip: After every change, read docker compose logs --tail=100 wazuh.manager first. Most configuration mistakes print a clear line there.

Tip: Back up config/ before you edit it. The password change touches several files, and one wrong edit can lock you out.

Tip: Alerts keep growing. Plan disk space before you add many agents, not after the indexer fills it.

Troubleshooting#

ProblemSolution
Wazuh dashboard server is not ready yetWait two minutes. Still there? docker compose logs wazuh.indexer --tail 100; check RAM and vm.max_map_count
wazuh.indexer exited with code 137The process was killed; low memory is a common cause (our reading). Raise Docker's memory or close programs
Browser certificate warningExpected with Wazuh's self-signed certificate. Use the HTTPS section for a trusted one
Agent shows Never connectedCheck the host address, ports 1514 and 1515 (Test-NetConnection <DOCKER_HOST_IP> -Port 1514 on Windows), and the agent log
Permission denied during certificate creationReported on macOS with Colima (issue 2045, open). Use a Linux or Windows host
Certificate step cannot download the toolThe generator fetches wazuh-certs-tool.sh from packages.wazuh.com; check internet and firewall
Manager will not start after a password changeThe wazuh-wui password must be 8 to 64 characters with upper, lower, number and symbol
maximum shards open [1000]/[1000]Issue 1437 (open). A community workaround raises cluster.max_shards_per_node; the real fix is an index retention policy (see the docs' index lifecycle management page)
Config error after cloning another tagIssue 2079 (open) shows ossec.conf errors on a v4.14.1 clone; our reading: files and images came from different versions. Re-clone the tag you pin

Diagnostics:

Run in terminalbash
docker compose ps
docker compose logs --tail=100 wazuh.manager
docker compose logs --tail=100 wazuh.indexer
docker compose logs --tail=100 wazuh.dashboard
docker stats --no-stream

Known bugs (open, November 2026)#

  • Issue 2771: the 4.14 manager and agent images have no diff tool, so file integrity monitoring with report_changes never shows what changed.
  • Issue 2045: certificate creation fails on macOS with Colima.
  • Issue 1437: the 1,000-shard limit can stop the dashboard from starting on a long-running stack.

Updates and backups#

Update. Read the release notes first. The docs' default route replaces the Compose files with the new tag's. Back up, then:

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
docker compose down
git fetch --all --tags
git checkout v<NEW_VERSION>
docker compose up -d

The docs say data and certificates stay in volumes. Keep your override file and passwords: if git checkout refuses because you edited tracked files, stash or copy your edits first. Wait for a stable release; today's candidates (4.14.10 and 5.0.0) are not for production.

Back up. The official file has no backup tool, so we use Docker's own volume-backup pattern. This stops the stack briefly, saves every Wazuh volume and the config folder:

Run in terminalbash
cd ~/docker_volumes/wazuh/wazuh-docker/single-node
mkdir -p ~/docker_volumes/wazuh/backups
docker compose down
for v in $(docker volume ls -q --filter "label=com.docker.compose.project=single-node"); do
  docker run --rm -v "$v":/data:ro -v ~/docker_volumes/wazuh/backups:/backup alpine:3.23 tar czf "/backup/$v-$(date +%F).tar.gz" -C /data .
done
tar czf ~/docker_volumes/wazuh/backups/wazuh-config-$(date +%F).tar.gz config docker-compose.override.yml
chmod 600 ~/docker_volumes/wazuh/backups/*.tar.gz
docker compose up -d

The project name is the folder name (single-node). Run it weekly, not nightly: the stack is down while it runs. On Linux a cron job at 03:00 works. The archives hold keys and hashes, so copy them to another machine and never to a shared folder.

Restore test. Unpack one archive into a throw-away volume and list it:

Run in terminalbash
docker volume create restore-test
docker run --rm -v restore-test:/data -v ~/docker_volumes/wazuh/backups:/backup alpine:3.23 tar xzf /backup/<volume-archive>.tar.gz -C /data
docker run --rm -v restore-test:/data alpine:3.23 ls /data
docker volume rm restore-test

Windows (PowerShell)#

The same idea in PowerShell (not run by us). Windows Task Scheduler can repeat it weekly:

Codepowershell
Set-Location "$HOME\docker_volumes\wazuh\wazuh-docker\single-node"
$backup = "$HOME\docker_volumes\wazuh\backups"
New-Item -ItemType Directory -Force $backup | Out-Null
docker compose down
foreach ($v in docker volume ls -q --filter "label=com.docker.compose.project=single-node") {
  docker run --rm -v "${v}:/data:ro" -v "${backup}:/backup" alpine:3.23 tar czf "/backup/$v-$(Get-Date -Format yyyy-MM-dd).tar.gz" -C /data .
}
docker compose up -d

Mac (Terminal)#

Not a documented host.

Performance and resources#

  • Documented needs: 4 cores, 8 GB RAM and 50 GB disk for a single node. We did not measure idle use, so we give no RAM figure of our own.
  • Heap: the compose file starts the indexer with a 1 GB heap (-Xms1g -Xmx1g). The tuning page recommends half the system RAM with both values equal, for example 4 GB on an 8 GB host. Change OPENSEARCH_JAVA_OPTS in docker-compose.yml only after the stack is stable.
  • Download size: the manager image is about 1.0 GB, the indexer about 1.1 GB and the dashboard about 0.5 GB (compressed, from Docker Hub).
  • Watch it: docker stats shows live CPU and memory per container.
  • Scaling: for more than 100 agents the docs recommend a distributed deployment; the multi-node stack needs 16 GB and 100 GB.

FAQ#

Is Wazuh free? Yes. The docs say its components follow the GPL version 2 and the Apache License 2.0. There is also a paid cloud and support service, which you do not need here.

Is Wazuh the same as CrowdSec? No. CrowdSec reads web logs and blocks bad IPs; Wazuh watches your machines for changes, logins and vulnerabilities. See our CrowdSec guide. Use both if you want blocking and visibility.

Can I run it on a Raspberry Pi? ARM64 is supported, but the docs ask for 8 GB of RAM. A Pi with less is not advised.

Does it need a GPU? No. The docs do not mention one.

Does Wazuh send my data to the project? The docs describe no telemetry for the Docker stack, but we did not inspect network traffic. Agents report only to your manager.

Can I use a Mac as the server? The docs list Linux and Windows. Use a Mac as an agent and a browser, and see our Caddy guide for HTTPS.

Sources#

Checked against the official docs on 2026-11-05.