Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rsol9000-01/wazuh/llms.txt

Use this file to discover all available pages before exploring further.

This page walks through the complete deployment of the Wazuh Docker Stack from repository clone to first Dashboard login. The preferred deployment path uses the included wazuh-dev.sh helper script, which automates prerequisite validation, kernel tuning, password hashing, certificate generation, and the final docker compose up in a single command. By the end of this guide, all four services — Indexer, Manager, Dashboard, and Agent — will be running and the Dashboard will be accessible over HTTPS on port 6443.
The Wazuh Indexer (OpenSearch) requires the Linux kernel parameter vm.max_map_count to be at least 262144. The wazuh-dev.sh script sets this automatically at runtime using sysctl -w vm.max_map_count=262144, but this value resets on reboot. To persist it across restarts, add the following line to /etc/sysctl.conf:
echo 'vm.max_map_count=262144' >> /etc/sysctl.conf
Then reload the configuration with sudo sysctl -p.

Deployment Steps

1

Clone the Repository

Clone the Wazuh Docker Stack repository and change into the project directory:
git clone https://github.com/rsol9000/wazuh-docker.git
cd wazuh-docker
All subsequent commands in this guide assume you are running from the repository root.
2

Configure Environment Variables

Copy the example environment file to .env and edit it with your deployment-specific values:
cp .env.example .env
nano .env
The following variables must be reviewed and set before deployment:
VariableDefault (.env.example)Description
INDEXER_USERNAMEadminUsername for the Wazuh Indexer (OpenSearch) API — used by the Manager and Dashboard to authenticate
INDEXER_PASSWORD_S1M0V1L48_T7G_2025_.*-Password for the Indexer API user — change this in production
API_USERNAMEwazuh-wuiUsername for the Wazuh Manager REST API — consumed by the Dashboard
API_PASSWORDMyS3cr37P450r.*-Password for the Manager REST API user — must not contain a $ character
DASHBOARD_USERNAMEkibanaserverUsername for the Dashboard’s Indexer connection
DASHBOARD_PASSWORDkibanaserverPassword for the Dashboard’s Indexer connection — change this in production
MANAGER_SERVER10.20.203.5IP address or hostname of the Wazuh Manager, used by external agents for enrollment
NETWORKnet_00Name of the Docker internal network created for inter-service communication
SUBNET10.60.60.0/24CIDR block for the Docker internal network
GATEWAY10.60.60.1Gateway address for the Docker internal network
PROJECT_ROOT.Path to the repository root used as the Compose project base directory
NGINX_IMAGEnginx:1.29.3-alpineNGINX image tag — used when a reverse proxy is added in front of the Dashboard
GENERATE_INDEXER_FILEgenerate-indexer-certs.ymlFilename of the Compose override used to run the certificate generator container
TZ(not set)POSIX timezone string (e.g., Europe/Madrid) injected into all containers for consistent log timestamps
DOCKER_GID(auto-detected)Docker group ID on the host — automatically resolved by wazuh-dev.sh via getent group docker; set manually if deploying without the script
LOCAL_AGENT_HOSTNAME(host FQDN)Hostname assigned to the wazuh.agent container; if set to localhost, the script substitutes the actual host FQDN using hostname -f
MY_USERNAME(not set)Username for a custom administrative user to be created or updated in the Indexer’s internal_users.yml
MY_PASSWORD(not set)Password for the custom administrative user; the script hashes this using the Indexer’s hash.sh tool
The wazuh-dev.sh script reads API_USERNAME, API_PASSWORD, MY_USERNAME, and MY_PASSWORD directly from .env at runtime to patch configuration files and hash passwords before starting the stack.
3

Generate TLS Certificates

Generate the mutual TLS certificates required for secure communication between the Indexer, Manager, and Dashboard:
sudo docker compose -f generate-indexer-certs.yml run --rm generator
This command runs the wazuh/wazuh-certs-generator:0.0.3 container, which reads the node definitions from config/certs.yml and outputs the following certificate files into ./config/wazuh_indexer_ssl_certs/:
  • root-ca.pem (shared CA for Indexer and Dashboard)
  • root-ca-manager.pem (CA copy for the Manager’s Filebeat)
  • wazuh.indexer.pem / wazuh.indexer-key.pem
  • wazuh.manager.pem / wazuh.manager-key.pem
  • wazuh.dashboard.pem / wazuh.dashboard-key.pem
  • admin.pem / admin-key.pem
These files are bind-mounted into the respective containers at startup and are required before running docker compose up.
4

Deploy with wazuh-dev.sh

Launch the full stack using the deployment helper script:
sudo bash scripts/wazuh-dev.sh server up
The script performs the following steps in order:
  1. Detects the Docker GID — resolves the host docker group ID via getent group docker and exports it as DOCKER_GID so the agent container can access /var/run/docker.sock
  2. Sets vm.max_map_count — checks the current value; if it is below 262144, runs sysctl -w vm.max_map_count=262144 automatically
  3. Validates dependencies — confirms that docker and curl are available on the host PATH
  4. Validates required files — checks for .env, docker-compose.yml, config/wazuh_indexer/internal_users.yml, and generate-indexer-certs.yml
  5. Resolves the agent hostname — reads LOCAL_AGENT_HOSTNAME from .env; substitutes the real FQDN if the value is localhost
  6. Patches API credentials — updates config/wazuh_dashboard/wazuh.yml with the API_USERNAME and API_PASSWORD values from .env
  7. Hashes the custom user password — runs wazuh/wazuh-indexer:4.14.5 to execute hash.sh against MY_PASSWORD and writes the bcrypt hash into internal_users.yml
  8. Generates TLS certificates — runs docker compose -f generate-indexer-certs.yml run --rm generator
  9. Starts the stack — executes docker compose -f docker-compose.yml --env-file .env up -d
The server argument selects docker-compose.yml (the full four-service stack). Use agent to deploy only the agent via agent/docker-compose-agent.yml. The second argument controls the Compose action and defaults to up when omitted; all supported actions are listed below.
ActionCommandDescription
upbash scripts/wazuh-dev.sh server upStart the stack in detached mode (default)
downbash scripts/wazuh-dev.sh server downStop and remove all containers
logsbash scripts/wazuh-dev.sh server logsTail logs for all services
psbash scripts/wazuh-dev.sh server psShow container status
restartbash scripts/wazuh-dev.sh server restartRestart all running containers
5

Verify the Stack

Confirm all containers are running and healthy:
docker compose ps
All four services — wazuh.indexer, wazuh.manager, wazuh.dashboard, and wazuh.agent — should show a status of running. Follow the Manager logs to watch the initial startup sequence:
docker compose logs -f wazuh.manager
Look for Filebeat successfully connecting to the Indexer and the Manager API becoming available on port 55000. The Indexer health check runs every 30 seconds with up to 3 retries; the Manager and Dashboard health checks run every 10 seconds with up to 10 retries.
6

Access the Dashboard

Open a browser and navigate to the Dashboard on the secure HTTPS port:
https://<your-host>:6443
Log in with the credentials set in your .env file:
  • Username: the value of DASHBOARD_USERNAME (default: kibanaserver)
  • Password: the value of DASHBOARD_PASSWORD (default: kibanaserver)
On first login you will see the Wazuh security overview. Navigate to Agents to verify that the containerized wazuh.agent has enrolled and is actively sending events to the Manager. The Dashboard communicates with the Manager API at https://wazuh.manager:55000 using the API_USERNAME and API_PASSWORD credentials.
For a quick manual deployment without the wazuh-dev.sh script — for example, if you have already generated certificates and patched the configuration files in a previous run — you can start the stack directly with:
sudo docker compose up -d
Ensure .env is populated, certificates exist in ./config/wazuh_indexer_ssl_certs/, and vm.max_map_count is already set to 262144 before using this shortcut.

Quick Health Check

Once the stack is up, use the following commands to verify each service is responding:
# Check container status and health state for all four services
docker compose ps

# Stream Manager logs to watch for startup errors or Filebeat connection issues
docker compose logs -f wazuh.manager

# Query the Indexer REST API — should return cluster health JSON (HTTP 200)
curl -k -u admin:SecretPassword https://localhost:9200

# Query the Manager REST API — should return a JSON response with version info
curl -sk https://localhost:55000
Replace SecretPassword with the value of INDEXER_PASSWORD from your .env file. The -k flag bypasses TLS certificate validation for the self-signed certificates generated in Step 3.

Build docs developers (and LLMs) love