This guide walks you through setting up a secure send-only mail server on a Linux VPS using:
- ✅ CloudPanel for web hosting
- ✅ Cloudflare for DNS and SSL
- ✅ Postfix (for sending mail)
- ✅ Dovecot (optional, for LMTP/expansion)
- ✅ OpenDKIM (for DKIM signing)
- ✅ mailutils (for CLI testing)
- ✅ PHPMailer (for PHP mail)
📬 Example Domain: example.com
This script has been tested and works on:
| OS / Platform | Version(s) | Notes |
|---|---|---|
| Ubuntu Server | 22.04, 24.04 LTS | Officially supported |
| Debian | 11, 12 | Works with slight package name variations |
| AlmaLinux / Rocky Linux | 8, 9 | Use dnf and update package names |
| CentOS Stream | 8, 9 | Not recommended; EOL risk |
| CloudPanel (Debian-based) | 2.5.x+ | Full compatibility for Web + Mail sending |
📢 Note: The script is written for APT-based systems (Debian/Ubuntu). For RHEL systems, you'll need to adapt
aptcommands todnforyum, and confirm path compatibility.
- Linux VPS with Ubuntu 24.04 LTS or compatible OS
- CloudPanel already installed and configured
- Cloudflare account managing your DNS (e.g.
example.com) - Sudo or root access to the server
- Basic DNS knowledge
Use Cloudflare Origin SSL Certificates for secure server-to-Cloudflare encryption.
-
Go to Cloudflare Dashboard
-
Select your domain (
example.com) -
Navigate to SSL/TLS > Origin Server
-
Click Create Certificate
- Choose RSA 2048
- Validity: 15 years
-
Save the:
- Private key:
/etc/ssl/private/cloudflare.key - Certificate:
/etc/ssl/certs/cloudflare.crt
- Private key:
-
Set correct permissions:
chmod 600 /etc/ssl/private/cloudflare.key
chmod 644 /etc/ssl/certs/cloudflare.crtCreate a file: install-mail-sender.sh
# Send-Only Mail Server Setup Script
# Author: xohail0 | Domain: example.com
#!/bin/bash
DOMAIN="example.com"
HOSTNAME="mail.$DOMAIN"
SSL_CERT="/etc/ssl/certs/cloudflare.crt"
SSL_KEY="/etc/ssl/private/cloudflare.key"
DKIM_SELECTOR="default"
echo "127.0.0.1 $HOSTNAME" >> /etc/hosts
hostnamectl set-hostname "$HOSTNAME"
echo "[1/6] Installing packages..."
apt update
apt install -y postfix mailutils dovecot-core opendkim opendkim-tools
echo "[2/6] Configuring Postfix..."
postconf -e "myhostname = $HOSTNAME"
postconf -e "myorigin = /etc/mailname"
postconf -e "mydestination = localhost"
postconf -e "relayhost ="
postconf -e "mynetworks = 127.0.0.0/8"
postconf -e "inet_interfaces = loopback-only"
postconf -e "inet_protocols = ipv4"
postconf -e "smtpd_tls_cert_file = $SSL_CERT"
postconf -e "smtpd_tls_key_file = $SSL_KEY"
postconf -e "smtpd_use_tls = yes"
postconf -e "smtpd_tls_security_level = may"
postconf -e "smtp_tls_security_level = may"
postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
echo "$DOMAIN" > /etc/mailname
echo "[3/6] Configuring OpenDKIM..."
cat > /etc/opendkim.conf <<EOF
Syslog yes
UMask 002
Canonicalization relaxed/simple
Mode s
SubDomains no
AutoRestart yes
AutoRestartRate 10/1h
Socket inet:12301@localhost
PidFile /var/run/opendkim/opendkim.pid
OversignHeaders From
TrustAnchorFile /usr/share/dns/root.key
UserID opendkim
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
InternalHosts /etc/opendkim/trusted.hosts
EOF
mkdir -p /etc/opendkim/keys/$DOMAIN
cat > /etc/opendkim/key.table <<EOF
$DKIM_SELECTOR._domainkey.$DOMAIN $DOMAIN:$DKIM_SELECTOR:/etc/opendkim/keys/$DOMAIN/$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
echo "[4/6] Generating DKIM keys..."
opendkim-genkey -s $DKIM_SELECTOR -d $DOMAIN -D /etc/opendkim/keys/$DOMAIN
chown -R opendkim:opendkim /etc/opendkim/keys/$DOMAIN
chmod 600 /etc/opendkim/keys/$DOMAIN/$DKIM_SELECTOR.private
echo "[5/6] Connecting Postfix with OpenDKIM..."
postconf -e "milter_default_action = accept"
postconf -e "milter_protocol = 6"
postconf -e "smtpd_milters = inet:localhost:12301"
postconf -e "non_smtpd_milters = inet:localhost:12301"
echo "[6/6] Restarting services..."
systemctl restart opendkim
systemctl restart postfix
echo ""
echo "✅ Installation complete!"
echo ""
echo "🔐 DKIM DNS record (add to Cloudflare as TXT record for $DKIM_SELECTOR._domainkey.$DOMAIN):"
cat /etc/opendkim/keys/$DOMAIN/$DKIM_SELECTOR.txt
echo ""
echo "🧪 Test email:"
echo "echo 'This is a test email body' | mail -s 'Test Subject' [email protected]"Run the script:
sudo bash install-mail-sender.shuse PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'localhost';
$mail->Port = 25;
$mail->SMTPAuth = false;
$mail->setFrom('[email protected]', 'GSM Xcode');
$mail->addAddress('[email protected]');
$mail->Subject = 'Test Email';
$mail->Body = 'This is a test email sent via local Postfix server.';
$mail->send();| Type | Name | Value |
|---|---|---|
| A | Your VPS IP |
|
| TXT | @ | v=spf1 ip4:YOUR_SERVER_IP ~all |
| TXT | default._domainkey | Paste DKIM record from script output |
| TXT | _dmarc | v=DMARC1; p=none; rua=mailto:[email protected] |
⚠️ Disable Cloudflare Proxy (orange cloud) formail.example.comA record — set to DNS only.
- Test via CLI:
echo "Test message" | mail -s "Test Subject" [email protected]- This setup is send-only: it does not receive incoming emails.
- Do not expose Postfix to the public internet unless properly secured.
- Use port 25 locally or through trusted web apps (e.g. PHP with PHPMailer).
To expand:
- Add support for incoming mail (IMAP via Dovecot)
- Add DKIM auto renewal
- Use Postfix submission port (587) with SASL auth
- Monitor logs:
tail -f /var/log/mail.log✅ You're now sending mail securely from your own VPS using CloudPanel + Cloudflare + Postfix + DKIM!
Maintained by xohail0 — This guide is built to help beginners to advanced users configure a reliable, secure, send-only mail server for apps, scripts, or websites.
Pull requests welcome. Contributions encouraged!