6.2 KiB
| name | description | version |
|---|---|---|
| email-server-setup | Self-host email server (Postfix + Dovecot + DKIM) on Ubuntu. | 1.0.0 |
Email Server Setup (Postfix + Dovecot + DKIM)
Self-hosted mail server on Ubuntu with virtual mailboxes, SASL authentication, DKIM signing, and IMAPS/SMTPS.
Architecture
Postfix (SMTP:25/465/587) → Dovecot SASL auth → passwd-file
→ OpenDKIM milter (8891) → DKIM signing
Dovecot (IMAP:143/993, POP3:110/995) → Maildir /var/mail/vhosts/
Step 1: Install packages
export DEBIAN_FRONTEND=noninteractive
sudo debconf-set-selections <<< "postfix postfix/mailname string $DOMAIN"
sudo debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'"
sudo apt-get update -qq
sudo apt-get install -y -qq postfix postfix-pcre dovecot-core \
dovecot-imapd dovecot-pop3d opendkim opendkim-tools certbot
Step 2: Create vmail user and directories
sudo groupadd -f vmail
sudo useradd -g vmail -d /var/mail -s /usr/sbin/nologin vmail
sudo mkdir -p /var/mail/vhosts/$DOMAIN
sudo chown -R vmail:vmail /var/mail
sudo chmod -R 700 /var/mail
Step 3: Configure Postfix
Key settings in /etc/postfix/main.cf (see references/postfix-main.cf for the
full working config):
virtual_mailbox_domains— the domain(s) to servevirtual_mailbox_base = /var/mail/vhostsvirtual_mailbox_maps = hash:/etc/postfix/vmailbox- SASL via Dovecot:
smtpd_sasl_type = dovecot, socket at/var/spool/postfix/private/auth - TLS certs point to Let's Encrypt path (use self-signed as fallback)
- DKIM milter:
smtpd_milters = inet:localhost:8891
Create /etc/postfix/vmailbox:
user@domain.com domain.com/user/
Hash it: sudo postmap /etc/postfix/vmailbox
Enable submission (587) and SMTPS (465) in master.cf
Uncomment the submission and smtps service blocks. Replace the
$mua_client_restrictions, $mua_helo_restrictions,
$mua_sender_restrictions variables with concrete values — Postfix does not
define them by default and postfix check will warn endlessly.
Step 4: Configure Dovecot
Mail location (/etc/dovecot/conf.d/10-mail.conf)
mail_location = maildir:/var/mail/vhosts/%d/%n
Authentication (/etc/dovecot/conf.d/10-auth.conf)
Disable system auth, enable passwd-file:
#!include auth-system.conf.ext
!include auth-passwdfile.conf.ext
Update /etc/dovecot/conf.d/auth-passwdfile.conf.ext:
passdb {
driver = passwd-file
args = scheme=SHA512-CRYPT username_format=%u /etc/dovecot/users
}
userdb {
driver = passwd-file
args = username_format=%u /etc/dovecot/users
}
Postfix SASL socket (/etc/dovecot/conf.d/10-master.conf)
Uncomment inside service auth { }:
unix_listener /var/spool/postfix/private/auth {
mode = 0666
}
Create users
HASH=$(doveadm pw -s SHA512-CRYPT -p 'password')
echo "user@domain.com:$HASH::$(id -u vmail):$(id -g vmail)::/var/mail/vhosts/domain.com/user/::" \
| sudo tee -a /etc/dovecot/users
sudo chmod 640 /etc/dovecot/users
sudo chown root:dovecot /etc/dovecot/users
Step 5: Configure DKIM
sudo mkdir -p /etc/opendkim/keys/$DOMAIN
sudo opendkim-genkey -D /etc/opendkim/keys/$DOMAIN -d $DOMAIN -s mail
sudo chown -R opendkim:opendkim /etc/opendkim/keys
/etc/opendkim.conf (see references/opendkim.conf):
Socket inet:8891@localhost
KeyTable file:/etc/opendkim/KeyTable
SigningTable file:/etc/opendkim/SigningTable
/etc/opendkim/KeyTable:
mail._domainkey.domain.com domain.com:mail:/etc/opendkim/keys/domain.com/mail.private
/etc/opendkim/SigningTable:
*@domain.com mail._domainkey.domain.com
Step 6: SSL certificates
Temporary: Self-signed
sudo mkdir -p /etc/letsencrypt/live/mail.$DOMAIN
sudo openssl req -new -x509 -days 365 -nodes \
-subj "/CN=mail.$DOMAIN" \
-out /etc/dovecot/private/dovecot.pem \
-keyout /etc/dovecot/private/dovecot.key
sudo cp /etc/dovecot/private/dovecot.pem /etc/letsencrypt/live/mail.$DOMAIN/fullchain.pem
sudo cp /etc/dovecot/private/dovecot.key /etc/letsencrypt/live/mail.$DOMAIN/privkey.pem
Real: Let's Encrypt (after DNS resolves)
sudo certbot certonly --standalone -d mail.$DOMAIN --agree-tos --email admin@$DOMAIN
Step 7: DNS records
Required records (add at your DNS provider):
| Type | Host | Value | Priority |
|---|---|---|---|
| MX | @ | mail.domain.com | 10 |
| A | server-ip | — | |
| TXT | @ | v=spf1 mx ~all | — |
| TXT | mail._domainkey | (from /etc/opendkim/keys/domain.com/mail.txt) | — |
| TXT | _dmarc | v=DMARC1; p=none; rua=mailto:admin@domain.com | — |
Also request PTR/reverse DNS from your hosting provider pointing your IP to
mail.domain.com — critical for deliverability.
Step 8: Start and verify
sudo systemctl restart dovecot postfix opendkim
sudo doveadm auth test user@domain.com 'password' # Must say "succeeded"
echo "test" | sudo /usr/sbin/sendmail user@domain.com # Local delivery
sudo ss -tlnp | grep -E ':(25|110|143|465|587|993|995)'
Pitfalls
-
Postfix
mua_*warnings — the submission/smtps blocks in master.cf reference$mua_client_restrictionsetc. which are not defined by default. Replace them with concrete values or define them in main.cf. Otherwisepostfix checkproduces hundreds of warnings. -
OpenDKIM restart loop — OpenDKIM may fail to write its PID file to
/run/opendkim/due to permissions. This causes systemd to restart it repeatedly. The process still starts and binds port 8891; check withss -tlnp | grep 8891rather than relying on systemd status alone. -
Dovecot
ssl = yesline — on Ubuntu 22.04, the default10-ssl.confhasssl = yesalready uncommented. Verify before editing. -
Port 25 outbound — many cloud providers block outbound port 25 by default. Request unblocking from your provider for external delivery.
-
/etc/dovecot/userspermissions — must be640and owned byroot:dovecot. Plainchmod 600will cause auth failures. -
Maildir vs mbox — the default Dovecot config on Ubuntu uses mbox format (
mbox:~/mail:INBOX=/var/mail/%u). You MUST change it to Maildir for virtual mailbox compatibility.