Proxmox Mail Gateway (PMG) is a mail gateway and spam filter. This cheatsheet covers daily operations and advanced configuration.
Proxmox Mail Gateway (PMG) Architecture
PMG Overview
# PMG sits between the internet and your mail server
# Internet -> PMG (port 25) -> Internal Mail Server (port 2525 or custom)
# Default PMG ports
# 25 (SMTP inbound), 8006 (Web UI), 40001 (Cluster sync), 22 (SSH)
# Access web UI
# https://pmg.example.com:8006
# Default credentials: admin@pam (system root password)
# Check PMG version
pmgversionTransport Rules
# Transport rules route mail to internal mail servers
# /etc/pmg/transport
# Format: domain target
example.com smtp:192.168.1.10:25
example.org smtp:192.168.1.11:25
sub.example.com smtp:192.168.1.12:2525
# Wildcard domain
.example.com smtp:192.168.1.10:25
# Catch-all (any domain not matched above)
* smtp:192.168.1.10:25
# Apply transport rules
pmg transport reloadMail Flow
# Standard flow:
# 1. Internet sends mail to PMG port 25
# 2. PMG runs SpamAssassin, ClamAV, rule system
# 3. PMG forwards clean mail to internal mail server
# 4. Quarantined mail is stored for review
# Verify mail flow in tracking center
# Administration > Tracking Center
# Or via CLI
pmg log viewPMG Queue Management
pmgqm (Queue Manager)
# Show queue statistics
pmgqm stats
# Show detailed queue state
pmgqm status
# List queued messages
pmgqm list
# List with filters
pmgqm list --sender [email protected]
pmgqm list --receiver [email protected]
# Show a specific message
pmgqm show <queue-id>
# Resend a message (attempt delivery again)
pmgqm resend <queue-id>
# Delete a message
pmgqm delete <queue-id>
# Delete all messages from a sender
pmgqm delete --sender [email protected]
# Flush the queue (attempt all deliveries)
pmgqm flush
# Move message to quarantine
pmgqm quarantine <queue-id>Queue Statistics
# Active queue count
pmgqm stats | grep active
# Deferred count
pmgqm stats | grep deferred
# View deferred queue details
pmgqm list --status deferred
# Show queue history
pmgqm history
# Show per-domain queue stats
pmgqm list | awk '{print $3}' | sort | uniq -c | sort -rn
# Remove old messages from queue
pmgqm delete --received-before "-7 days"Quarantine
Managing Quarantine
# Access quarantine web UI
# https://pmg.example.com:8006/#/quarantine
# List quarantined messages (CLI)
pmgqm list --status quarantine
# Release a quarantined message to recipient
pmgqm release <queue-id>
# Release and whitelist sender
pmgqm release --whitelist <queue-id>
# Whitelist a sender (bypass quarantine)
# Administration > Quarantine > Whitelist
# Or via CLI
pmg whitelist add [email protected]
# Blacklist a sender
pmg blacklist add [email protected]
# View whitelist
pmg whitelist list
# View blacklist
pmg blacklist list
# Remove from whitelist
pmg whitelist remove [email protected]
# Configure quarantine retention
# pmg config set --quarantine-retention 30Quarantine Reports & Notifications
# Send quarantine digest to users
pmgqm send-digest
# Configure digest schedule
# pmg config set --digest-daily 1
# pmg config set --digest-weekly 0
# Generate quarantine statistics
pmgqm stats --quarantine
# Query quarantine by time range
pmgqm list --status quarantine --received-after "-24 hours"Rule System
Understanding Objects
# Rules consist of: What + Who + When + Action
# What: Spam score threshold, virus, specific headers
# Who: Sender, recipient, domain
# When: Time of day, day of week
# Action: Block, quarantine, pass, redirect
# List rules
pmg rule list
# Show a specific rule's details
pmg rule show <rule-id>
# Enable/disable a rule
pmg rule enable <rule-id>
pmg rule disable <rule-id>
# Reorder rules (lower priority number runs first)
pmg rule move <rule-id> --position 1Creating Rules (CLI)
# Block mail with spam score >= 5 from external senders
pmg rule create --name "Block High Spam" \
--what "spamscore >= 5" \
--who "!from_local" \
--action "Block"
# Quarantine mail with spam score 3-5
pmg rule create --name "Quarantine Medium Spam" \
--what "spamscore >= 3 and spamscore < 5" \
--who "!from_local" \
--action "Quarantine"
# Block all mail from specific country
pmg rule create --name "Block Country" \
--what "country == CN or country == RU" \
--action "Block"
# Whitelist specific sender (always deliver)
pmg rule create --name "Whitelist Partner" \
--what "sender == '@partner.com'" \
--action "Accept"
# Redirect mail from specific sender
pmg rule create --name "Redirect Executive Mail" \
--what "sender == '[email protected]'" \
--action "Redirect to [email protected]"
# Block attachments by extension
pmg rule create --name "Block Executables" \
--what "filename matches '.exe$' or filename matches '.scr$'" \
--action "Block"Custom Rules (Advanced)
# Combine conditions
# Block if spam score high AND from unknown sender AND contains specific word
--what "spamscore >= 5 AND !from_local AND body contains 'viagra'"
# Time-based rules
--when "time 08:00-18:00" # Only apply during work hours
--when "day Mon-Fri" # Only apply weekdays
# Multiple actions per rule
# Use action sets: Action: Quarantine + Notify admin
# Log-only rule (for testing before enforcing)
pmg rule create --name "Test Rule" \
--what "spamscore >= 2" \
--action "Log"SpamAssassin Tuning
Bayes Learning
# Enable Bayesian filtering
# Navigate to Mail Filter > SpamDetector > Bayes in web UI
# Or configure in /etc/mail/spamassassin/local.cf
# Train Bayes with known spam
sa-learn --spam /var/spam/*.emails
# Train Bayes with known ham (legitimate mail)
sa-learn --ham /var/ham/*.emails
# Auto-learn (PMG automatically learns from quarantined/released mail)
# Settings: Mail Filter > SpamDetector > Bayes > Auto-learn
# Show Bayes statistics
sa-learn --dump magic
# Reset Bayes database
sa-learn --clear
sa-learn --rebuild
# Bayes database location
ls -la /var/lib/amavis/.spamassassin/bayes_*Custom Scores
# Edit SpamAssassin local configuration
# /etc/mail/spamassassin/local.cf
# Adjust base score thresholds
required_score 5.0 # Default spam threshold (lower = more aggressive)
tag_level 2.0 # Add spam headers above this score
tag2_level 6.0 # Mark as high spam above this score
# Rewrite specific rules scores
score RCVD_IN_SBL_CSS 3.0 1.5 3.0 1.5 # Raise SBL blacklist score
score RCVD_IN_PBL 1.5 0.0 1.5 0.0 # Lower PBL score
# Disable a rule
score RCVD_IN_PBL 0 0 0 0
# Enable short-circuiting (skip rules if threshold already hit)
use_bayes_rules 1
shortcircuit USER_IN_WHITELIST on
shortcircuit USER_IN_DEF_WHITELIST on
shortcircuit ALL_TRUSTED on
# Add custom rules
# /etc/mail/spamassassin/custom.cf
header LOCAL_HAS_X_PRIORITY X-Priority =~ /^1/
describe LOCAL_HAS_X_PRIORITY High priority header
score LOCAL_HAS_X_PRIORITY 0.5
# After editing, restart services
systemctl restart pmg-smtpd-filter
systemctl restart pmg-smtp-filterRazor / DCC / Pyzor
# Install collaborative filtering components
apt install -y razor pyzor dcc-client
# Configure Razor
razor-admin -create
razor-admin -register -user [email protected] -pass $(openssl rand -base64 12)
# Configure Pyzor
pyzor discover
# Configure DCC (ifdcc)
# /etc/dcc/dcc_conf
DCCM_LOG_AT=never
DCCM_REJECT_AT=many
# Enable in SpamAssassin
# /etc/mail/spamassassin/local.cf
use_razor 1
use_pyzor 1
use_dcc 1
dcc_dccifd_path /var/run/dcc/dccifd
# Test DCC connectivity
cdcc "info"
# Restart after enabling
systemctl restart pmg-smtpd-filterCluster Management
pmgcm Commands
# Create a PMG cluster
pmgcm create my-cluster
# Join a node to the cluster
pmgcm join master.example.com
# Show cluster status
pmgcm status
# Show cluster nodes
pmgcm nodes
# Remove a node
pmgcm delete <node-name>
# Sync cluster configuration
pmgcm sync
# Force cluster sync
pmgcm sync --force
# Show cluster config
pmgcm configCluster Synchronization
# Cluster sync ports: 40001 (TCP, pmgcm)
# Ensure firewall allows this between nodes
# Manual sync of config
pmgcm sync --from master.example.com
# Check last sync time
journalctl -u pmgcm -n 10 | grep "sync"
# Resolve sync conflicts
# Configuration is stored in /etc/pmg/
# Master configuration takes priority
# Transfer certificates between nodes
# Administration > Certificates > Cluster SyncTLS Certificates
# Generate Let's Encrypt certificate
# Administration > Certificates > ACME
# Or manually upload certificate
# /etc/pmg/pmg-tls.pem (certificate)
# /etc/pmg/pmg-tls.key (private key)
# After changing certificates, restart
systemctl restart pmgproxy
# Verify certificate
openssl s_client -connect pmg.example.com:8006 -showcerts
# Generate self-signed certificate
openssl req -x509 -newkey rsa:4096 -nodes \
-keyout /etc/pmg/pmg-tls.key \
-out /etc/pmg/pmg-tls.pem \
-days 3650 -subj "/CN=pmg.example.com"
# Set permissions
chmod 640 /etc/pmg/pmg-tls.keyLogs & Debugging
PMG Log Commands
# View PMG logs (web UI equivalent)
pmg log view
# View real-time log
pmg log watch
# View logs with filters
pmg log view --since "-1 hour"
pmg log view --since "2024-01-01" --until "2024-01-02"
# View logs for specific sender
pmg log view --sender [email protected]
# View logs for specific recipient
pmg log view --receiver [email protected]
# Save logs to file
pmg log view --output /tmp/pmg-log.txtTracking Center
# Web UI: Administration > Tracking Center
# Search by message ID (from email headers)
# Tracking Center > Search > Message-ID: <...>
# Search by sender/receiver
# Tracking Center > Search > Sender or Receiver
# Search by date range
# Tracking Center > Search > Date Range
# View message processing details
# Click on a message to see:
# - SpamAssassin score breakdown
# - Rule matches
# - Virus scan results
# - Delivery statusGrep Patterns
# PMG filter logs
grep -i "spam" /var/log/pmg-smtpd-filter.log
grep -i "virus" /var/log/pmg-smtpd-filter.log
# Connection logs
grep "connect from" /var/log/mail.log
grep "disconnect" /var/log/mail.log
# Rule matches
grep "RULE:" /var/log/pmg.log
# Quarantine actions
grep "quarantine" /var/log/pmg.log
# Delivery failures
grep "status=deferred\|status=bounced" /var/log/mail.log
# TLS connection failures
grep "TLS\|tls" /var/log/mail.log | grep -i "error\|fail"
# All errors
grep -i "error\|warning\|fatal" /var/log/pmg.log
# SpamAssassin score details
grep "spam," /var/log/mail.log | head -5DKIM Signing in PMG
Configuring DKIM
# PMG can sign outgoing mail with DKIM
# Administration > Mail Proxy > DKIM
# Add DKIM key pair
# Administration > Mail Proxy > DKIM > Add
# Select domain, upload private key, set selector
# Or via CLI
pmg config dkim add --domain example.com \
--selector 202401 \
--keyfile /etc/pmg/dkim/example.com.key
# List configured DKIM keys
pmg config dkim list
# Remove DKIM key
pmg config dkim remove --domain example.com
# Test DKIM signing
# Send test email: pmg will sign outgoing mail automatically
# Check headers for "DKIM-Signature:"Backup & Restore PMG Config
Backup PMG
# Backup entire PMG configuration
tar czf /root/pmg-backup-$(date +%Y%m%d).tar.gz \
/etc/pmg/ \
/var/lib/pmg/ \
/var/spool/pmg/ \
/etc/network/ \
/etc/hosts \
/etc/apt/sources.list \
/etc/apt/sources.list.d/
# Backup specific components
# Config only
tar czf pmg-config-$(date +%Y%m%d).tar.gz /etc/pmg/
# Quarantine data
tar czf pmg-quarantine-$(date +%Y%m%d).tar.gz /var/spool/pmg/quarantine/
# SpamAssassin bayes database
tar czf pmg-bayes-$(date +%Y%m%d).tar.gz /var/lib/amavis/.spamassassin/
# PMG built-in backup tool
# Administration > BackupRestore PMG
# Restore from config backup
systemctl stop pmg-smtpd-filter pmg-smtp-filter pmgproxy pmgdaemon
tar xzf pmg-backup-20240101.tar.gz -C /
systemctl start pmgdaemon pmgproxy pmg-smtpd-filter pmg-smtp-filter
# Restore specific config files
tar xzf pmg-config-20240101.tar.gz -C /etc/pmg/
# After restore, verify everything
pmgversion
pmgcm status
systemctl status pmg-smtpd-filter
# Re-import database (if backed up separately)
pmgdb restore /path/to/pmg-database.sql