diff --git a/scripts/install_opensmtpd_sendonly.sh b/scripts/install_opensmtpd_sendonly.sh index 08a9978..7d20b77 100644 --- a/scripts/install_opensmtpd_sendonly.sh +++ b/scripts/install_opensmtpd_sendonly.sh @@ -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 </etc/smtpd/smtpd.conf </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 模板 ------------------ diff --git a/scripts/install_postfix_sendonly.sh b/scripts/install_postfix_sendonly.sh new file mode 100644 index 0000000..9e57f72 --- /dev/null +++ b/scripts/install_postfix_sendonly.sh @@ -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 <" + 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 </etc/opendkim/key.table </etc/opendkim/signing.table </etc/opendkim/trusted.hosts </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 <