add scripts/install_postfix_sendonly.sh
This commit is contained in:
parent
de9001f20a
commit
91a566c39b
@ -158,49 +158,59 @@ EOF
|
||||
}
|
||||
|
||||
# ------------------ OpenSMTPD ------------------
|
||||
deploy_smtpd(){
|
||||
|
||||
deploy_smtpd() {
|
||||
verify_cert
|
||||
log "🚀 写入 OpenSMTPD 配置..."
|
||||
log "🚀 写入 OpenSMTPD 配置 (仅启用 587 / STARTTLS)..."
|
||||
mkdir -p /etc/smtpd
|
||||
|
||||
cat >/etc/smtpd/smtpd.conf <<EOF
|
||||
# /etc/smtpd/smtpd.conf - Send-only mode
|
||||
pki ${HOSTNAME} cert "${CERT}"
|
||||
pki ${HOSTNAME} key "${KEY}"
|
||||
|
||||
# 监听端口(25/587)均启用 TLS,无需认证
|
||||
listen on 0.0.0.0 port 25 tls pki ${HOSTNAME}
|
||||
listen on 0.0.0.0 port 587 tls pki ${HOSTNAME}
|
||||
listen on 0.0.0.0 port 587
|
||||
listen on ::0 port 587
|
||||
|
||||
# DKIM 过滤器:将外发邮件经 OpenDKIM 签名
|
||||
filter "dkim" smtp-out chain "inet://127.0.0.1:8891"
|
||||
# 启用 TLS 支持(STARTTLS)
|
||||
tls enable
|
||||
pki ${HOSTNAME}
|
||||
|
||||
table aliases file:/etc/aliases
|
||||
|
||||
# 动作定义
|
||||
action "relay" mail-from any rcpt-to any filter "dkim" relay
|
||||
|
||||
# 匹配规则
|
||||
match from any for domain "${DOMAIN}" action "relay"
|
||||
|
||||
smtp helo ${HOSTNAME}
|
||||
# 允许本机及 svc.plus 域发信
|
||||
accept from local for any relay
|
||||
accept from any for domain "${DOMAIN}" relay
|
||||
EOF
|
||||
|
||||
systemctl enable --now opensmtpd || (
|
||||
log "⚠️ 发现语法错误,尝试 fallback 简化配置..."
|
||||
cat >/etc/smtpd/smtpd.conf <<EOF
|
||||
pki ${HOSTNAME} cert "${CERT}"
|
||||
pki ${HOSTNAME} key "${KEY}"
|
||||
listen on 0.0.0.0 port 25 tls pki ${HOSTNAME}
|
||||
listen on 0.0.0.0 port 587 tls pki ${HOSTNAME}
|
||||
action "relay" relay
|
||||
match from any for domain "${DOMAIN}" action "relay"
|
||||
smtp helo ${HOSTNAME}
|
||||
EOF
|
||||
# 若系统自带默认配置,先禁用
|
||||
if [ -f /etc/smtpd.conf ]; then
|
||||
log "⚙️ 检测到系统默认 /etc/smtpd.conf,自动禁用..."
|
||||
mv /etc/smtpd.conf /etc/smtpd.conf.disabled 2>/dev/null || true
|
||||
fi
|
||||
ln -sf /etc/smtpd/smtpd.conf /etc/smtpd.conf
|
||||
|
||||
# 语法校验
|
||||
if ! smtpd -n -f /etc/smtpd/smtpd.conf > /tmp/smtpd_check.log 2>&1; then
|
||||
log "⚠️ 配置语法检测失败:"
|
||||
cat /tmp/smtpd_check.log
|
||||
die "配置无效,已终止启动。"
|
||||
fi
|
||||
|
||||
# 启动并启用服务
|
||||
systemctl enable --now opensmtpd || die "❌ 启动 opensmtpd 失败"
|
||||
sleep 1
|
||||
|
||||
# 若仍监听 25 端口则强制关闭
|
||||
if ss -tlnp | grep -qE ':25\s'; then
|
||||
log "🚫 检测到 25 端口仍在监听,强制关闭..."
|
||||
fuser -k 25/tcp 2>/dev/null || true
|
||||
systemctl restart opensmtpd
|
||||
)
|
||||
fi
|
||||
|
||||
log "✅ OpenSMTPD 已启用并监听 25/587 端口(Send-Only 模式)"
|
||||
# 再次确认状态
|
||||
if ss -tlnp | grep -qE ':587\s'; then
|
||||
log "✅ OpenSMTPD 6.8 已启用并监听 587 端口(STARTTLS Send-Only 模式)"
|
||||
else
|
||||
die "❌ 端口 587 未成功监听,请检查日志:journalctl -xeu opensmtpd.service"
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------ DNS 模板 ------------------
|
||||
|
||||
306
scripts/install_postfix_sendonly.sh
Normal file
306
scripts/install_postfix_sendonly.sh
Normal file
@ -0,0 +1,306 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# install_postfix_sendonly.sh v1.0
|
||||
# Postfix + OpenDKIM + SPF + DMARC(Send-Only 模式)
|
||||
# --------------------------------------------------------
|
||||
# ✅ 自动部署轻量级 Postfix 发信服务(仅 587 STARTTLS)
|
||||
# ✅ 集成 DKIM 签名、SPF/DMARC/rDNS/HELO 校验模板
|
||||
# ✅ 兼容阿里云 / Cloudflare DNS 输出格式
|
||||
# ✅ 适配 Ubuntu / Debian / RHEL 系列系统
|
||||
# --------------------------------------------------------
|
||||
# Author: Pan Haitao @ svc.plus
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOMAIN="svc.plus"
|
||||
HOSTNAME="smtp.${DOMAIN}"
|
||||
SERVER_IP="52.196.108.28"
|
||||
EMAIL="no-reply@${DOMAIN}"
|
||||
|
||||
CERT="/etc/ssl/${DOMAIN}.pem"
|
||||
KEY="/etc/ssl/${DOMAIN}.key"
|
||||
|
||||
DKIM_SELECTOR="mail"
|
||||
DKIM_KEY_DIR="/etc/opendkim/keys/${DOMAIN}"
|
||||
TMP_PASS="$(openssl rand -base64 12)"
|
||||
ACTION="${1:-help}"
|
||||
|
||||
log(){ echo -e "\033[1;36m$*\033[0m"; }
|
||||
die(){ echo "❌ $*"; exit 1; }
|
||||
check_root(){ [ "$EUID" -eq 0 ] || die "请用 root 运行"; }
|
||||
|
||||
# ------------------ 应用端配置 ------------------
|
||||
show_app_config(){
|
||||
cat <<EOF
|
||||
|
||||
📦 应用端 SMTP 配置:
|
||||
----------------------------------------------------------
|
||||
smtp:
|
||||
host: "${HOSTNAME}"
|
||||
port: 587
|
||||
username: "${EMAIL}"
|
||||
password: "${TMP_PASS}"
|
||||
from: "XControl Account <${EMAIL}>"
|
||||
tls:
|
||||
mode: "auto"
|
||||
insecureSkipVerify: false
|
||||
auth: "login"
|
||||
----------------------------------------------------------
|
||||
EOF
|
||||
echo "首发密码(仅本次显示):${TMP_PASS}"
|
||||
}
|
||||
|
||||
check_send_email(){
|
||||
local SMTP_HOST="${HOSTNAME}"
|
||||
local SMTP_PORT=587
|
||||
local SMTP_USER="${EMAIL}"
|
||||
local SMTP_PASS="${TMP_PASS}"
|
||||
local TEST_TO="${1:-${EMAIL}}"
|
||||
local SUBJECT="📨 SMTP Deliverability Test — $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
local BODY="✅ Automated deliverability test from ${SMTP_HOST}
|
||||
|
||||
Environment:
|
||||
- HELO: $(hostname -f)
|
||||
- Source IP: $(curl -s ifconfig.me 2>/dev/null || echo 'unknown')
|
||||
- TLS: STARTTLS on ${SMTP_PORT}
|
||||
- Auth: LOGIN (${SMTP_USER})
|
||||
|
||||
If you received this message intact, DKIM/DMARC/SPF validation succeeded."
|
||||
|
||||
echo "🔍 Testing outbound mail via ${SMTP_HOST}:${SMTP_PORT}"
|
||||
echo "-------------------------------------------------------------"
|
||||
swaks --server "${SMTP_HOST}:${SMTP_PORT}" \
|
||||
--tls --protocol ESMTP \
|
||||
--auth LOGIN \
|
||||
--auth-user "${SMTP_USER}" \
|
||||
--auth-password "${SMTP_PASS}" \
|
||||
--from "${SMTP_USER}" \
|
||||
--to "${TEST_TO}" \
|
||||
--header "From: XControl Mail System <${SMTP_USER}>" \
|
||||
--header "Subject: ${SUBJECT}" \
|
||||
--body "${BODY}" \
|
||||
--timeout 15 --quit-after "."
|
||||
echo "-------------------------------------------------------------"
|
||||
}
|
||||
|
||||
# ------------------ 依赖 ------------------
|
||||
ensure_packages(){
|
||||
log "📦 安装 Postfix + OpenDKIM..."
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt update -qq
|
||||
apt install -y postfix opendkim opendkim-tools mailutils swaks dnsutils openssl curl
|
||||
}
|
||||
|
||||
# ------------------ SSL ------------------
|
||||
verify_cert(){
|
||||
if [[ -f "$CERT" && -f "$KEY" ]]; then
|
||||
log "🔐 使用自有 SSL 证书:$CERT"
|
||||
openssl x509 -noout -subject -dates -in "$CERT" || true
|
||||
else
|
||||
log "⚠️ 未检测到 ${CERT}/${KEY},生成自签证书..."
|
||||
mkdir -p /etc/ssl
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
|
||||
-subj "/CN=${HOSTNAME}" -keyout "$KEY" -out "$CERT"
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------ DKIM ------------------
|
||||
deploy_dkim(){
|
||||
log "🔏 配置 OpenDKIM..."
|
||||
mkdir -p "${DKIM_KEY_DIR}"
|
||||
cd "${DKIM_KEY_DIR}"
|
||||
if [ ! -f "${DKIM_SELECTOR}.private" ]; then
|
||||
opendkim-genkey -s "${DKIM_SELECTOR}" -d "${DOMAIN}"
|
||||
chown opendkim:opendkim "${DKIM_SELECTOR}.private" "${DKIM_SELECTOR}.txt"
|
||||
chmod 600 "${DKIM_SELECTOR}.private"
|
||||
fi
|
||||
|
||||
cat >/etc/opendkim.conf <<EOF
|
||||
Syslog yes
|
||||
UMask 002
|
||||
Mode sv
|
||||
Canonicalization relaxed/simple
|
||||
SubDomains no
|
||||
KeyTable /etc/opendkim/key.table
|
||||
SigningTable /etc/opendkim/signing.table
|
||||
ExternalIgnoreList refile:/etc/opendkim/trusted.hosts
|
||||
InternalHosts refile:/etc/opendkim/trusted.hosts
|
||||
Socket inet:8891@localhost
|
||||
UserID opendkim
|
||||
EOF
|
||||
|
||||
cat >/etc/opendkim/key.table <<EOF
|
||||
${DKIM_SELECTOR}._domainkey.${DOMAIN} ${DOMAIN}:${DKIM_SELECTOR}:${DKIM_KEY_DIR}/${DKIM_SELECTOR}.private
|
||||
EOF
|
||||
cat >/etc/opendkim/signing.table <<EOF
|
||||
*@${DOMAIN} ${DKIM_SELECTOR}._domainkey.${DOMAIN}
|
||||
EOF
|
||||
cat >/etc/opendkim/trusted.hosts <<EOF
|
||||
127.0.0.1
|
||||
localhost
|
||||
${DOMAIN}
|
||||
EOF
|
||||
|
||||
chown -R opendkim:opendkim /etc/opendkim
|
||||
systemctl enable --now opendkim
|
||||
}
|
||||
|
||||
# ------------------ Postfix ------------------
|
||||
|
||||
deploy_postfix() {
|
||||
verify_cert
|
||||
log "🚀 配置 Postfix Send-only (仅启用 587 / STARTTLS)..."
|
||||
|
||||
# 确保 postfix 存在
|
||||
command -v postconf >/dev/null 2>&1 || die "Postfix 未安装"
|
||||
|
||||
# 主配置(禁用入站、仅发信)
|
||||
postconf -e "myhostname = ${HOSTNAME}"
|
||||
postconf -e "myorigin = ${DOMAIN}"
|
||||
postconf -e "mydestination = "
|
||||
postconf -e "relayhost = "
|
||||
postconf -e "inet_interfaces = all"
|
||||
postconf -e "inet_protocols = all"
|
||||
postconf -e "biff = no"
|
||||
postconf -e "append_dot_mydomain = no"
|
||||
postconf -e "readme_directory = no"
|
||||
postconf -e "smtpd_banner = ${HOSTNAME} ESMTP"
|
||||
postconf -e "compatibility_level = 2"
|
||||
postconf -e "mydomain = ${DOMAIN}"
|
||||
postconf -e "smtp_helo_name = ${HOSTNAME}"
|
||||
postconf -e "alias_maps = hash:/etc/aliases"
|
||||
postconf -e "alias_database = hash:/etc/aliases"
|
||||
postconf -e "mynetworks = 127.0.0.0/8 [::1]/128"
|
||||
postconf -e "relay_domains = ${DOMAIN}"
|
||||
|
||||
# TLS & DKIM
|
||||
postconf -e "smtpd_tls_cert_file = ${CERT}"
|
||||
postconf -e "smtpd_tls_key_file = ${KEY}"
|
||||
postconf -e "smtpd_tls_security_level = may"
|
||||
postconf -e "smtp_tls_security_level = may"
|
||||
postconf -e "smtp_use_tls = yes"
|
||||
postconf -e "smtp_tls_note_starttls_offer = yes"
|
||||
postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
|
||||
postconf -e "smtpd_tls_auth_only = yes"
|
||||
postconf -e "milter_default_action = accept"
|
||||
postconf -e "milter_protocol = 6"
|
||||
postconf -e "smtpd_milters = inet:localhost:8891"
|
||||
postconf -e "non_smtpd_milters = inet:localhost:8891"
|
||||
|
||||
# 禁用 25 端口入站,仅启用 587
|
||||
cat >/etc/postfix/master.cf <<EOF
|
||||
smtp inet n - y - - smtpd
|
||||
# 关闭 25 端口监听
|
||||
smtp inet n - n - - reject
|
||||
|
||||
submission inet n - y - - smtpd
|
||||
-o syslog_name=postfix/submission
|
||||
-o smtpd_tls_security_level=encrypt
|
||||
-o smtpd_sasl_auth_enable=no
|
||||
-o smtpd_relay_restrictions=permit_mynetworks,reject_unauth_destination
|
||||
-o milter_macro_daemon_name=ORIGINATING
|
||||
EOF
|
||||
|
||||
systemctl enable --now postfix
|
||||
systemctl restart postfix
|
||||
sleep 1
|
||||
|
||||
# 验证监听端口
|
||||
if ss -tlnp | grep -qE ':587\s'; then
|
||||
log "✅ Postfix 已启用并仅监听 587 端口 (STARTTLS Send-Only 模式)"
|
||||
else
|
||||
die "❌ 端口 587 未成功监听,请检查日志:journalctl -xeu postfix"
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------ DNS 模板 ------------------
|
||||
show_dns_record(){
|
||||
log "🌐 生成 DNS 模板(SPF / DKIM / DMARC / rDNS / HELO)..."
|
||||
local DKIM_TXT DKIM_PUB LINE LEN=255
|
||||
if [[ -f "${DKIM_KEY_DIR}/${DKIM_SELECTOR}.txt" ]]; then
|
||||
DKIM_TXT=$(tr -d '\n' < "${DKIM_KEY_DIR}/${DKIM_SELECTOR}.txt" | sed 's/"//g')
|
||||
DKIM_PUB=$(echo "${DKIM_TXT}" | sed -n 's/.*p=\(.*\)$/\1/p' | tr -d ' ')
|
||||
else
|
||||
DKIM_PUB="<DKIM 公钥未生成>"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------------------------"
|
||||
echo "A smtp.${DOMAIN} ${SERVER_IP}"
|
||||
echo "MX ${DOMAIN} smtp.${DOMAIN}."
|
||||
echo "SPF @ \"v=spf1 a:smtp.${DOMAIN} -all\""
|
||||
echo -n "DKIM ${DKIM_SELECTOR}._domainkey "
|
||||
echo "\"v=DKIM1; k=rsa; p="
|
||||
while [[ -n "$DKIM_PUB" ]]; do
|
||||
LINE=${DKIM_PUB:0:$LEN}
|
||||
DKIM_PUB=${DKIM_PUB:$LEN}
|
||||
echo "\"${LINE}\""
|
||||
done
|
||||
echo "DMARC _dmarc \"v=DMARC1; p=none; rua=mailto:postmaster@${DOMAIN}\""
|
||||
echo "rDNS (请让 ${SERVER_IP} 反查为 ${HOSTNAME})"
|
||||
echo "HELO (EHLO 输出应为 ${HOSTNAME})"
|
||||
echo "----------------------------------------------------------"
|
||||
}
|
||||
|
||||
# ------------------ 自检 ------------------
|
||||
check_self(){
|
||||
log "🔍 自检 SPF / DKIM / DMARC / rDNS / 端口 ..."
|
||||
echo
|
||||
echo "SPF:"; dig +short TXT ${DOMAIN} | grep -i spf || echo "⚠️ 未配置 SPF"; echo
|
||||
echo "DKIM:"; dig +short TXT ${DKIM_SELECTOR}._domainkey.${DOMAIN} || echo "⚠️ 未配置 DKIM"; echo
|
||||
echo "DMARC:"; dig +short TXT _dmarc.${DOMAIN} || echo "⚠️ 未配置 DMARC"; echo
|
||||
echo "rDNS:"; dig +short -x ${SERVER_IP} || echo "⚠️ 未配置反向解析"; echo
|
||||
echo "端口监听:"; ss -tlnp | grep -E '(:25|:587|:8891)\s' || echo "⚠️ 端口未监听"; echo
|
||||
echo "OpenDKIM testkey:"; opendkim-testkey -d "${DOMAIN}" -s "${DKIM_SELECTOR}" -vvv || true
|
||||
}
|
||||
|
||||
# ------------------ 卸载 ------------------
|
||||
uninstall_reset(){
|
||||
log "🧹 停止并清理..."
|
||||
systemctl stop postfix || true
|
||||
systemctl stop opendkim || true
|
||||
apt purge -y postfix opendkim opendkim-tools || true
|
||||
apt autoremove -y || true
|
||||
rm -rf /etc/postfix /etc/opendkim /var/log/mail*
|
||||
log "✅ 已清理完成(证书未动)。"
|
||||
}
|
||||
|
||||
# ------------------ 主流程 ------------------
|
||||
check_root
|
||||
case "${ACTION}" in
|
||||
deploy)
|
||||
ensure_packages
|
||||
deploy_dkim
|
||||
deploy_postfix
|
||||
show_dns_record
|
||||
;;
|
||||
upgrade)
|
||||
log "⬆️ 更新配置并重启..."
|
||||
deploy_dkim
|
||||
deploy_postfix
|
||||
show_dns_record
|
||||
;;
|
||||
show)
|
||||
case "${2:-}" in
|
||||
dns_record) show_dns_record ;;
|
||||
app_config) show_app_config ;;
|
||||
*) echo "用法: $0 show {dns_record|app_config}" ;;
|
||||
esac
|
||||
;;
|
||||
check)
|
||||
case "${2:-}" in
|
||||
self) check_self ;;
|
||||
send_email) check_send_email ;;
|
||||
*) echo "用法: $0 check {self|send_email}" ;;
|
||||
esac
|
||||
;;
|
||||
uninstall|reset)
|
||||
uninstall_reset
|
||||
;;
|
||||
help|--help|-h)
|
||||
echo "用法: $0 {deploy|upgrade|show {dns_record|app_config}|check {self|send_email}|uninstall}"
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 {deploy|upgrade|show {dns_record|app_config}|check {self|send_email}|uninstall}"
|
||||
;;
|
||||
esac
|
||||
Loading…
Reference in New Issue
Block a user