Setting Up a Secure SMTP/IMAP Server on Ubuntu with Postfix, OpenDKIM & Dovecot
This guide walks you through building your own mail server at mail.thekbbohara.xyz on Ubuntu. You'll configure DNS in Cloudflare, obtain TLS certificates, set up Postfix for SMTP, OpenDKIM for signing, and Dovecot for IMAP/POP3.
- Prerequisites
VPS with Ubuntu (20.04+).
Domain thekbbohara.xyz, managed in Cloudflare.
Root or sudo access via SSH (ssh root@91.99.29.246).
Basic Linux command‑line familiarity.
- DNS Configuration in Cloudflare
Add the following records in your Cloudflare dashboard for the zone thekbbohara.xyz. For each record, set Proxy status to DNS only (gray cloud), not orange.
- A Record
`Type: A
Name: @
IPv4 address: 91.99.29.246
TTL: Auto
Proxy status: DNS only (gray cloud)`
- A Record
`Type: A
Name: mail
IPv4 address: 91.99.29.246
TTL: Auto
Proxy status: DNS only (gray cloud)`
- MX Record
`Type: MX
Name: @
Mail server: mail.thekbbohara.xyz
Priority: 10
TTL: Auto
Proxy status: n/a`
- SPF Record
`Type: TXT
Name: @
Content: v=spf1 a:mail.thekbbohara.xyz -all
TTL: Auto
Proxy status: DNS only (gray cloud)`
- DKIM Record (after key generation)
`Type: TXT
Name: default._domainkey
Content: v=DKIM1; k=rsa; p=YOUR_PUBLIC_KEY
TTL: Auto
Proxy status: DNS only (gray cloud)`
- DMARC Record
`Type: TXT
Name: _dmarc
Content: v=DMARC1; p=none; rua=mailto:postmaster@thekbbohara.xyz
TTL: Auto
Proxy status: DNS only (gray cloud)`
- Install & Configure Postfix
Install
sudo apt update
sudo apt install -y postfix
During install, choose Internet Site, System mail name=thekbbohara.xyz.
Configure /etc/postfix/main.cf – key settings:
`myhostname = mail.thekbbohara.xyz
mydomain = thekbbohara.xyz
myorigin = $mydomain
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost
relayhost =
Milter (OpenDKIM)
smtpd_milters = inet:localhost:12345
non_smtpd_milters = $smtpd_milters
TLS (letsencrypt paths)
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.thekbbohara.xyz/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.thekbbohara.xyz/privkey.pem
smtpd_use_tls=yes
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache`
Reload
sudo systemctl reload postfix
- Obtain TLS Certificates with Certbot
Open port 80
sudo ufw allow 80/tcp
sudo ufw reload
Install Certbot & run
sudo apt install -y certbot
sudo systemctl stop postfix
sudo certbot certonly --standalone -d mail.thekbbohara.xyz --agree-tos --email postmaster@thekbbohara.xyz --non-interactive
sudo systemctl start postfix
Verify
ls /etc/letsencrypt/live/mail.thekbbohara.xyz/
cert.pem chain.pem fullchain.pem privkey.pem
- Setup OpenDKIM for DKIM Signing
Install
sudo apt install -y opendkim opendkim-tools
Create user/group
sudo groupadd --system opendkim
sudo useradd --system --gid opendkim --home /var/run/opendkim --shell /usr/sbin/nologin opendkim
Generate keys
sudo mkdir -p /etc/opendkim/keys/thekbbohara.xyz
cd /etc/opendkim/keys/thekbbohara.xyz
sudo opendkim-genkey -r -b 2048 -d thekbbohara.xyz -s default
sudo chown opendkim:opendkim default.private
sudo chmod 600 default.private
Publish DNS record:
cat default.txt
Copy the v=DKIM1;...p=... string into Cloudflare as TXT under default._domainkey.
Configure /etc/opendkim.conf
Domain thekbbohara.xyz
KeyFile /etc/opendkim/keys/thekbbohara.xyz/default.private
Selector default
Socket inet:12345@localhost
Enable socket in /etc/default/opendkim:
SOCKET="inet:12345@localhost"
Restart services
sudo systemctl enable --now opendkim
sudo systemctl reload postfix
Test key
opendkim-testkey -d thekbbohara.xyz -s default -vv
should report "key OK"
- Enable SMTPS (Implicit TLS on Port 465)
Edit /etc/postfix/master.cf and uncomment the smtps block:
smtps inet n - n - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
Reload Postfix
sudo systemctl reload postfix
Open firewall
sudo ufw allow 465/tcp
Verify
sudo ss -tulpn | grep ':465'
- Configure Dovecot for IMAP/POP3
Install
sudo apt install -y dovecot-imapd dovecot-pop3d dovecot-lmtpd
Mail location (/etc/dovecot/conf.d/10-mail.conf):
mail_location = maildir:~/Maildir
Authentication socket (/etc/dovecot/conf.d/10-master.conf):
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
SSL config (/etc/dovecot/conf.d/10-ssl.conf):
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.thekbbohara.xyz/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.thekbbohara.xyz/privkey.pem
Enable & start
sudo systemctl enable --now dovecot
Open ports
sudo ufw allow 143/tcp # IMAP
sudo ufw allow 993/tcp # IMAPS
sudo ufw allow 110/tcp # POP3
sudo ufw allow 995/tcp # POP3S
- Testing & Verification
SMTP STARTTLS handshake
openssl s_client -starttls smtp -connect mail.thekbbohara.xyz:25 -crlf <<< "EHLO test\r\nQUIT"
SMTPS implicit TLS
openssl s_client -connect mail.thekbbohara.xyz:465 -crlf <<< "QUIT"
Send a test email
swaks --to you@domain.com --from noreply@thekbbohara.xyz --server mail.thekbbohara.xyz --port 465 --auth LOGIN --auth-user noreply --auth-password YOUR_PASS --tls
Check mail queue
postqueue -p
Verify reception
ls ~/Maildir/new
Inspect spam score
Send to mail‑tester.com and aim for ≥10/10.
- Troubleshooting
bad field count in master.cf → Ensure each service line has exactly 7 columns before options.
ECONNREFUSED on 465 → Check smtps block in master.cf, reload Postfix, open firewall.
DKIM_INVALID → Re-generate keys, republish DNS, test with opendkim-testkey.
Spam placement → PTR alignment, SPF/DKIM/DMARC, warm up IP, request delisting.
Congratulations! You’ve built a fully functional, secure, and authenticated mail server. 🎉