A server with a public IP starts getting login attempts and port scans within minutes of going online. Without monitoring, nobody notices. Wazuh is an open-source SIEM that combines intrusion detection, file integrity monitoring and vulnerability detection, and it runs well in Docker. This is the process I use on my own VPS.
What you need
- A Linux VPS with Docker and Docker Compose installed.
- At least 8 GB of RAM. The Wazuh indexer (built on OpenSearch) alone wants about 4 GB.
- SSH access with sudo.
1. Prepare the kernel
The indexer needs a higher virtual memory limit than the default. Without it, the container starts and dies straight away.
sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee /etc/sysctl.d/99-wazuh.conf2. Get the official stack
The wazuh-docker project ships a ready-made single-node setup. Pick the latest version on the repository's releases page and use that tag when cloning.
git clone https://github.com/wazuh/wazuh-docker.git -b v4.x.y # use the current version
cd wazuh-docker/single-node3. Generate certificates and start
The components talk to each other over TLS. The repository includes a certificate generator:
docker compose -f generate-indexer-certs.yml run --rm generator
docker compose up -d
docker compose psAfter a minute or two you should see three containers: manager, indexer and dashboard.
4. Keep the dashboard off the internet
This is the most common mistake. The docker-compose.yml publishes the dashboard on port 443 on every interface. There's an extra trap: ports published by Docker bypass UFW rules, because Docker writes straight into iptables. Your firewall can say a port is closed while it's actually open.
The fix is to bind the port to localhost only, by editing the dashboard section:
ports:
- "127.0.0.1:8443:5601"Then reach it through an SSH tunnel from your own computer and open https://localhost:8443 in the browser:
ssh -L 8443:127.0.0.1:8443 user@vps-ipChange the default passwords before using it for real, too. The official Wazuh documentation covers the process for the Docker deployment.
5. Install the agent on the host
The manager in Docker can't see the host on its own. To monitor the VPS, install the agent directly on the system and point it at the local manager. The agent version must not be newer than the manager's.
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
sudo WAZUH_MANAGER="127.0.0.1" apt install wazuh-agent
sudo systemctl enable --now wazuh-agentThe agent uses the manager's ports 1514 and 1515. If all your agents live on the same server, bind those to 127.0.0.1 as well.
What you get
- SSH logins with non-existent users and brute-force attacks, with real-time alerts.
- Changes to sensitive files such as /etc/passwd or your nginx config (File Integrity Monitoring).
- System packages with known vulnerabilities.
I pair Wazuh with Dozzle to read every container's logs in one place. Wazuh tells me something is happening; Dozzle helps me see what.
In short: lock ports down in the compose file (127.0.0.1) instead of trusting the firewall alone, reach the dashboard through an SSH tunnel, and put the agent on the host.