Complete Mail Server Setup Guide with Postfix and Dovecot on Ubuntu Server 22.04
Setting up a mail server is one of the most complex tasks in system administration. This comprehensive guide walks through deploying a secure, production-ready mail server with Postfix, Dovecot, and essential security features on Ubuntu Server 22.04.
Prerequisites
- Ubuntu Server 22.04 LTS with static IP
- Domain name with DNS control
- Valid SSL certificate (or use Let's Encrypt)
- Basic understanding of email protocols
- Minimum 2GB RAM, 20GB storage
DNS Configuration
Required DNS Records
Before starting, configure these DNS records:
# A Records
mail.example.com A 192.168.1.100
example.com A 192.168.1.100
# MX Record
example.com MX 10 mail.example.com
# SPF Record
example.com TXT "v=spf1 mx a ip4:192.168.1.100 -all"
# DKIM Record (will be added after configuration)
# DMARC Record
_dmarc.example.com TXT "v=DMARC1; p=quarantine; rua=mailto:postmaster@example.com"
# PTR Record (Reverse DNS)
100.1.168.192.in-addr.arpa PTR mail.example.com
Initial System Setup
Set Hostname
sudo hostnamectl set-hostname mail.example.com
sudo nano /etc/hosts
127.0.0.1 localhost
192.168.1.100 mail.example.com mail
Update System
sudo apt update && sudo apt upgrade -y
sudo apt install wget curl vim net-tools -y
Postfix Installation and Configuration
Install Postfix
sudo apt install postfix postfix-mysql -y
During installation, select: - Internet Site - System mail name: example.com
Basic Postfix Configuration
sudo nano /etc/postfix/main.cf
# Basic Configuration
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
mydestination = $myhostname, localhost.$mydomain, localhost
# Virtual Domain Configuration
virtual_mailbox_domains = example.com
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = hash:/etc/postfix/virtual
# TLS Configuration
smtpd_tls_cert_file = /etc/ssl/certs/mail.example.com.crt
smtpd_tls_key_file = /etc/ssl/private/mail.example.com.key
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_ciphers = high
smtpd_tls_mandatory_ciphers = high
tls_preempt_cipherlist = yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
# SASL Configuration
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
# Restrictions
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
reject_rbl_client zen.spamhaus.org,
reject_rbl_client bl.spamcop.net
smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_sender,
reject_unknown_sender_domain
# Message Size and Connection Limits
message_size_limit = 52428800
mailbox_size_limit = 0
recipient_delimiter = +
smtp_tls_security_level = may
Configure Virtual Mailboxes
# Create mail user and directories
sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail/vhosts -m
sudo mkdir -p /var/mail/vhosts/example.com
sudo chown -R vmail:vmail /var/mail/vhosts
# Create virtual mailbox mapping
sudo nano /etc/postfix/vmailbox
info@example.com example.com/info/
admin@example.com example.com/admin/
user@example.com example.com/user/
# Create virtual alias mapping
sudo nano /etc/postfix/virtual
postmaster@example.com admin@example.com
webmaster@example.com admin@example.com
abuse@example.com admin@example.com
# Generate database files
sudo postmap /etc/postfix/vmailbox
sudo postmap /etc/postfix/virtual
Configure master.cf
sudo nano /etc/postfix/master.cf
Uncomment and modify these lines:
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
-o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=$mua_client_restrictions
-o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_sender_restrictions=$mua_sender_restrictions
-o smtpd_recipient_restrictions=
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=$mua_client_restrictions
-o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_sender_restrictions=$mua_sender_restrictions
-o smtpd_recipient_restrictions=
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
Dovecot Installation and Configuration
Install Dovecot
sudo apt install dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd -y
Configure Dovecot
sudo nano /etc/dovecot/dovecot.conf
# Protocols
protocols = imap pop3 lmtp
# Listen on all interfaces
listen = *, ::
# Base directory
base_dir = /var/run/dovecot/
Configure Mail Location
sudo nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = vmail
first_valid_uid = 5000
first_valid_gid = 5000
Configure Authentication
sudo nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
# Comment out system auth
#!include auth-system.conf.ext
# Enable SQL auth (if using) or passwd file
!include auth-passwdfile.conf.ext
Create Password File
sudo nano /etc/dovecot/users
# Format: user@domain:password:uid:gid::/var/mail/vhosts/domain/user::
admin@example.com:{PLAIN}password123:5000:5000::/var/mail/vhosts/example.com/admin::
user@example.com:{PLAIN}password456:5000:5000::/var/mail/vhosts/example.com/user::
For encrypted passwords:
# Generate encrypted password
doveadm pw -s SHA512-CRYPT
Configure Password File Auth
sudo nano /etc/dovecot/conf.d/auth-passwdfile.conf.ext
passdb {
driver = passwd-file
args = scheme=CRYPT username_format=%u /etc/dovecot/users
}
userdb {
driver = passwd-file
args = username_format=%u /etc/dovecot/users
}
Configure Master Settings
sudo nano /etc/dovecot/conf.d/10-master.conf
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
port = 110
}
inet_listener pop3s {
port = 995
ssl = yes
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
unix_listener auth-userdb {
mode = 0666
user = vmail
group = vmail
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
user = dovecot
}
service auth-worker {
user = vmail
}
Configure SSL
sudo nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/ssl/certs/mail.example.com.crt
ssl_key = </etc/ssl/private/mail.example.com.key
ssl_min_protocol = TLSv1.2
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl_prefer_server_ciphers = yes
SSL Certificate Setup
Using Let's Encrypt
# Install Certbot
sudo apt install certbot -y
# Stop services temporarily
sudo systemctl stop postfix dovecot
# Get certificate
sudo certbot certonly --standalone -d mail.example.com
# Update configuration files with Let's Encrypt paths
# Postfix: /etc/postfix/main.cf
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
# Dovecot: /etc/dovecot/conf.d/10-ssl.conf
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
# Restart services
sudo systemctl start postfix dovecot
Auto-renewal Script
sudo nano /etc/cron.daily/renew-certificates
#!/bin/bash
certbot renew --pre-hook "systemctl stop postfix dovecot" --post-hook "systemctl start postfix dovecot"
sudo chmod +x /etc/cron.daily/renew-certificates
Spam and Virus Protection
Install SpamAssassin
sudo apt install spamassassin spamc -y
sudo systemctl enable spamassassin
Configure SpamAssassin
sudo nano /etc/default/spamassassin
ENABLED=1
OPTIONS="--create-prefs --max-children 5 --helper-home-dir"
PIDFILE="/var/run/spamd.pid"
CRON=1
Configure Postfix for SpamAssassin
sudo nano /etc/postfix/master.cf
Add after smtp line:
-o content_filter=spamassassin
spamassassin unix - n n - - pipe
user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
Install ClamAV
sudo apt install clamav clamav-daemon -y
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam clamav-daemon
Install Amavis
sudo apt install amavisd-new -y
Configure Amavis
sudo nano /etc/amavis/conf.d/15-content_filter_mode
Uncomment these lines:
@bypass_virus_checks_maps = (
\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);
@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
Configure Postfix for Amavis
sudo nano /etc/postfix/main.cf
Add:
content_filter = smtp-amavis:[127.0.0.1]:10024
sudo nano /etc/postfix/master.cf
Add:
smtp-amavis unix - - n - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20
127.0.0.1:10025 inet n - n - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
DKIM Configuration
Install OpenDKIM
sudo apt install opendkim opendkim-tools -y
Configure OpenDKIM
sudo nano /etc/opendkim.conf
Syslog yes
UMask 007
Domain example.com
KeyFile /etc/opendkim/keys/example.com/mail.private
Selector mail
Socket inet:12301@localhost
PidFile /var/run/opendkim/opendkim.pid
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
Generate DKIM Keys
sudo mkdir -p /etc/opendkim/keys/example.com
cd /etc/opendkim/keys/example.com
sudo opendkim-genkey -s mail -d example.com
sudo chown opendkim:opendkim mail.private
Configure DKIM Tables
sudo nano /etc/opendkim/KeyTable
mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private
sudo nano /etc/opendkim/SigningTable
*@example.com mail._domainkey.example.com
sudo nano /etc/opendkim/TrustedHosts
127.0.0.1
localhost
192.168.1.0/24
example.com
mail.example.com
Add DKIM to Postfix
sudo nano /etc/postfix/main.cf
Add:
# DKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301
Publish DKIM Record
sudo cat /etc/opendkim/keys/example.com/mail.txt
Add the output to your DNS as a TXT record.
Webmail Setup (Roundcube)
Install Dependencies
sudo apt install apache2 php php-mysql php-xml php-mbstring php-intl php-zip php-gd php-curl php-imagick mariadb-server -y
Setup Database
sudo mysql_secure_installation
sudo mysql -u root -p
CREATE DATABASE roundcube;
CREATE USER 'roundcube'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON roundcube.* TO 'roundcube'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Install Roundcube
cd /tmp
wget https://github.com/roundcube/roundcubemail/releases/download/1.6.5/roundcubemail-1.6.5-complete.tar.gz
tar xzf roundcubemail-1.6.5-complete.tar.gz
sudo mv roundcubemail-1.6.5 /var/www/roundcube
sudo chown -R www-data:www-data /var/www/roundcube
Configure Apache
sudo nano /etc/apache2/sites-available/roundcube.conf
<VirtualHost *:80>
ServerName webmail.example.com
DocumentRoot /var/www/roundcube
<Directory /var/www/roundcube>
Options +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/roundcube_error.log
CustomLog ${APACHE_LOG_DIR}/roundcube_access.log combined
</VirtualHost>
sudo a2ensite roundcube
sudo a2enmod rewrite
sudo systemctl restart apache2
Testing and Troubleshooting
Test SMTP
# Test local delivery
echo "Test email" | mail -s "Test Subject" admin@example.com
# Test SMTP with telnet
telnet localhost 25
EHLO mail.example.com
QUIT
# Test SMTP-AUTH
perl -MMIME::Base64 -e 'print encode_base64("admin\@example.com");'
perl -MMIME::Base64 -e 'print encode_base64("password");'
Test IMAP
telnet localhost 143
a LOGIN admin@example.com password
b SELECT INBOX
c LOGOUT
Check Logs
# Postfix logs
sudo tail -f /var/log/mail.log
# Dovecot logs
sudo tail -f /var/log/dovecot.log
# System logs
sudo journalctl -u postfix -f
sudo journalctl -u dovecot -f
Common Issues
Permission Problems
sudo chown -R vmail:vmail /var/mail/vhosts
sudo chmod -R 700 /var/mail/vhosts
Postfix Queue Management
# View queue
sudo postqueue -p
# Flush queue
sudo postqueue -f
# Delete all queued mail
sudo postsuper -d ALL
Security Best Practices
Fail2ban Configuration
sudo apt install fail2ban -y
sudo nano /etc/fail2ban/jail.local
[postfix]
enabled = true
port = smtp,ssmtp,submission
logpath = /var/log/mail.log
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps,submission,ssmtp
logpath = /var/log/mail.log
Rate Limiting
sudo nano /etc/postfix/main.cf
Add:
# Rate limiting
smtpd_client_connection_rate_limit = 10
smtpd_client_message_rate_limit = 30
anvil_rate_time_unit = 60s
Regular Maintenance Script
sudo nano /usr/local/bin/mail-maintenance.sh
#!/bin/bash
# Mail server maintenance script
# Update spam rules
sa-update
# Update ClamAV
freshclam
# Check mail queue
queue_size=$(mailq | tail -1 | awk '{print $5}')
if [ "$queue_size" -gt 100 ]; then
echo "Warning: Mail queue has $queue_size messages" | mail -s "Mail Queue Alert" admin@example.com
fi
# Check disk usage
disk_usage=$(df -h /var/mail | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$disk_usage" -gt 80 ]; then
echo "Warning: Mail partition is $disk_usage% full" | mail -s "Disk Space Alert" admin@example.com
fi
# Restart services if needed
for service in postfix dovecot spamassassin clamav-daemon; do
if ! systemctl is-active --quiet $service; then
systemctl start $service
echo "$service was down and has been restarted" | mail -s "Service Restart Alert" admin@example.com
fi
done
sudo chmod +x /usr/local/bin/mail-maintenance.sh
sudo crontab -e
# Add: 0 * * * * /usr/local/bin/mail-maintenance.sh
Conclusion
This comprehensive guide covered setting up a production-ready mail server on Ubuntu Server 22.04. The configuration includes secure SMTP/IMAP services, spam filtering, virus scanning, and webmail access. Remember to regularly monitor logs, update spam rules, and maintain security patches to keep your mail server running smoothly and securely.