UPDATE: I will not be answering questions as this guide is outdated and just copied and pasted into a single page with improved order (not redoing steps or editing the same file over and over in different steps).
Please check out the original article which is being updated frequently:
LinuxBabe - Build Your Own Email Server on Ubuntu: Basic Postfix Setup
Steps were re-written from below links for faster setup.
This guide assumes you are using Ubuntu 18 and Nginx.
Part 1: Build Your Own Email Server on Ubuntu: Basic Postfix Setup - LinuxBabe
Part 2: Install Dovecot IMAP server on Ubuntu and Enable TLS Encryption
Part 3: How to Set up SPF and DKIM with Postfix on Ubuntu Server
Part 4: Creating DMARC Record to Protect Your Domain Name From Email Spoofing
Check hostname:
$ hostname -fChange hostname:
$ hostnamectl set-hostname example.com
$ nano /etc/hostname # change to example.comChange hosts:
$ nano /etc/hosts127.0.1.1 example.com example
127.0.0.1 localhost
127.0.0.1 example.com
Check PTR record:
$ dig -x example.com +shortCreate user to send mails from:
$ adduser noreply # can be hello, info, sales etcOpen SMTP ports on firewall:
$ ufw allow smtpInstall mailutils, Postfix, Dovecot and Open DKIM:
$ apt-get update
$ apt-get install mailutils -y
$ apt-get install postfix postfix-policyd-spf-python -y
$ apt-get install dovecot-core dovecot-imapd dovecot-lmtpd -y
$ apt-get install opendkim opendkim-tools -y
$ apt autoremoveEdit Postfix config:
$ nano /etc/postfix/main.cfAdd mydomain and update myhostname & mydestination:
...
mydomain = example.com
myhostname = mail.example.com
...
mydestination = $myhostname, $mydomain, localhost.localdomain, , localhost
...
Add the following lines at the end of the file:
mailbox_transport = lmtp:unix:private/dovecot-lmtp
smtputf8_enable = no
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
Save and close, then restart Postfix:
$ systemctl restart postfixCreate email aliases:
$ nano /etc/aliases# See man 5 aliases for format
postmaster: root
root: noreply # <-- your mail username
Rebuild aliases:
$ newaliasesOpen IMAP ports on firewall
$ ufw allow 587/tcp
$ ufw allow 465/tcp
$ ufw allow 143/tcp
$ ufw allow 993/tcpInstall Let’s Encrypt client (certbot):
$ apt install software-properties-common -y
$ add-apt-repository ppa:certbot/certbot
$ apt update
$ apt install certbot python3-certbot-nginx -yCreate virtual host for mail.example.com:
$ mkdir /var/www/mail
$ touch /etc/nginx/sites-available/mail
$ ln -s /etc/nginx/sites-available/mail /etc/nginx/sites-enabled/mail
$ nano /etc/nginx/sites-enabled/mailserver {
listen 80;
server_name mail.example.com;
root /var/www/mail;
location ~ /.well-known/acme-challenge {
allow all;
}
}
$ mkdir /var/www/mail
$ chown www-data:www-data /var/www/mail -R
# replace www-data with your nginx user if it is differentTest then restart nginx:
$ nginx -t
# or
$ service nginx configtest
# if successful, restart
$ service nginx restart # or reloadObtain Let’s Encrypt SSL/TLS certificate:
$ certbot --nginx --agree-tos --redirect --hsts --staple-ocsp -d mail.example.comConfigure Postfix
$ nano /etc/postfix/master.cfDefault code example (commented out):
...
#tlsproxy unix - - y - 0 tlsproxy
#submission inet n - y - - smtpd
# -o syslog_name=postfix/submission
# -o smtpd_tls_security_level=encrypt
...
UNcomment and ADD the following, so that it looks like this:
...
#tlsproxy unix - - y - 0 tlsproxy
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=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
-o smtpd_tls_wrappermode=no
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
#smtps inet n - y - - smtpd
...
Microsoft outlook only supports submission over port 465. If you are going to use Microsoft outlook mail client, then you also need to enable submission service on port 465 by adding the following lines in the file:
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=permit_mynetworks,permit_sasl_authenticated,reject
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
Add this at the end of the file:
policyd-spf unix - n n - 0 spawn
user=policyd-spf argv=/usr/bin/policyd-spf
Save and close, then edit the main postfix config:
$ nano /etc/postfix/main.cfChange TLS parameters from:
# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
To the following:
# TLS parameters
smtpd_tls_cert_file=/etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/example.com/privkey.pem
smtpd_use_tls=yes
smtpd_tls_security_level = encrypt
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_use_tls=yes
smtp_tls_security_level = may
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
NOTE: Remember to change example.com to your folder name.
To check that folder, use: $ ls -la /etc/letsencrypt/live
Restart Postfix and verify success:
$ service postfix restart
$ netstat -lnptYou should see these:
tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN 23511/master
tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 23511/master
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 23511/master
Configure Dovecot:
$ nano /etc/dovecot/dovecot.confAdd the following line, then save and close:
protocols = imap lmtp
Add dovecot to the mail group:
$ adduser dovecot mailEdit the auth config file:
$ nano /etc/dovecot/conf.d/10-auth.confUncomment the following line:
disable_plaintext_auth = yes
Change username format to use full email address:
auth_username_format = %n
Support older email clients:
auth_mechanisms = plain login
Save and close, then edit the SSL/TLS config:
$ nano /etc/dovecot/conf.d/10-ssl.confChange yes to required
ssl = required
Change SSL paths from:
ssl_cert = </etc/dovecot/private/dovecot.pem
ssl_key = </etc/dovecot/private/dovecot.key
To the following:
ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/example.com/privkey.pem
NOTE: Remember to change example.com to your folder name.
To check that folder, use: $ ls -la /etc/letsencrypt/live
Save and close, then edit the master config:
$ nano /etc/dovecot/conf.d/10-master.confChange service lmtp section to the following:
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
Change service auth section to the following:
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
Save and close, then edit the mailbox config:
$ nano /etc/dovecot/conf.d/15-mailboxes.confTo auto-create folders, add the following into every mailbox section:
auto = create
Example:
mailbox Trash {
auto = create
special_use = \Trash
}
Restart Postfix and Dovecot:
$ systemctl restart postfix dovecotCreate a TXT record on your DNS for @:
TXT @ 3600 "v=spf1 a mx ip4:<ip4_server_ip> ip6:<ip6_server_ip> ~all"
Note: ip6 is optional.
Test TXT DNS records:
$ dig example.com txtAdd Postfix user to opendkim group:
$ gpasswd -a postfix opendkimEdit OpenDKIM config:
$ nano /etc/opendkim.confUncomment the #Commonly-used options; part and paste in this block below it:
# Commonly-used options; the commented-out versions show the defaults.
Canonicalization simple
Mode sv
SubDomains no
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
Add the following lines at the end of this file:
# Map domains in From addresses to keys used to sign messages
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
# Hosts to ignore when verifying signatures
ExternalIgnoreList /etc/opendkim/trusted.hosts
# A set of internal hosts whose mail should be signed
InternalHosts /etc/opendkim/trusted.hosts
Save and close, then create a directory structure for OpenDKIM:
$ mkdir /etc/opendkim
$ mkdir /etc/opendkim/keys
$ chown -R opendkim:opendkim /etc/opendkim
$ chmod go-rw /etc/opendkim/keys
$ nano /etc/opendkim/signing.tableAdd this line:
*@example.com default._domainkey.example.com
Save and close, then create the key table:
$ nano /etc/opendkim/key.tablePaste the following:
default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com/default.private
Save and close, then create the trusted hosts file:
$ nano /etc/opendkim/trusted.hostsAdd the following, then save and close:
127.0.0.1
localhost
*.example.com
Create a folder for your domain:
$ mkdir /etc/opendkim/keys/example.comGenerate OpenDKIM keys:
$ sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s default -vMake OpenDKIM the owner of the key:
$ chown opendkim:opendkim /etc/opendkim/keys/example.com/default.privateDisplay public key:
$ cat /etc/opendkim/keys/your-domain.com/default.txtNote: You have to remove the concatenation and make it a single string, example:
"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkDG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr1dZwz3zuCy+5Fym2JjX5/dqtAlo6ejnn3bzr25xI2IYfNxBrVCqQ8N6qa0DKjlQ0jyskNQl/luHA97X3Fh6hbQEiIuPqQm1nNNbXIfZVTQDHzW1F1Bu6jMvu4SSS27jgtveSnHG4PK8jpYJePkead8BV9mg8jVNMYVM4kA4sN+Ux5pvFHUb5V+AUqx64bpR86sPOw6sX1ES/vOkCVvgx15qEYaGAPaZBXwkyJ/2qi1fNmsFTUOn+0rmkDeizCqVcDDdttdpPdujNwKpONuB+6x0MIvIcjbWl9vWDZZgp7kvKiBVXuGi/IBOkZtFdK/2HkvUw7IVZ5lqCji9ZIGllwIDAQAB"
Create a new TXT DNS record with the above string:
TXT default._domainkey 3600 "v=DKIM1; h=sha256; k=rsa; p=<key>"
Test your key:
$ opendkim-testkey -d example.com -s default -vvvCreate a directory to hold the OpenDKIM socket file:
$ mkdir /var/spool/postfix/opendkim
$ chown opendkim:postfix /var/spool/postfix/opendkim
$ nano /etc/opendkim.confReplace:
Socket local:/var/run/opendkim/opendkim.sock
With the following:
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Restart services:
$ systemctl restart opendkim postfix dovecotSend test mail:
$ echo 'Testing mail server' | mail [email protected] -s 'Test subject' -r noreply
First of all, thank you for such a useful document.
Can you include Roundcube upload in this document?