NODE_STATUS: ACTIVE
DOC: INFRA_GUIDE // DOC-001
PLATFORM: FEDORA_42 // WAZUH_4.9
SECTIONS: 13
SYS_TIME: --:--:--
[ DOC-001 // INFRASTRUCTURE_GUIDE ] Author: Kathlyn · v1.0.4
FIELD MANUAL | COMPLETE SETUP WALKTHROUGH

Infrastructure
Guide

Complete step-by-step walkthrough of the SOCHomeLab server setup — from bare Fedora 42 to a fully operational Wazuh stack with SSL, Filebeat, and OpenSearch.

Written by Kathlyn · Infrastructure Engineer
Fedora 42 Wazuh 4.9 OpenSearch Filebeat SSH Hardening firewalld SSL/PKI
[ TABLE OF CONTENTS ] 13 SECTIONS
01
[ LAYER: HARDWARE // HOST ]

Environment

HardwareIntel NUC mini PC
OSFedora 42
Server IP192.168.1.33 — DHCP reservation on router
Gateway192.168.1.254
Interfacewlp2s0 (WiFi)
RAM15 GB
WorkstationThinkPad T14 — Fedora 42 — 192.168.1.185
02
[ LAYER: BASE_OS // INITIAL_CONFIG ]

Fedora Server Setup

Check Fedora version

bash
cat /etc/fedora-release
uname -r

Update everything first

bash
sudo dnf update -y && sudo dnf upgrade -y
Wait for this to fully complete before moving on to any other step.
03
[ LAYER: NETWORK // DHCP_RESERVATION ]

Network Configuration

Rather than configuring a static IP on the OS side, we used a DHCP reservation on the router. The router always assigns 192.168.1.33 to the NUC based on its MAC address. This is cleaner than OS-level static IP config.

bash
ip a
ping google.com -c 4
04
[ LAYER: IAM // USER_ADMIN ]

User Accounts

bash
# Create account with sudo access
sudo useradd -m -G wheel katato
sudo passwd katato

# Verify wheel group membership
getent group wheel
💡 For a production setup, create separate accounts per team member. Shared accounts mean no individual accountability in audit logs.
05
[ LAYER: REMOTE_ACCESS // SSH_HARDENING ]

SSH Hardening

Install and enable SSH server

bash
sudo dnf install -y openssh-server
sudo systemctl enable --now sshd
sudo systemctl status sshd

Generate SSH keys (on your client device, not the server)

bash // client
ssh-keygen -t ed25519 -C "katato"
ssh-copy-id -p 7389 katato@192.168.1.33

Test passwordless login

bash // client
ssh -p 7389 katato@192.168.1.33

Harden sshd_config

/etc/ssh/sshd_config
Port 7389
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
bash — apply config
sudo systemctl restart sshd
Keep your current session open and test in a new terminal before closing. If you get locked out, fix the config from the local terminal.

SSH client shortcut (on your client device)

~/.ssh/config
Host intelnuc
    HostName 192.168.1.33
    User katato
    Port 7389

Now just type ssh intelnuc to connect from anywhere.

06
[ LAYER: PERIMETER // FIREWALLD ]

Firewall Configuration

PortServicePurpose
7389SSHRemote access — non-default port for security
443HTTPSWazuh dashboard
1514TCPWazuh agent communication
1515TCPWazuh agent registration
9200TCPOpenSearch / Wazuh indexer
55000TCPWazuh API
bash
sudo systemctl enable --now firewalld

# Custom SSH port
sudo firewall-cmd --permanent --add-port=7389/tcp
sudo firewall-cmd --permanent --remove-service=ssh

# Application ports
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=1514/tcp
sudo firewall-cmd --permanent --add-port=1515/tcp
sudo firewall-cmd --permanent --add-port=9200/tcp
sudo firewall-cmd --permanent --add-port=55000/tcp

# Apply and verify
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
07
[ LAYER: PATCHING // DNF_AUTOMATIC ]

Automatic Updates

bash
sudo dnf install -y dnf-automatic
sudo nano /etc/dnf/automatic.conf
/etc/dnf/automatic.conf
apply_updates = yes
bash
sudo systemctl enable --now dnf-automatic-install.timer
sudo systemctl status dnf-automatic-install.timer
08
[ LAYER: HIDS // WAZUH_INSTALL ]

Wazuh HIDS Installation

Add the Wazuh repository

bash
sudo rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH

sudo tee /etc/yum.repos.d/wazuh.repo << EOF
[wazuh]
gpgcheck=1
gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH
enabled=1
name=Wazuh repository
baseurl=https://packages.wazuh.com/4.x/yum/
protect=1
EOF

Install components

bash
sudo dnf install -y wazuh-manager
sudo systemctl enable --now wazuh-manager

sudo dnf install -y wazuh-indexer wazuh-dashboard
If the manager is already installed before running the install script, it will exit early without generating SSL certificates. See Section 09 to handle this manually.
09
[ LAYER: PKI // SSL_CERTIFICATES ]

SSL Certificate Setup

Required if the all-in-one installer was interrupted or run on a system with existing Wazuh components.

Generate certificates

bash
curl -sO https://packages.wazuh.com/4.9/wazuh-certs-tool.sh
config.yml
nodes:
  indexer:
    - name: node-1
      ip: "192.168.1.33"
  server:
    - name: wazuh-1
      ip: "192.168.1.33"
  dashboard:
    - name: dashboard
      ip: "192.168.1.33"
bash
sudo bash wazuh-certs-tool.sh -A
ls wazuh-certificates/

Copy certs to indexer

bash
sudo mkdir -p /etc/wazuh-indexer/certs
sudo cp /home/katato/wazuh-certificates/root-ca.pem /etc/wazuh-indexer/certs/
sudo cp /home/katato/wazuh-certificates/node-1.pem /etc/wazuh-indexer/certs/indexer.pem
sudo cp /home/katato/wazuh-certificates/node-1-key.pem /etc/wazuh-indexer/certs/indexer-key.pem
sudo cp /home/katato/wazuh-certificates/admin.pem /etc/wazuh-indexer/certs/
sudo cp /home/katato/wazuh-certificates/admin-key.pem /etc/wazuh-indexer/certs/
sudo chown -R wazuh-indexer:wazuh-indexer /etc/wazuh-indexer/certs/
sudo chmod 500 /etc/wazuh-indexer/certs/
sudo chmod 400 /etc/wazuh-indexer/certs/*

Copy certs to dashboard

bash
sudo mkdir -p /etc/wazuh-dashboard/certs
sudo cp /home/katato/wazuh-certificates/root-ca.pem /etc/wazuh-dashboard/certs/
sudo cp /home/katato/wazuh-certificates/dashboard.pem /etc/wazuh-dashboard/certs/
sudo cp /home/katato/wazuh-certificates/dashboard-key.pem /etc/wazuh-dashboard/certs/
sudo chown -R wazuh-dashboard:wazuh-dashboard /etc/wazuh-dashboard/certs/
sudo chmod 500 /etc/wazuh-dashboard/certs/
sudo chmod 400 /etc/wazuh-dashboard/certs/*

Copy certs for Filebeat

bash
sudo mkdir -p /etc/filebeat/certs
sudo cp /home/katato/wazuh-certificates/root-ca.pem /etc/filebeat/certs/
sudo cp /home/katato/wazuh-certificates/wazuh-1.pem /etc/filebeat/certs/filebeat.pem
sudo cp /home/katato/wazuh-certificates/wazuh-1-key.pem /etc/filebeat/certs/filebeat-key.pem
sudo chown -R root:root /etc/filebeat/certs/
sudo chmod 500 /etc/filebeat/certs/
sudo chmod 400 /etc/filebeat/certs/*
10
[ LAYER: SYSTEMD // SERVICE_STARTUP ]

Wazuh Services

Start in this exact order — each service depends on the previous:

bash — startup sequence
# 1 — Indexer first
sudo systemctl enable --now wazuh-indexer
sudo systemctl status wazuh-indexer --no-pager | grep Active

# Wait 30 seconds then initialize security
sudo /usr/share/wazuh-indexer/bin/indexer-security-init.sh

# 2 — Manager
sudo systemctl restart wazuh-manager
sleep 20
sudo systemctl status wazuh-manager --no-pager | grep Active

# 3 — Dashboard last
sudo systemctl restart wazuh-dashboard
sleep 20
sudo systemctl status wazuh-dashboard --no-pager | grep Active

Access the dashboard

🌐 Open https://192.168.1.33 in your browser. Accept the self-signed certificate warning — Chrome: Advanced → Proceed · Firefox: Advanced → Accept the Risk

Install Wazuh agent on ThinkPad

Run this on the ThinkPad, not the NUC:

bash — ThinkPad T14
sudo rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH

sudo tee /etc/yum.repos.d/wazuh.repo << EOF
[wazuh]
gpgcheck=1
gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH
enabled=1
name=Wazuh repository
baseurl=https://packages.wazuh.com/4.x/yum/
protect=1
EOF

sudo WAZUH_MANAGER="192.168.1.33" dnf install -y wazuh-agent
sudo systemctl enable --now wazuh-agent
bash — verify on NUC
sudo /var/ossec/bin/agent_control -l
11
[ LAYER: LOG_PIPELINE // FILEBEAT ]

Filebeat Setup

Filebeat ships Wazuh alerts from log files into OpenSearch.

bash
sudo dnf install -y filebeat

sudo curl -so /etc/filebeat/filebeat.yml \
  https://packages.wazuh.com/4.9/tpl/wazuh/filebeat/filebeat.yml

sudo curl -so /etc/filebeat/wazuh-template.json \
  https://raw.githubusercontent.com/wazuh/wazuh/v4.9.2/extensions/elasticsearch/7.x/wazuh-template.json
/etc/filebeat/filebeat.yml — output section
output.elasticsearch:
  hosts: ["192.168.1.33:9200"]
  protocol: https
  username: "admin"
  password: "your_password_here"
  ssl.certificate_authorities:
    - /etc/filebeat/certs/root-ca.pem
  ssl.certificate: "/etc/filebeat/certs/filebeat.pem"
  ssl.key: "/etc/filebeat/certs/filebeat-key.pem"
bash
sudo systemctl enable --now filebeat

# Verify alerts are flowing
curl -s -k -u admin:admin \
  "https://192.168.1.33:9200/_cat/indices?v" | grep wazuh-alerts
12
[ LAYER: VERIFICATION // HEALTH_CHECK ]

Health Check

Run this any time to verify all core services are healthy:

bash — full health check
echo "=== SERVICES ===" && \
sudo systemctl status wazuh-manager wazuh-indexer wazuh-dashboard \
  filebeat --no-pager | grep -E "●|Active" && \
echo "" && \
echo "=== CLUSTER HEALTH ===" && \
curl -s -k -u admin:admin \
  "https://192.168.1.33:9200/_cluster/health?pretty" | grep -E "status|number_of_nodes" && \
echo "" && \
echo "=== ALERTS IN OPENSEARCH ===" && \
curl -s -k -u admin:admin \
  "https://192.168.1.33:9200/_cat/indices?v" | grep wazuh-alerts && \
echo "" && \
echo "=== AGENT STATUS ===" && \
sudo /var/ossec/bin/agent_control -l

Expected healthy output

ServiceExpected Status
wazuh-manageractive (running)
wazuh-indexeractive (running)
wazuh-dashboardactive (running)
filebeatactive (running)
OpenSearch clustergreen or yellow
wazuh-alerts indexdoc count > 0
ThinkPad T14 agentActive
13
[ LAYER: POST_MORTEM // LESSONS ]

Lessons Learned

[ SSL // CERT_BOOTSTRAPPING ]

The Wazuh all-in-one installer assumes a clean system. If any Wazuh component is already installed it exits early without generating or placing SSL certificates. The fix is to run wazuh-certs-tool.sh manually and copy each cert file to its correct directory with correct ownership and permissions.

bash — always back up certs
sudo cp -r /etc/wazuh-indexer/certs /etc/wazuh-indexer/certs.bak
[ CONFIG // OSSEC_XML_CORRUPTION ]

The manager config file can become corrupted if edited incorrectly. Always validate XML before restarting. Back up the config before every edit.

bash — validate XML
sudo python3 -c "
import xml.etree.ElementTree as ET
try:
    ET.parse('/var/ossec/etc/ossec.conf')
    print('XML is valid')
except ET.ParseError as e:
    print(f'XML error: {e}')
"

sudo cp /var/ossec/etc/ossec.conf /var/ossec/etc/ossec.conf.bak
[ TLS // FILEBEAT_CERT_MISMATCH ]

Filebeat failed with x509: certificate is valid for 192.168.1.33, not 127.0.0.1 because the config used 127.0.0.1 as the host but the cert was generated for 192.168.1.33. Always use the actual server IP in Filebeat's output config — never localhost or 127.0.0.1.

[ OPENSEARCH // REPLICA_WARNINGS ]

Single-node clusters show yellow status because there's no second node to hold replicas. Fix by setting replicas to zero — this turns the index green immediately.

bash
curl -s -k -u admin:admin -X PUT \
  "https://192.168.1.33:9200/wazuh-alerts-*/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"number_of_replicas": 0}'