a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
456 lines
12 KiB
Bash
456 lines
12 KiB
Bash
#!/bin/bash
|
|
################################################################################
|
|
# Script Name: postfix-relay-install.sh
|
|
# Version: 1.0
|
|
# Description: Automated Postfix satellite relay installation — configures
|
|
# Postfix as a relay-only MTA with SASL auth, TLS, sender
|
|
# rewriting, and firewall lockdown
|
|
#
|
|
# Author: Phil Connor
|
|
# Contact: contact@mylinux.work
|
|
# Website: https://mylinux.work
|
|
# License: MIT
|
|
#
|
|
# Usage:
|
|
# sudo ./postfix-relay-install.sh --relay smtp.example.com --port 587
|
|
# sudo ./postfix-relay-install.sh --relay smtp.example.com --user user --pass pass
|
|
# sudo ./postfix-relay-install.sh --dry-run
|
|
#
|
|
################################################################################
|
|
|
|
set -euo pipefail
|
|
|
|
# ============================================================================
|
|
# DEFAULTS
|
|
# ============================================================================
|
|
|
|
RELAY_HOST=""
|
|
RELAY_PORT="587"
|
|
SASL_USER=""
|
|
SASL_PASS=""
|
|
FROM_ADDRESS=""
|
|
HOSTNAME_OVERRIDE=""
|
|
ROOT_ALIAS=""
|
|
TLS_MODE="may"
|
|
NO_FIREWALL=false
|
|
DRY_RUN=false
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
# ============================================================================
|
|
# HELPER FUNCTIONS
|
|
# ============================================================================
|
|
|
|
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
log_step() { echo -e "${CYAN}[STEP]${NC} $*"; }
|
|
|
|
show_usage() {
|
|
cat <<EOF
|
|
Usage: $0 [OPTIONS]
|
|
|
|
Installs and configures Postfix as a satellite relay (outbound only).
|
|
|
|
OPTIONS:
|
|
--relay HOST Relay host FQDN or IP (required)
|
|
--port PORT Relay port: 25, 465, 587 (default: 587)
|
|
--user USER SASL authentication username
|
|
--pass PASS SASL authentication password
|
|
--from ADDRESS Rewrite all sender addresses to this
|
|
--hostname NAME Set Postfix myhostname
|
|
--root-alias ADDR Forward root mail to this address
|
|
--tls MODE TLS mode: may, required, wrapper (default: may)
|
|
--no-firewall Skip firewall configuration
|
|
--dry-run Show what would be done
|
|
-h, --help Show this help
|
|
|
|
EXAMPLES:
|
|
sudo $0 --relay smtp.example.com --port 587
|
|
sudo $0 --relay smtp.example.com --user alerts@example.com --pass AppPass
|
|
sudo $0 --relay smtp.example.com --from noreply@example.com --tls required
|
|
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-h|--help) show_usage ;;
|
|
--relay) RELAY_HOST="$2"; shift 2 ;;
|
|
--port) RELAY_PORT="$2"; shift 2 ;;
|
|
--user) SASL_USER="$2"; shift 2 ;;
|
|
--pass) SASL_PASS="$2"; shift 2 ;;
|
|
--from) FROM_ADDRESS="$2"; shift 2 ;;
|
|
--hostname) HOSTNAME_OVERRIDE="$2"; shift 2 ;;
|
|
--root-alias) ROOT_ALIAS="$2"; shift 2 ;;
|
|
--tls) TLS_MODE="$2"; shift 2 ;;
|
|
--no-firewall) NO_FIREWALL=true; shift ;;
|
|
--dry-run) DRY_RUN=true; shift ;;
|
|
*) log_error "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$RELAY_HOST" ]; then
|
|
log_error "--relay is required"
|
|
echo ""
|
|
show_usage
|
|
fi
|
|
}
|
|
|
|
check_root() {
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
log_error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# OS DETECTION
|
|
# ============================================================================
|
|
|
|
detect_os() {
|
|
if [ -f /etc/os-release ]; then
|
|
. /etc/os-release
|
|
OS_FAMILY=""
|
|
case "$ID" in
|
|
debian|ubuntu) OS_FAMILY="debian" ;;
|
|
rhel|centos|rocky|almalinux|fedora) OS_FAMILY="rhel" ;;
|
|
*)
|
|
if [ -n "${ID_LIKE:-}" ]; then
|
|
case "$ID_LIKE" in
|
|
*debian*|*ubuntu*) OS_FAMILY="debian" ;;
|
|
*rhel*|*centos*|*fedora*) OS_FAMILY="rhel" ;;
|
|
esac
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [ -z "$OS_FAMILY" ]; then
|
|
log_error "Unsupported OS: $ID"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "Detected OS: $PRETTY_NAME (family: $OS_FAMILY)"
|
|
else
|
|
log_error "Cannot detect OS"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# INSTALLATION
|
|
# ============================================================================
|
|
|
|
remove_conflicting_mta() {
|
|
log_step "Removing conflicting MTAs..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would remove sendmail/exim if present"
|
|
return
|
|
fi
|
|
|
|
case "$OS_FAMILY" in
|
|
debian)
|
|
apt-get remove -y -qq exim4 exim4-base exim4-daemon-light sendmail 2>/dev/null || true
|
|
;;
|
|
rhel)
|
|
dnf remove -y -q sendmail 2>/dev/null || true
|
|
;;
|
|
esac
|
|
}
|
|
|
|
install_postfix() {
|
|
log_step "Installing Postfix..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would install postfix and dependencies"
|
|
return
|
|
fi
|
|
|
|
case "$OS_FAMILY" in
|
|
debian)
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
|
|
postfix libsasl2-modules mailutils ca-certificates >/dev/null 2>&1
|
|
;;
|
|
rhel)
|
|
dnf install -y -q \
|
|
postfix cyrus-sasl-plain mailx ca-certificates >/dev/null 2>&1
|
|
;;
|
|
esac
|
|
|
|
log_info "Postfix installed"
|
|
}
|
|
|
|
# ============================================================================
|
|
# CONFIGURATION
|
|
# ============================================================================
|
|
|
|
configure_relay() {
|
|
log_step "Configuring relay host: [$RELAY_HOST]:$RELAY_PORT"
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would configure main.cf"
|
|
return
|
|
fi
|
|
|
|
local my_hostname
|
|
my_hostname="${HOSTNAME_OVERRIDE:-$(hostname -f 2>/dev/null || hostname)}"
|
|
local my_domain
|
|
my_domain=$(echo "$my_hostname" | sed 's/^[^.]*\.//')
|
|
|
|
# Build main.cf
|
|
cat > /etc/postfix/main.cf <<EOF
|
|
# Postfix Satellite Relay Configuration
|
|
# Generated by postfix-relay-install.sh v1.0
|
|
|
|
# Identity
|
|
myhostname = $my_hostname
|
|
mydomain = $my_domain
|
|
myorigin = \$mydomain
|
|
|
|
# Relay configuration
|
|
relayhost = [$RELAY_HOST]:$RELAY_PORT
|
|
|
|
# Listen only on loopback — relay only, no inbound mail
|
|
inet_interfaces = loopback-only
|
|
inet_protocols = all
|
|
mydestination = \$myhostname, localhost.\$mydomain, localhost
|
|
|
|
# SASL authentication
|
|
smtp_sasl_auth_enable = $([ -n "$SASL_USER" ] && echo "yes" || echo "no")
|
|
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
|
|
smtp_sasl_security_options = noanonymous
|
|
smtp_sasl_tls_security_options = noanonymous
|
|
|
|
# TLS configuration
|
|
smtp_use_tls = yes
|
|
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
|
|
smtp_tls_security_level = $TLS_MODE
|
|
smtp_tls_loglevel = 1
|
|
|
|
# Misc
|
|
alias_maps = hash:/etc/aliases
|
|
alias_database = hash:/etc/aliases
|
|
mailbox_size_limit = 0
|
|
recipient_delimiter = +
|
|
compatibility_level = 2
|
|
|
|
# Queue settings
|
|
maximal_queue_lifetime = 1d
|
|
bounce_queue_lifetime = 1d
|
|
EOF
|
|
|
|
# Handle TLS wrapper mode (port 465)
|
|
if [ "$TLS_MODE" = "wrapper" ]; then
|
|
postconf -e "smtp_tls_wrappermode = yes"
|
|
postconf -e "smtp_tls_security_level = encrypt"
|
|
fi
|
|
|
|
# Fix CA cert path for RHEL
|
|
if [ "$OS_FAMILY" = "rhel" ]; then
|
|
postconf -e "smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt"
|
|
fi
|
|
|
|
log_info "main.cf configured"
|
|
}
|
|
|
|
configure_sasl() {
|
|
if [ -z "$SASL_USER" ]; then
|
|
return
|
|
fi
|
|
|
|
log_step "Configuring SASL authentication..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would create sasl_passwd"
|
|
return
|
|
fi
|
|
|
|
echo "[$RELAY_HOST]:$RELAY_PORT $SASL_USER:$SASL_PASS" > /etc/postfix/sasl_passwd
|
|
postmap /etc/postfix/sasl_passwd
|
|
chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
|
|
|
|
log_info "SASL credentials configured"
|
|
}
|
|
|
|
configure_sender_rewrite() {
|
|
if [ -z "$FROM_ADDRESS" ]; then
|
|
return
|
|
fi
|
|
|
|
log_step "Configuring sender rewriting: $FROM_ADDRESS"
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would create sender_canonical"
|
|
return
|
|
fi
|
|
|
|
echo "/.+/ $FROM_ADDRESS" > /etc/postfix/sender_canonical_regexp
|
|
postconf -e "sender_canonical_maps = regexp:/etc/postfix/sender_canonical_regexp"
|
|
|
|
log_info "Sender rewriting configured"
|
|
}
|
|
|
|
configure_aliases() {
|
|
if [ -z "$ROOT_ALIAS" ]; then
|
|
return
|
|
fi
|
|
|
|
log_step "Configuring root alias: $ROOT_ALIAS"
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would set root alias"
|
|
return
|
|
fi
|
|
|
|
if grep -q "^root:" /etc/aliases 2>/dev/null; then
|
|
sed -i "s/^root:.*$/root: $ROOT_ALIAS/" /etc/aliases
|
|
else
|
|
echo "root: $ROOT_ALIAS" >> /etc/aliases
|
|
fi
|
|
|
|
newaliases
|
|
log_info "Root alias set"
|
|
}
|
|
|
|
configure_firewall() {
|
|
if [ "$NO_FIREWALL" = true ]; then
|
|
return
|
|
fi
|
|
|
|
log_step "Configuring firewall (blocking inbound SMTP)..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would block inbound port 25"
|
|
return
|
|
fi
|
|
|
|
# UFW
|
|
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q "active"; then
|
|
ufw deny in 25/tcp >/dev/null 2>&1 || true
|
|
log_info "UFW: blocked inbound port 25"
|
|
fi
|
|
|
|
# firewalld
|
|
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
|
|
firewall-cmd --permanent --remove-service=smtp >/dev/null 2>&1 || true
|
|
firewall-cmd --reload >/dev/null 2>&1 || true
|
|
log_info "firewalld: removed smtp service"
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# SERVICE MANAGEMENT
|
|
# ============================================================================
|
|
|
|
start_postfix() {
|
|
log_step "Starting Postfix..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would enable and start postfix"
|
|
return
|
|
fi
|
|
|
|
systemctl enable postfix >/dev/null 2>&1
|
|
systemctl restart postfix
|
|
|
|
if systemctl is-active --quiet postfix; then
|
|
log_info "Postfix is running"
|
|
else
|
|
log_error "Postfix failed to start"
|
|
journalctl -u postfix --no-pager -n 10
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
send_test() {
|
|
log_step "Sending test email..."
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "[DRY RUN] Would send test email"
|
|
return
|
|
fi
|
|
|
|
local test_to="${ROOT_ALIAS:-root}"
|
|
echo "Test email from $(hostname) via Postfix relay through $RELAY_HOST" | \
|
|
mail -s "Postfix Relay Test — $(hostname) — $(date '+%Y-%m-%d %H:%M')" "$test_to" 2>/dev/null || true
|
|
|
|
log_info "Test email queued (check $test_to inbox)"
|
|
}
|
|
|
|
# ============================================================================
|
|
# VERIFICATION
|
|
# ============================================================================
|
|
|
|
verify() {
|
|
log_step "Verifying configuration..."
|
|
echo ""
|
|
|
|
if systemctl is-active --quiet postfix; then
|
|
log_info "✓ Postfix service: running"
|
|
else
|
|
log_error "✗ Postfix service: not running"
|
|
fi
|
|
|
|
log_info "Relay host: $(postconf -h relayhost 2>/dev/null)"
|
|
log_info "TLS level: $(postconf -h smtp_tls_security_level 2>/dev/null)"
|
|
log_info "SASL auth: $(postconf -h smtp_sasl_auth_enable 2>/dev/null)"
|
|
log_info "Interfaces: $(postconf -h inet_interfaces 2>/dev/null)"
|
|
|
|
echo ""
|
|
log_info "Mail queue:"
|
|
mailq 2>/dev/null | tail -5
|
|
|
|
echo ""
|
|
log_info "Installation complete"
|
|
echo ""
|
|
log_info "Useful commands:"
|
|
echo " mailq — view mail queue"
|
|
echo " postqueue -f — flush mail queue"
|
|
echo " tail -f /var/log/mail.log — watch mail log (Debian)"
|
|
echo " tail -f /var/log/maillog — watch mail log (RHEL)"
|
|
echo " echo test | mail -s test root — send test email"
|
|
}
|
|
|
|
# ============================================================================
|
|
# MAIN
|
|
# ============================================================================
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
check_root
|
|
detect_os
|
|
|
|
echo ""
|
|
log_info "=== Postfix Relay Install Script v1.0 ==="
|
|
echo ""
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_warn "DRY RUN MODE — no changes will be made"
|
|
echo ""
|
|
fi
|
|
|
|
remove_conflicting_mta
|
|
install_postfix
|
|
configure_relay
|
|
configure_sasl
|
|
configure_sender_rewrite
|
|
configure_aliases
|
|
configure_firewall
|
|
start_postfix
|
|
send_test
|
|
|
|
if [ "$DRY_RUN" != true ]; then
|
|
verify
|
|
fi
|
|
}
|
|
|
|
main "$@"
|