new-site/infra/postfix/mta_setup.sh
justin 2fab98c0a8 postfix: multi-IP warmup sending pool (20 IPs, gradual rotation)
- 20 IPs (.90-.109 / mta01-mta20) with FCrDNS + SPF in HestiaCP
- .90 (mta01) dedicated Yahoo/AOL recovery IP (yahooslow, 20s trickle)
- .91-.109 (out02-out20) rotation pool via transport_maps randmap
- pw-mta-warmup: cron-driven scheduler grows the active rotation pool
  3 -> 5 -> 8 -> 12 -> 16 -> 19 IPs over ~25 days
- mta_setup.sh: idempotent installer (backups + postfix-check-gated reload)

New IPs verified clean on Spamhaus/Barracuda/SpamCop/SORBS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 19:03:30 -05:00

80 lines
3 KiB
Bash

#!/bin/bash
set -e
TS=$(date +%s)
echo "=== backups ==="
cp /etc/postfix/master.cf /etc/postfix/master.cf.bak.$TS
cp /etc/postfix/main.cf /etc/postfix/main.cf.bak.$TS
cp /etc/postfix/transport /etc/postfix/transport.bak.$TS
echo "backed up (.$TS)"
echo "=== master.cf: yahooslow bind .90 + add out02..out20 ==="
python3 - <<'PY'
mc = open('/etc/postfix/master.cf').read()
if 'smtp_bind_address=207.174.124.90' not in mc:
out=[]; iny=False
for ln in mc.split('\n'):
out.append(ln)
if ln.startswith('yahooslow '): iny=True
elif iny and 'smtp_destination_recipient_limit=1' in ln:
out.append(' -o smtp_bind_address=207.174.124.90')
out.append(' -o smtp_helo_name=mta01.performancewest.net')
iny=False
mc='\n'.join(out)
if 'out02 unix' not in mc:
b=['','# === Warmup rotation pool (.91-.109 / mta02-mta20) ===']
for i in range(2,21):
octet=89+i; name='out%02d'%i; helo='mta%02d.performancewest.net'%i
b += ['%s unix - - n - - smtp'%name,
' -o smtp_bind_address=207.174.124.%d'%octet,
' -o smtp_helo_name=%s'%helo,
' -o syslog_name=postfix/%s'%name,
' -o smtp_destination_concurrency_limit=2',
' -o smtp_destination_rate_delay=2s',
' -o smtp_destination_recipient_limit=2']
mc=mc.rstrip('\n')+'\n'+'\n'.join(b)+'\n'
open('/etc/postfix/master.cf','w').write(mc)
print(' master.cf updated')
PY
echo "=== transport: yahoo/aol/yahoo-ISPs -> yahooslow; gmail/outlook removed (rotate) ==="
cat > /etc/postfix/transport <<'EOF'
# Yahoo/AOL + Yahoo-hosted ISPs -> dedicated .90 trickle (yahooslow). Everything
# else falls through transport_maps to the randmap rotation pool.
yahoo.com yahooslow:
ymail.com yahooslow:
rocketmail.com yahooslow:
aol.com yahooslow:
att.net yahooslow:
sbcglobal.net yahooslow:
bellsouth.net yahooslow:
verizon.net yahooslow:
frontier.com yahooslow:
frontiernet.net yahooslow:
EOF
/usr/sbin/postmap /etc/postfix/transport
echo " transport rebuilt"
echo "=== install warmup scheduler + stamp start + set phase-1 pool ==="
cp /tmp/pw-mta-warmup.sh /usr/local/bin/pw-mta-warmup
chmod +x /usr/local/bin/pw-mta-warmup
/usr/local/bin/pw-mta-warmup --start
echo "=== postfix check (gate) ==="
if /usr/sbin/postfix check 2>&1; then
echo "CHECK OK"; /usr/sbin/postfix reload && echo "RELOADED"
else
echo "CHECK FAILED — rolling back"
cp /etc/postfix/master.cf.bak.$TS /etc/postfix/master.cf
cp /etc/postfix/main.cf.bak.$TS /etc/postfix/main.cf
cp /etc/postfix/transport.bak.$TS /etc/postfix/transport
/usr/sbin/postmap /etc/postfix/transport
/usr/sbin/postfix reload
echo "ROLLED BACK"; exit 1
fi
echo "=== cron (daily warmup advance) ==="
echo '17 7 * * * root /usr/local/bin/pw-mta-warmup >> /var/log/pw-mta-warmup.log 2>&1' > /etc/cron.d/pw-mta-warmup
echo "=== final transport_maps ==="
/usr/sbin/postconf -h transport_maps
echo "=== out transport count ==="
grep -cE "^out[0-9]+ unix" /etc/postfix/master.cf