Graylog Setup Guide for Multiple Postfix MTA Servers on AlmaLinux
Architecture Overview
This guide sets up:
- 1 Central Graylog Server (AlmaLinux) – for log collection and analysis
- Multiple MTA Servers (AlmaLinux with Postfix) – forwarding logs to Graylog
Part 1: Install Graylog Server (Central Server)
System Requirements
- AlmaLinux 8 or 9
- Minimum 4GB RAM (8GB+ recommended)
- 50GB+ disk space for logs
- Static IP address
Step 1: Update System and Install Prerequisites
# Update system
sudo dnf update -y
# Install required tools
sudo dnf install -y wget curl java-17-openjdk-headless pwgen
Step 2: Install MongoDB
# Add MongoDB repository
cat <<EOF | sudo tee /etc/yum.repos.d/mongodb-org-6.0.repo
[mongodb-org-6.0]
name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/\$releasever/mongodb-org/6.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc EOF # Install MongoDB sudo dnf install -y mongodb-org # Enable and start MongoDB sudo systemctl daemon-reload sudo systemctl enable mongod sudo systemctl start mongod # Verify MongoDB is running sudo systemctl status mongod
Step 3: Install OpenSearch (Elasticsearch alternative)
# Add OpenSearch repository
curl -SL https://artifacts.opensearch.org/releases/bundle/opensearch/2.x/opensearch-2.x.repo -o /tmp/opensearch-2.x.repo
sudo mv /tmp/opensearch-2.x.repo /etc/yum.repos.d/
# Install OpenSearch
sudo dnf install -y opensearch-2.11.1
# Configure OpenSearch for Graylog
sudo tee -a /etc/opensearch/opensearch.yml > /dev/null <<EOF
# Graylog configuration
cluster.name: graylog
node.name: \${HOSTNAME}
network.host: 0.0.0.0
discovery.type: single-node
action.auto_create_index: false
plugins.security.disabled: true
EOF
# Set JVM heap size (50% of available RAM, max 32GB)
sudo sed -i 's/^-Xms.*/-Xms2g/' /etc/opensearch/jvm.options
sudo sed -i 's/^-Xmx.*/-Xmx2g/' /etc/opensearch/jvm.options
# Enable and start OpenSearch
sudo systemctl daemon-reload
sudo systemctl enable opensearch
sudo systemctl start opensearch
# Wait for OpenSearch to start
sleep 30
# Verify OpenSearch is running
curl -X GET "localhost:9200"
Step 4: Install Graylog Server
# Download and install Graylog repository
sudo rpm -Uvh https://packages.graylog2.org/repo/packages/graylog-5.2-repository_latest.rpm
# Install Graylog server
sudo dnf install -y graylog-server
# Generate password secret (save this!)
PASSWORD_SECRET=$(pwgen -N 1 -s 96)
echo "Password Secret: $PASSWORD_SECRET"
# Generate admin password hash (change 'YourAdminPassword' to your desired password)
ADMIN_PASSWORD="YourAdminPassword"
ADMIN_PASSWORD_SHA2=$(echo -n "$ADMIN_PASSWORD" | sha256sum | awk '{print $1}')
echo "Admin Password: $ADMIN_PASSWORD"
echo "Admin Password Hash: $ADMIN_PASSWORD_SHA2"
# Configure Graylog
sudo cp /etc/graylog/server/server.conf /etc/graylog/server/server.conf.backup
# Update configuration
sudo sed -i "s/^password_secret =.*/password_secret = $PASSWORD_SECRET/" /etc/graylog/server/server.conf
sudo sed -i "s/^root_password_sha2 =.*/root_password_sha2 = $ADMIN_PASSWORD_SHA2/" /etc/graylog/server/server.conf
# Set HTTP bind address (change to your server IP)
SERVER_IP=$(hostname -I | awk '{print $1}')
sudo sed -i "s|^#http_bind_address = .*|http_bind_address = $SERVER_IP:9000|" /etc/graylog/server/server.conf
sudo sed -i "s|^#http_publish_uri = .*|http_publish_uri = http://$SERVER_IP:9000/|" /etc/graylog/server/server.conf
# Set Elasticsearch hosts
sudo sed -i "s|^#elasticsearch_hosts = .*|elasticsearch_hosts = http://127.0.0.1:9200|" /etc/graylog/server/server.conf
# Enable and start Graylog
sudo systemctl daemon-reload
sudo systemctl enable graylog-server
sudo systemctl start graylog-server
# Check status
sudo systemctl status graylog-server
Step 5: Configure Firewall
# Open required ports
sudo firewall-cmd --permanent --add-port=9000/tcp # Graylog web interface
sudo firewall-cmd --permanent --add-port=1514/tcp # Syslog TCP input
sudo firewall-cmd --permanent --add-port=1514/udp # Syslog UDP input
sudo firewall-cmd --permanent --add-port=5044/tcp # Beats input (optional)
sudo firewall-cmd --reload
# Verify ports are open
sudo firewall-cmd --list-ports
Step 6: Access Graylog Web Interface
- Open browser:
http://YOUR_SERVER_IP:9000 - Login with:
- Username:
admin - Password: (the password you set in ADMIN_PASSWORD variable)
- Username:
Part 2: Configure Graylog to Receive Logs
Step 1: Create Syslog Input
- Log into Graylog web interface
- Navigate to System → Inputs
- Select Syslog TCP from dropdown
- Click Launch new input
- Configure:
- Title:
Postfix Syslog TCP - Bind address:
0.0.0.0 - Port:
1514 - Store full message: Check this
- Title:
- Click Save
Step 2: Create Postfix Stream
- Navigate to Streams
- Click Create Stream
- Configure:
- Title:
Postfix Logs - Description:
All Postfix mail server logs
- Title:
- Click Save
- Click Manage Rules on the new stream
- Add rule:
- Field:
application_name - Type:
match regular expression - Value:
postfix.*
- Field:
- Click Save
- Click Start stream
Part 3: Configure MTA Servers to Send Logs
Option A: Using Rsyslog (Simpler, Built-in)
On each MTA server, run:
# Backup rsyslog configuration
sudo cp /etc/rsyslog.conf /etc/rsyslog.conf.backup
# Add forwarding configuration
sudo tee /etc/rsyslog.d/10-graylog.conf > /dev/null <<'EOF'
# Queue configuration for reliability
$ActionQueueType LinkedList
$ActionQueueFileName graylog_queue
$ActionResumeRetryCount -1
$ActionQueueSaveOnShutdown on
$ActionQueueMaxDiskSpace 1g
# Forward all logs to Graylog
*.* @@GRAYLOG_SERVER_IP:1514;RSYSLOG_SyslogProtocol23Format
EOF
# Replace GRAYLOG_SERVER_IP with actual IP
GRAYLOG_IP="192.168.1.100" # Change this to your Graylog server IP
sudo sed -i "s/GRAYLOG_SERVER_IP/$GRAYLOG_IP/" /etc/rsyslog.d/10-graylog.conf
# Restart rsyslog
sudo systemctl restart rsyslog
# Verify rsyslog is running
sudo systemctl status rsyslog
# Test by sending a test message
logger -t postfix/test "Test message from $(hostname) to Graylog"
Option B: Using Filebeat (More Reliable, Recommended for Production)
On each MTA server, run:
Install Filebeat
sudo rpm –import https://artifacts.elastic.co/GPG-KEY-elasticsearch
cat <<EOF | sudo tee /etc/yum.repos.d/elastic.repo
[elastic-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOF
sudo dnf install -y filebeat
Backup default configuration
sudo cp /etc/filebeat/filebeat.yml /etc/filebeat/filebeat.yml.backup
Create new configuration
sudo tee /etc/filebeat/filebeat.yml > /dev/null <<‘EOF’
filebeat.inputs:
- type: log enabled: true paths:
- /var/log/maillog
- /var/log/maillog-*
fields:
log_type: postfix
server_role: mta
hostname: ${HOSTNAME}
fields_under_root: true
output.logstash:
hosts: [“GRAYLOG_SERVER_IP:5044”]
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
permissions: 0644
EOF
Replace GRAYLOG_SERVER_IP
GRAYLOG_IP=”192.168.1.100″ # Change this
sudo sed -i “s/GRAYLOG_SERVER_IP/$GRAYLOG_IP/” /etc/filebeat/filebeat.yml
Replace HOSTNAME placeholder
sudo sed -i “s/\${HOSTNAME}/$(hostname)/” /etc/filebeat/filebeat.yml
Enable and start Filebeat
sudo systemctl enable filebeat
sudo systemctl start filebeat
Check status
bash
# Install Filebeat
sudo rpm –import https://artifacts.elastic.co/GPG-KEY-elasticsearch
cat <<EOF | sudo tee /etc/yum.repos.d/elastic.repo
[elastic-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
EOF
sudo dnf install -y filebeat
# Backup default configuration
sudo cp /etc/filebeat/filebeat.yml /etc/filebeat/filebeat.yml.backup
# Create new configuration
sudo tee /etc/filebeat/filebeat.yml > /dev/null <<‘EOF’
filebeat.inputs:
– type: log
enabled: true
paths:
– /var/log/maillog
– /var/log/maillog-*
fields:
log_type: postfix
server_role: mta
hostname: ${HOSTNAME}
fields_under_root: true
output.logstash:
hosts: [“GRAYLOG_SERVER_IP:5044”]
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
permissions: 0644
EOF
# Replace GRAYLOG_SERVER_IP
GRAYLOG_IP=”192.168.1.100″ # Change this
sudo sed -i “s/GRAYLOG_SERVER_IP/$GRAYLOG_IP/” /etc/filebeat/filebeat.yml
# Replace HOSTNAME placeholder
sudo sed -i “s/\${HOSTNAME}/$(hostname)/” /etc/filebeat/filebeat.yml
# Enable and start Filebeat
sudo systemctl enable filebeat
sudo systemctl start filebeat
# Check status
sudo systemctl status filebeat
If using Filebeat, also create Beats input in Graylog:
- System → Inputs
- Select Beats from dropdown
- Configure:
- Title:
Filebeat Input - Bind address:
0.0.0.0 - Port:
5044
- Title:
- Click Save
Part 4: Create Postfix Log Extractors
Extract Common Postfix Fields
- Navigate to System → Inputs
- Click Manage extractors on your Syslog input
- Create the following extractors:
Extractor 1: Message ID
- Type: Regular expression
- Field:
message - Pattern:
.*(?:postfix[/\w-]*\[\d+\]): ([A-F0-9]+): - Store as field:
postfix_message_id
Extractor 2: Queue ID
- Type: Grok pattern
- Field:
message - Pattern:
%{POSTFIX_QUEUEID:postfix_queue_id}
Extractor 3: From Address
- Type: Regular expression
- Field:
message - Pattern:
from=<([^>]*)> - Store as field:
mail_from
Extractor 4: To Address
- Type: Regular expression
- Field:
message - Pattern:
to=<([^>]*)> - Store as field:
mail_to
Extractor 5: Status
- Type: Regular expression
- Field:
message - Pattern:
status=(\w+) - Store as field:
delivery_status
Part 5: Create Dashboards and Reports
Create Basic Postfix Dashboard
- Navigate to Dashboards
- Click Create dashboard
- Name it:
Postfix Mail Traffic - Add widgets:
Widget 1: Message Count Over Time
- Type: Area chart
- Metric: Count
- Time Range: Last 24 hours
- Interval: 5 minutes
Widget 2: Delivery Status Distribution
- Type: Pie chart
- Field:
delivery_status - Top values: 10
Widget 3: Top Senders
- Type: Data table
- Field:
mail_from - Top values: 20
Widget 4: Top Recipients
- Type: Data table
- Field:
mail_to - Top values: 20
Widget 5: Messages by MTA Server
- Type: Bar chart
- Field:
sourceorhostname - Top values: 10
Schedule Daily Reports
- Navigate to Alerts & Events → Event Definitions
- Click Create Event Definition
- Configure:
- Title:
Daily Postfix Report - Priority: Normal
- Condition Type: Filter & Aggregation
- Search Query:
application_name:postfix* - Aggregation: Count
- Time Range: Last 24 hours
- Title:
- Add Notification:
- Type: Email
- Recipients: Your email address
- Subject:
Daily Postfix Report - {event_timestamp}
- Set schedule to run daily at desired time
Part 6: Useful Searches and Queries
Common Search Queries
# All bounced emails
delivery_status:bounced
# Emails from specific sender
mail_from:"user@example.com"
# All emails to specific domain
mail_to:*@example.com
# Emails from specific MTA server
source:"mta1.example.com"
# Failed deliveries in last hour
delivery_status:(deferred OR bounced) AND timestamp:[now-1h TO now]
# Large emails (over 10MB)
size:>10485760
# Emails with specific queue ID
postfix_queue_id:"ABC123DEF456"
# All relay denials
message:*"Relay access denied"*
# Authentication failures
message:*"authentication failed"*
Create Saved Searches
- Run a search query
- Click Save search
- Name it appropriately
- Use for quick access or in dashboards
Part 7: Maintenance and Optimization
Index Rotation and Retention
- Navigate to System → Indices
- Click Index Set (default)
- Configure:
- Index Rotation: Daily (or based on size)
- Index Retention: 30 days (adjust based on needs)
- Max number of indices: 30
Performance Tuning
# Adjust JVM heap for Graylog (50% of available RAM)
sudo nano /etc/sysconfig/graylog-server
# Add: GRAYLOG_SERVER_JAVA_OPTS="-Xms4g -Xmx4g"
# Adjust OpenSearch heap
sudo nano /etc/opensearch/jvm.options
# Change -Xms and -Xmx to 50% of available RAM (max 32g)
# Restart services
sudo systemctl restart graylog-server
sudo systemctl restart opensearch
Backup Configuration
# Backup Graylog configuration
sudo cp /etc/graylog/server/server.conf /backup/graylog-server.conf.$(date +%Y%m%d)
# Backup MongoDB (Graylog metadata)
sudo mongodump --out=/backup/mongodb-$(date +%Y%m%d)
# Backup OpenSearch indices (optional, large)
curl -X PUT "localhost:9200/_snapshot/backup_repo" -H 'Content-Type: application/json' -d'
{
"type": "fs",
"settings": {
"location": "/backup/opensearch"
}
}'
Part 8: Troubleshooting
Check Graylog Logs
sudo tail -f /var/log/graylog-server/server.log
Check if Logs are Being Received
# On Graylog server
sudo tcpdump -i any -n port 1514
# On MTA server - test connectivity
telnet GRAYLOG_SERVER_IP 1514
Verify Services are Running
sudo systemctl status mongod
sudo systemctl status opensearch
sudo systemctl status graylog-server
Check OpenSearch Health
curl -X GET "localhost:9200/_cluster/health?pretty"
Common Issues
Issue: Graylog web interface not accessible
- Solution: Check firewall rules, verify http_bind_address in config
Issue: No logs appearing in Graylog
- Solution: Check input status, verify MTA can reach Graylog port, check rsyslog/filebeat logs
Issue: High memory usage
- Solution: Reduce JVM heap sizes, configure index retention, add more RAM
Summary
You now have:
- ✅ Central Graylog server collecting logs from multiple MTAs
- ✅ Real-time log analysis and search capabilities
- ✅ Automated daily reports
- ✅ Custom dashboards for mail traffic visualization
- ✅ Long-term log retention and archival
Next Steps:
- Fine-tune extractors for your specific Postfix configuration
- Create additional dashboards for different reporting needs
- Set up alerting for critical events (queue buildups, high bounce rates)
- Configure TLS encryption for log transmission (optional but recommended)
- Implement user access controls for team members
Documentation Resources:
- Graylog Official Docs: https://docs.graylog.org/
- Postfix Log Format: http://www.postfix.org/postconf.5.html
- OpenSearch Docs: https://opensearch.org/docs/

