Set Up SPF, DKIM & DMARC on Virtualmin, CyberPanel, Ubuntu
Stop failed email delivery and spoofing by publishing correct SPF, DKIM, and DMARC on Virtualmin, CyberPanel, or plain Ubuntu. Practical Australian server steps, diagnostics, and when to book Fixwebnode.
If mail from your domain lands in spam, fails authentication, or gets rejected by Gmail and Microsoft 365, your SPF, DKIM, and DMARC records are incomplete or wrong. This guide walks Australian site owners and small-business sysadmins through publishing those three DNS records on Virtualmin, CyberPanel, and a plain Ubuntu Linux mail stack so receiving servers know which hosts may send for your domain, every message is cryptographically signed, and unauthorised senders are rejected or quarantined.
Fixwebnode provides remote Linux and Ubuntu server support for exactly this class of mail-authentication work across Australia—panel configuration, key generation, DNS publication, and live verification—without marketplace bidding.
Why SPF, DKIM, and DMARC matter on your mail server
SPF lists the IP addresses and includes allowed to send mail for your domain. DKIM attaches a cryptographic signature to each message so the body and headers cannot be altered in transit. DMARC tells receivers what to do when SPF or DKIM fails (none, quarantine, or reject) and where to send aggregate reports. Together they cut spoofing, improve inbox placement, and satisfy bulk-sender requirements from major providers. On Virtualmin and CyberPanel the panels can generate keys and suggest records; on bare Ubuntu you wire OpenDKIM and Postfix yourself, then publish TXT records at your DNS host.
Why do SPF, DKIM, or DMARC fail on Virtualmin, CyberPanel, or Ubuntu in Australia?
Most failures come from a missing or overly strict SPF include, a DKIM selector that does not match the signing key on the server, or a DMARC policy published before alignment is clean. Fix the DNS and signing path first; only then tighten policy from p=none to quarantine or reject.
| Symptom | Quick check | When to call Fixwebnode |
|---|---|---|
| Gmail "failed SPF" / soft fail | dig TXT example.com +short and compare sending IP | Multiple includes, forwarding, or mixed panels |
| DKIM body hash mismatch | Selector TXT vs OpenDKIM/Virtualmin key | Key rotation or multi-domain signing broken |
| DMARC aggregate shows fail | rua mailbox + alignment (aspf/adkim) | Policy move to reject or report parsing needed |
Common issues with SPF, DKIM, and DMARC setup
- SPF too long or wrong include chain — messages soft-fail because the sending IP (panel, relay, or ESP) is not covered, or the record exceeds the 10-DNS-lookup limit.
- DKIM selector published but server signs with another name — receivers see no matching public key; Virtualmin/CyberPanel default selectors often differ from a hand-edited OpenDKIM setup.
- DMARC p=reject before SPF/DKIM align — legitimate mail is rejected; reports show spf=fail or dkim=fail on your own domains.
- IPv6 or secondary MX not in SPF — dual-stack Ubuntu hosts send on AAAA while SPF only lists A records.
- Panel DNS cache vs registrar DNS — records edited in Virtualmin BIND never reach the public nameservers still pointed at the registrar.
Issue 1 — SPF soft-fail or permerror (missing IP or too many lookups)
Symptom: headers show Received-SPF: softfail or permerror; Gmail/Outlook junk the message.
Step 1 — Find the real sending IP
dig +short TXT example.com
curl -4 ifconfig.me
curl -6 ifconfig.me
postfix check
postconf -n | grep -E 'myhostname|inet_protocols|smtp_bind'
Note both IPv4 and IPv6 if the host is dual-stack.
Step 2 — Build a single SPF string under 255 octets and ≤10 lookups
v=spf1 ip4:203.0.113.10 ip6:2001:db8::10 include:_spf.google.com -all
Prefer ip4:/ip6: for your own server over nested includes. Use ~all only while testing; move to -all once clean.
Step 3 — Publish and verify
dig TXT example.com +short
dig TXT example.com @8.8.8.8 +short
Wait for TTL; send a test to a Gmail account and open "Show original".
When to call Fixwebnode: flattened SPF still permerrors, or you juggle several ESPs and need a safe include redesign without breaking billing mail.
Issue 2 — DKIM signature present but verification fails
Symptom: dkim=fail (body hash did not verify) or no key for signature.
Step 1 — Confirm what selector the MTA actually uses
sudo grep -r Selector /etc/opendkim.conf /etc/opendkim/ 2>/dev/null
sudo postconf -n | grep -i milter
sudo tail -n 50 /var/log/mail.log | grep -i dkim
On Virtualmin, open the domain → Email Settings → DNS Records / DKIM and note the selector (often the domain or a short tag like default or x).
Step 2 — Publish the exact public key TXT
dig TXT default._domainkey.example.com +short
# CyberPanel / OpenDKIM example key check
sudo cat /etc/opendkim/keys/example.com/default.txt
The host name must be <selector>._domainkey.<domain>. Value starts with v=DKIM1; k=rsa; p=.... Split long keys into quoted 255-char chunks if your DNS UI requires it.
Step 3 — Restart signing and retest
sudo systemctl restart opendkim
sudo systemctl restart postfix
# Virtualmin: regenerate DKIM for the domain in the UI, then apply config
echo 'Test body' | mail -s 'DKIM test' you@gmail.com
When to call Fixwebnode: multi-domain key tables are inconsistent, milters are out of order, or CyberPanel and manual OpenDKIM both try to sign the same mail.
Issue 3 — DMARC reports show fail after you published p=reject
Symptom: rua reports list your own newsletters or ticket mail as failed; customers bounce.
Step 1 — Start with monitoring only
v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; fo=1; adkim=r; aspf=r
Publish as _dmarc.example.com TXT.
Step 2 — Confirm alignment
dig TXT _dmarc.example.com +short
# After a few days, inspect XML reports or use a simple rua inbox
SPF must pass on the envelope domain (or aligned org domain). DKIM must pass on a domain aligned with the From: header. Relaxed alignment (adkim=r; aspf=r) is usually enough for small business mail.
Step 3 — Tighten only when fail rate is near zero
v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@example.com; adkim=r; aspf=r
Raise pct and move to p=reject in stages.
When to call Fixwebnode: you need report automation, subdomain policies, or BIMI readiness after reject is stable.
How to set up SPF, DKIM, and DMARC on Virtualmin
Prerequisites: Virtualmin with mail enabled, domain already receiving mail, DNS either hosted in Virtualmin BIND or at an external registrar you can edit.
Step 1 — Enable DKIM globally
sudo virtualmin enable-dkim
# or UI: Email Messages → DomainKeys Identified Mail → enable, choose selector
Step 2 — Per-domain signing and suggested DNS
In Virtualmin: select domain → Server Configuration → DNS Records (or Email Settings). Enable DKIM for the domain. Copy the SPF and DKIM TXT suggestions Virtualmin shows. If BIND is authoritative and nameservers point here, apply and wait for propagation. If nameservers stay at the registrar, paste the same TXT values there.
Step 3 — SPF for local IP plus any relay
# Example after noting server IP
v=spf1 ip4:YOUR.IPv4 ip6:YOUR.IPv6 a mx ~all
Replace ~all with -all after tests pass.
Step 4 — DMARC
Add TXT _dmarc.yourdomain with p=none first as above. Verify:
dig TXT yourdomain.com +short
dig TXT default._domainkey.yourdomain.com +short
dig TXT _dmarc.yourdomain.com +short
How to set up SPF, DKIM, and DMARC on CyberPanel
CyberPanel (OpenLiteSpeed + Postfix stack) exposes email and DNS under each website.
Step 1 — Create or select the mail domain in CyberPanel → Email → Email Domains. Ensure the hostname resolves and Postfix is running:
sudo systemctl status postfix
sudo systemctl status opendkim || sudo systemctl status lspd
Step 2 — Generate DKIM in the panel
Website → DNS / Email → DKIM. Create keys; CyberPanel prints the selector and public TXT. Publish at your DNS provider (CyberPanel PowerDNS if you use it, otherwise registrar).
Step 3 — SPF and DMARC TXT
# SPF
v=spf1 ip4:SERVER_IPv4 ip6:SERVER_IPv6 mx -all
# DMARC (monitor first)
v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; adkim=r; aspf=r
Step 4 — Verify signing path
sudo tail -f /var/log/mail.log
# Send test; look for DKIM-Signature header and opendkim "pass" lines
How to set up SPF, DKIM, and DMARC on plain Ubuntu (Postfix + OpenDKIM)
Assumes Ubuntu 22.04/24.04, Postfix already sending, root or sudo access.
Step 1 — Install OpenDKIM
sudo apt update
sudo apt install -y opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys
sudo chown -R opendkim:opendkim /etc/opendkim
Step 2 — Minimal OpenDKIM config
sudo tee /etc/opendkim.conf <<'EOF'
Syslog yes
SyslogSuccess yes
Canonicalization relaxed/simple
Mode sv
SubDomains no
AutoRestart yes
AutoRestartRate 10/1M
UMask 002
UserID opendkim:opendkim
Socket local:/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid
KeyTable /etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList refile:/etc/opendkim/trusted.hosts
InternalHosts refile:/etc/opendkim/trusted.hosts
EOF
sudo mkdir -p /opendkim
sudo chown opendkim:opendkim /opendkim
Step 3 — Keys, tables, trust
DOMAIN=example.com
SELECTOR=default
sudo mkdir -p /etc/opendkim/keys/$DOMAIN
sudo opendkim-genkey -b 2048 -d $DOMAIN -D /etc/opendkim/keys/$DOMAIN -s $SELECTOR -v
sudo chown -R opendkim:opendkim /etc/opendkim/keys
sudo chmod 600 /etc/opendkim/keys/$DOMAIN/$SELECTOR.private
echo "$SELECTOR._domainkey.$DOMAIN $DOMAIN:$SELECTOR:/etc/opendkim/keys/$DOMAIN/$SELECTOR.private" | sudo tee /etc/opendkim/key.table
echo "*@$DOMAIN $SELECTOR._domainkey.$DOMAIN" | sudo tee /etc/opendkim/signing.table
printf '127.0.0.1\nlocalhost\n%s\n*.%s\n' "$DOMAIN" "$DOMAIN" | sudo tee /etc/opendkim/trusted.hosts
sudo cat /etc/opendkim/keys/$DOMAIN/$SELECTOR.txt
Publish the printed TXT at default._domainkey.example.com.
Step 4 — Hook Postfix milter
sudo postconf -e 'milter_default_action = accept'
sudo postconf -e 'milter_protocol = 6'
sudo postconf -e 'smtpd_milters = local:/opendkim/opendkim.sock'
sudo postconf -e 'non_smtpd_milters = local:/opendkim/opendkim.sock'
sudo systemctl enable --now opendkim
sudo systemctl restart postfix opendkim
Step 5 — SPF and DMARC at DNS as in the earlier sections, then:
dig TXT example.com +short
dig TXT default._domainkey.example.com +short
dig TXT _dmarc.example.com +short
echo 'ubuntu dkim test' | mail -s 'auth check' your.address@gmail.com
In Gmail "Show original" you want SPF: PASS, DKIM: PASS, DMARC: PASS (once policy and alignment are set).
Remote diagnostics checklist (any panel)
- Compare public TXT vs what the panel generated (
digagainst 8.8.8.8 and against your authoritative NS). - Confirm the outbound IP with
curl -4/-6 ifconfig.mematches SPF. - Read
/var/log/mail.log(or journalctl -u postfix) for opendkim and SPF-related lines while sending one test. - Check nameserver delegation: if Virtualmin BIND holds records but NS still point at the registrar, public dig will never see panel edits.
- After changes, respect TTL; force checks with
dig +nocacheor a second resolver.
When DIY is enough vs when to book Fixwebnode
DIY is enough when you control one domain, one Ubuntu or panel host, and can publish TXT records and read mail logs. Book a specialist when you have mixed Virtualmin and CyberPanel hosts, outbound relays, Microsoft 365 or Google Workspace side-by-side with local Postfix, repeated permerror on SPF flattening, or you must move DMARC to reject without losing invoices and password resets. Fixwebnode works remotely across Australia for this mail-auth path—see all regions on the service areas page—and can complete key rotation, panel milter wiring, and live header validation with you on a call.
Book remote help for SPF, DKIM, and DMARC
If tests still show fail after the steps above, or you want a clean path from p=none to p=reject on production domains, start a conversation with Fixwebnode. Remote sessions cover Virtualmin, CyberPanel, and Ubuntu Postfix/OpenDKIM end to end. Book via the landing page: Ubuntu Linux server support and bug fixing. Bring your domain name, panel type, and a recent "Show original" header so diagnosis starts immediately.