Proxmox Mail Relay - Setup

Proxmox Mail Relay - Setup

I tried to create my own mail server

I actually got it going but damn it was a problematic, and difficult thing to do. In the end after doing more research I gave up and put left the docker compose file in the development folder - it does actually work.

So now what. Well, I need a mail server and when you host services whether for internal use of otherwise most of them still use email and although more of these are allowing the use of webhooks and other integrations, the fact of the matter is I am not interested in signing up to more services to use these integrations.

So, what to do. Well since two of these services require Mail gun, I simply utilized its services and set up a mail relay on the Proxmox hypervisor which is pretty handy as that is where all these services run.

Proxmox by default has postfix installed and with a little reconfiguration you can get it to act as a relay to your cloud-based mail system (not mix personal and development work - creates all sorts of problems).

So here is the script to adjust the postfix file to do the job on the Proxmox hypervisor.

Hypervisor Configuration

#!/bin/bash

# Updated 01-02-2025
# Refer to the following along with fail2ban
# https://superuser.com/questions/576751/example-of-fail2ban-configuration-to-ban-servers-spamming-my-postfix-server


# Variables
MAIN_CF="/etc/postfix/main.cf"
SASL_PASSWD="/etc/postfix/sasl_passwd"
MAILGUN_SMTP="smtp.mailgun.org"
MAILGUN_PORT="587"
MAILGUN_USER="[email address you setup for the hypervisor"
MAILGUN_PASS="[email address password it generated when you set it up"
TIMESTAMP=$(date +%Y%m%d%H%M%S)
EMAIL_ADDRESS="[testing email address your sending too]"

# Install necessary SASL modules
apt-get install -y libsasl2-modules


#Make the mail log
touch /var/log/mail.log

# Backup existing main.cf file with timestamp
cp $MAIN_CF "${MAIN_CF}-${TIMESTAMP}.bak"

# Update main.cf file
cat <<EOF > $MAIN_CF
# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# compatibility level - refer to base file
compatibility_level=3.6

myhostname=pxe.braedach.com

smtpd_banner = \$myhostname ESMTP \$mail_name (Debian/GNU)
biff = no

# Listen on all interfaces or the pxe wont relay from LXC
inet_interfaces = all

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Setup mail logging
maillog_file = /var/log/mail.log

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = \$myhostname, localhost.\$mydomain, localhost

relayhost = [$MAILGUN_SMTP]:$MAILGUN_PORT

mynetworks = [modify these as required - I use CIDR notation]
recipient_delimiter = +

# Mailgun SMTP settings
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:$SASL_PASSWD
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
smtp_tls_note_starttls_offer = yes

# Enforce policies
smtpd_recipient_restrictions = 
    permit_mynetworks,
    reject_unauth_destination,
    reject_unknown_reverse_client_hostname,
    reject_non_fqdn_sender,
    reject_non_fqdn_recipient,
    reject_unknown_sender_domain,
    reject_unknown_recipient_domain,
    permit_auth_destination,
    permit

# Additional restrictions
smtpd_sender_restrictions = 
    reject_unknown_sender_domain,
    reject_unauth_pipelining
EOF


# Create sasl_passwd file with Mailgun credentials
echo "[$MAILGUN_SMTP]:$MAILGUN_PORT $MAILGUN_USER:$MAILGUN_PASS" > $SASL_PASSWD

# Secure sasl_passwd file
chmod 600 $SASL_PASSWD

# Create hash database for sasl_passwd
postmap $SASL_PASSWD

# Restart Postfix service
systemctl restart postfix

# Enable Postfix service to start on boot
systemctl enable postfix

# Run postfix check and ensure it returns nothing
POSTFIX_CHECK=$(postfix check)
if [ -n "$POSTFIX_CHECK" ]; then
    echo "Warning: Postfix check returned the following issues:"
    echo "$POSTFIX_CHECK"
else
    echo "Postfix configuration is correct."
fi

echo "Postfix has been configured to use Mailgun SMTP server."

# Test email to verify setup with hostname
echo "Sending test email for verification..."
echo "This is a test email from $(hostname -f)" | mail -s "Test Email from $(hostname -f)" ${EMAIL_ADDRESS}

An email should hit your designated in box shortly thereafter

Now for the LXC containers - UPDATED - 2025-10-09


#!/bin/bash

# Postfix setup script for LXC Debian 12 container
# Updated 2025-10-09
# Goal:
#   - All mail generated by root is delivered to security@braedach.com
#   - Outgoing mail from root is rewritten to appear from security@[hostname].tld

set -euo pipefail

MAIL_SERVER="[your mail server fqdn]"
EMAIL_ADDRESS="security@tld"
EMAIL_ADDRESS_HOST="security@$(hostname -f)"
MAIN_CF="/etc/postfix/main.cf"
TIMESTAMP=$(date +%Y%m%d%H%M)

apt-get update
apt-get install -y postfix rsyslog mailutils sudo

# Backup existing main.cf
cp "$MAIN_CF" "${MAIN_CF}-${TIMESTAMP}.bak"

# Set mailname
echo "$(hostname -f)" > /etc/mailname

# Reset generic map and aliases
rm -f /etc/postfix/generic
cp /usr/share/postfix/main.cf.debian "$MAIN_CF"
touch /etc/aliases

# Remove any existing root/docker aliases
sed -i '/^root:/d;/^docker:/d' /etc/aliases

# Preseed debconf for Postfix
debconf-set-selections <<< "postfix postfix/mailname string $(hostname -f)"
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Satellite system'"
debconf-set-selections <<< "postfix postfix/relayhost string ${MAIL_SERVER}"

# Core Postfix configuration
postconf -e "relayhost = $MAIL_SERVER"
postconf -e "myhostname = $(hostname -f)"
postconf -e "smtp_generic_maps = hash:/etc/postfix/generic"
postconf -e "smtp_helo_name = $(hostname -f)"
postconf -e "myorigin = /etc/mailname"
postconf -e "mydestination = \$myhostname, localhost.\$mydomain, localhost"
postconf -e "maillog_file = /var/log/mail.log"

# Generic map: rewrite root@host → security@[hostname].braedach.com
cat > /etc/postfix/generic <<EOF
root@$(hostname -f) ${EMAIL_ADDRESS_HOST}
EOF
postmap /etc/postfix/generic

# Aliases: deliver root’s mail to external security@tld
echo "root: ${EMAIL_ADDRESS}" >> /etc/aliases
newaliases

# Permissions and logging
touch /var/log/mail.log
chown root:adm /var/log/mail.log
chmod 640 /var/log/mail.log
chmod 644 /etc/postfix/generic

# Enable and restart services
systemctl enable postfix rsyslog
systemctl restart rsyslog postfix

# Validate configuration
if ! postfix check; then
    echo "Error: Postfix check failed."
    exit 1
else
    echo "Postfix configuration is correct."

    echo "Sending test email from ${EMAIL_ADDRESS_HOST} via ${MAIL_SERVER}..."
    echo "This is a test email." | mail -s "Test Email from ${EMAIL_ADDRESS_HOST}" "${EMAIL_ADDRESS}"
fi

Another email address should hit your inbox from the LXC

Job done - works a treat.

#enoughsaid