Zabbix Or GrayLog or Any SEIM

Hello everyone,

I hope you’re all having a great holiday season. Recently, I’ve been planning to monitor and secure my entire infrastructure. Here’s a quick overview of my setup:
Proxmox: All my infrastructure runs virtually on Proxmox.
pfSense: I use a virtualized pfSense instance for managing all networking tasks within my Proxmox server.
Wazuh: I’ve installed Wazuh and deployed its agents on some of my VMs.

Now, I’m looking to implement a system that allows me to monitor all my networking gear effectively. Ideally, I’d like suggestions on tools that can:

  1. Monitor my infrastructure and networking equipment.
  2. Notify me of any issues (e.g., via Microsoft Teams using webhooks).
  3. Provide a comprehensive dashboard to visualize everything.

I’ve been considering Zabbix as it seems promising, but Wazuh feels a bit challenging to learn. Unfortunately, I recently had an accident and can’t spend too much time in front of a screen, so I need something that’s straightforward to set up and maintain while still being robust.

Here’s a summary of my current setup:
Servers: 8 websites hosted on a separate VLAN in pfSense, accessed via a Cloudflare tunnel.
Test VMs: A few test environments.
Monitoring: Currently using Uptime Kuma to track uptime for my servers and websites, but it doesn’t provide detailed information.

I’d also like to focus on improving security, perhaps by further exploring Wazuh or similar tools to make my infrastructure more secure.

I know I might sound a bit scattered, but I’d really appreciate any guidance or recommendations on monitoring tools or systems that could meet my needs.

Thanks in advance!

While zabbix can parse logs from windows and linux systems I wouldn’t consider it a true SEIM. Zabbix is good at performance metrics and monitoring.

Graylog is the go-to for a SEIM solution.

I use both in my professional setups. You’ll have to play with setting up capturing logs with zabbix to see how you like it if you don’t want both. I personally don’t mind having 2 agents running and I like that I have 2 separate systems for monitoring.

2 Likes

Right, Zabbix can be used as a log archive but it is unusable as a SIEM.
Zabbix is great for network monitoring though and for collecting historical performance data. I would encourage you to run Zabbix in addition to a SIEM, where the SIEM is used for the log data and for searching and correlating the logs.

In this forum you will find many proponents for Graylog, however, if you don’t want to build the SIEM functionality (as in ready-made dashboards, preconfigured searches, point-and-click hunt-pivoting) on your own and don’t want to pay for it in Graylog, you’re probably better of with a third solution, e.g. Security Onion using ELK, or SELKS, or Gravwell CE. I also ran Grafana Loki for a year and while it is pretty efficient it is quite complex as in complicated.

I haven’t done it, but I saw that it is possible to integrate Security Onion and Wazuh. That would be my recommendation.

BTW, Wazuh builds on top of OSSEC which was considered to be a SIEM, I’d guess that the Wazuh folks would call Wazuh to be a SIEM, too.

1 Like

Thank you guys. For your response. I think I need to learn more for graylog. Even Zabbix needs time to setup things. But I will first stick to zabbix and then start learning graylog.

Wazuh can be done later on.

@LTS_Tom has an excellent video on getting Graylog setup and working. You can also find his Docker compose file over on his Git repo.

3 Likes

Here is my Graylog tutorial

2 Likes

banross,

Setting up Graylog using Docker Compose is super easy (once you figure it out :upside_down_face:). I have been running my setup for a while and I followed the advice from Tom’s video when setting it up the first time.

I have two examples for you that you can almost literary copy/paste into a Linux server (with Docker). I run mine in a Ubuntu 24.04.1 LTS server (as a Proxmox VM).

The difference between the two examples is the network setup.

The first example uses the Docker bridge network driver (which is what I have seen most people do when running containers at home). You will have to map all the ports you want and modify and re-deploy the stack when you want to map more ports.

The second one uses a Docker macvlan network driver which allows you to specify a dedicated IP for your container. In this case you do not have to do any port mapping because you are addressing the container by its assigned IP address. I find this cleaner and gives you the opportunity to give your container a proper DNS record internal to your network. Creating the macvlan network is something you would have to do independently and externally to this configuration for it work though. Nonetheless, it is pretty straightforward and you can easily find instructions online.

I tried to put comments on both examples to tell you what needs to be changed to fit your environment. The most important things to change/notice are:

  • Network setup
  • Volume mapping
  • Passwords for OpenSearch and Graylog

Here is the example for my “graylog stack” using the bridge network driver:

services:
  mongodb:
    image: "mongo:6.0.20"
    ports:
      - "27017:27017"   
    restart: "unless-stopped"
    networks:
      - graylog
    volumes:
      - "/opt/docker/graylog-stack/mongodb/data:/data/db"  # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/mongodb/data
    container_name: graylog-stack-mongodb

  opensearch:
    image: "opensearchproject/opensearch:2.18.0"
    environment:
      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
      - "bootstrap.memory_lock=true"
      - "discovery.type=single-node"
      - "action.auto_create_index=false"
      - "plugins.security.ssl.http.enabled=false"
      - "plugins.security.disabled=true"
      # Can generate a password for `OPENSEARCH_INITIAL_ADMIN_PASSWORD` using a linux device via:
      # tr -dc A-Z-a-z-0-9_@#%^-_=+ < /dev/urandom | head -c${1:-32}
      - "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<REDACTED>" # <-- CHANGE ME WITH GENERATED PASSWORD
    ulimits:
      memlock:
        hard: -1
        soft: -1
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - "9200:9200"
      - "9300:9300"    
    restart: "unless-stopped"
    networks:
      - graylog
    volumes:
      - "/opt/docker/graylog-stack/opensearch/data:/usr/share/opensearch/data"  # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/opensearch/data
    container_name: graylog-stack-opensearch

  graylog:
    container_name: graylog-stack-graylog
    image: "graylog/graylog:6.1.5"
    depends_on:
      mongodb:
        condition: "service_started"
      opensearch:
        condition: "service_started"
    entrypoint: "/usr/bin/tini -- wait-for-it opensearch:9200 -- /docker-entrypoint.sh"
    environment:
      GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/config/node-id"
      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
      GRAYLOG_ELASTICSEARCH_HOSTS: "http://opensearch:9200"
      GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
      GRAYLOG_REPORT_DISABLE_SANDBOX: "true"
      GRAYLOG_PASSWORD_SECRET: "<REDACTED>" # <-- CHANGE ME WITH YOUR PASSWORD SECRET (must be at least 16 characters)
      GRAYLOG_ROOT_PASSWORD_SHA2: "<REDACTED>" # <-- CHANGE ME WITH YOUR PASSWORD SHA2
      GRAYLOG_HTTP_EXTERNAL_URI: "http://127.0.0.1:9000/"
      GRAYLOG_TIMEZONE: "America/New_York" # <-- CHANGE ME WITH YOUR TIMEZONE
      TZ: "America/New_York" # <-- CHANGE ME WITH YOUR TIMEZONE
    ports:
      # Graylog web interface and REST API
      - "9000:9000/tcp"
      # Beats
      - "5044:5044/tcp"
      # Syslog TCP
      - "5140:5140/tcp"
      # Syslog UDP
      - "5140:5140/udp"
      # GELF TCP
      - "12201:12201/tcp"
      # GELF UDP
      - "12201:12201/udp"
      # Forwarder data
      - "13301:13301/tcp"
      # Forwarder config
      - "13302:13302/tcp"
      #
      # BELOW ARE EXAMPLES OF ADDITIONAL PORTS FOR OTHER LOG SOURCES THAT I USE. YOU DON'T NECESSARILY NEED THEM ALL.
      # unifi
      - "33123:33123/tcp"
      # unifi
      - "33123:33123/udp"
      # pfsense
      - "33124:33124/tcp"
      # pfsense
      - "33124:33124/udp"
      # truenas
      - "33125:33125/tcp"
      # truenas
      - "33125:33125/udp"  
      # proxmox
      - "33126:33126/tcp"
      # proxmox
      - "33126:33126/udp"  
      # synology
      - "33127:33127/tcp"
      # synology
      - "33127:33127/udp"  
    restart: "unless-stopped"
    networks:
      - graylog
    volumes:
      - "/opt/docker/graylog-stack/graylog/data:/usr/share/graylog/data/data"        # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/graylog/data
      - "/opt/docker/graylog-stack/graylog/config:/usr/share/graylog/data/config"    # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/graylog/config
      - "/opt/docker/graylog-stack/graylog/journal:/usr/share/graylog/data/journal"  # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/graylog/journal 

networks:
  graylog:
    driver: "bridge"

Here is the example for my “graylog stack” using the macvlan network driver:

services:
  mongodb:
    image: "mongo:6.0.20"
    restart: "unless-stopped"
    networks:
      dmz:
        ipv4_address: 10.10.10.10 # <-- CHANGE ME WITH YOUR IP ADDRESS
    volumes:
      - "/opt/docker/graylog-stack/mongodb/data:/data/db"  # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/mongodb/data  
    container_name: graylog-stack-mongodb

  opensearch:
    image: "opensearchproject/opensearch:2.18.0"
    environment:
      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
      - "bootstrap.memory_lock=true"
      - "discovery.type=single-node"
      - "action.auto_create_index=false"
      - "plugins.security.ssl.http.enabled=false"
      - "plugins.security.disabled=true"
      # Can generate a password for `OPENSEARCH_INITIAL_ADMIN_PASSWORD` using a linux device via:
      # tr -dc A-Z-a-z-0-9_@#%^-_=+ < /dev/urandom | head -c${1:-32}
      - "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<REDACTED>" # <-- CHANGE ME WITH GENERATED PASSWORD
    ulimits:
      memlock:
        hard: -1
        soft: -1
      nofile:
        soft: 65536
        hard: 65536
    restart: "unless-stopped"
    networks:
      dmz:
        ipv4_address: 10.10.10.11 # <-- CHANGE ME WITH YOUR IP ADDRESS
    volumes:
      - "/opt/docker/graylog-stack/opensearch/data:/usr/share/opensearch/data"  # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/opensearch/data
    container_name: graylog-stack-opensearch

  graylog:
    container_name: graylog-stack-graylog
    image: "graylog/graylog:6.1.5"
    depends_on:
      mongodb:
        condition: "service_started"
      opensearch:
        condition: "service_started"
    entrypoint: "/usr/bin/tini -- wait-for-it opensearch:9200 -- /docker-entrypoint.sh"
    environment:
      GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/config/node-id"
      GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
      GRAYLOG_ELASTICSEARCH_HOSTS: "http://opensearch:9200"
      GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
      GRAYLOG_REPORT_DISABLE_SANDBOX: "true"
      GRAYLOG_PASSWORD_SECRET: "<REDACTED>" # <-- CHANGE ME WITH YOUR PASSWORD SECRET (must be at least 16 characters)
      GRAYLOG_ROOT_PASSWORD_SHA2: "<REDACTED>" # <-- CHANGE ME WITH YOUR PASSWORD SHA2
      GRAYLOG_HTTP_EXTERNAL_URI: "http://127.0.0.1:9000/"
      GRAYLOG_TIMEZONE: "America/New_York" # <-- CHANGE ME WITH YOUR TIMEZONE
      TZ: "America/New_York" # <-- CHANGE ME WITH YOUR TIMEZONE
    restart: unless-stopped
    networks:
      dmz:  # <-- THIS IS A MACVLAN NETWORK CREATED OUTSIDE THIS FILE. THE NAME CAN BE DIFFERENT. IN THIS EXAMPLE, IT IS `dmz`.
        ipv4_address: 10.10.10.12 # <-- CHANGE ME WITH YOUR IP ADDRESS
    volumes:
      - "/opt/docker/graylog-stack/graylog/data:/usr/share/graylog/data/data"        # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/graylog/data
      - "/opt/docker/graylog-stack/graylog/config:/usr/share/graylog/data/config"    # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/graylog/config
      - "/opt/docker/graylog-stack/graylog/journal:/usr/share/graylog/data/journal"  # <-- CHANGE ME WITH YOUR PATH. In this example, it is /opt/docker/graylog-stack/graylog/journal 

networks:
  dmz:  # <-- THIS IS A MACVLAN NETWORK CREATED OUTSIDE THIS FILE. THE NAME CAN BE DIFFERENT. IN THIS EXAMPLE, IT IS `dmz`.
    name: dmz  # <-- THIS IS A MACVLAN NETWORK CREATED OUTSIDE THIS FILE. THE NAME CAN BE DIFFERENT. IN THIS EXAMPLE, IT IS `dmz`.
    external: true

Both of these YAML files are using the latest versions of each container in the stack (I just re-deployed mine as I was writing this to make sure they still worked).

As far as deploying the stack, you can use Docker Compose from the CLI but I have grown fond of using Portainer (https://www.portainer.io). You can deploy Portainer as a container (https://hub.docker.com/r/portainer/portainer-ce) and use it to manage other containers and build stacks. It makes maintenance and upgrades super easy… and sometimes it is nice to have a pretty GUI.

Anyways, hope this helps. I know I spent a ton of time trying to figure out logging for my home environment before landing on this setup (and I am really happy with it).

Regards,
DrMofongo