Post

Install and Configure Mail Server on Ubuntu 22.04 with Postfix, Dovecot and Roundcube: Step-by-Step Complete Guide - Part 1

mailserver

Image by Arief JR

Setting up and managing your own mail server can have several advantages and disadvantages. Here are some reasons why you might choose to install and configure a self-managed mail server, as well as some potential drawbacks to consider:

Advantages of Self-Managed Mail Server

  1. Control and Customization:

You have full control over the server configuration, including security settings, email policies, and filtering rules. Customization allows you to tailor the server to meet specific needs or preferences that might not be possible with third-party services.

  1. Privacy and Security:

Hosting your own mail server ensures that your emails are stored and transmitted through your own infrastructure, which can be more secure than using a third-party service. You can implement advanced security measures such as encryption, spam filtering, and intrusion detection systems.

  1. Cost Savings:

For organizations with high email volumes, hosting your own server can be more cost-effective in the long run compared to paying for commercial email services. There are no recurring fees based on the number of users or the volume of emails.

  1. Data Sovereignty:

You maintain complete ownership and control over your data, which is especially important for organizations with strict data sovereignty requirements. Compliance with specific regulatory requirements regarding data storage and transmission can be more easily managed.

  1. Learning and Experience:

Setting up and managing a mail server can be a valuable learning experience for IT professionals, enhancing their skills in system administration, networking, and security.

Disadvantages of Self-Managed Mail Server

  1. Complexity and Maintenance:

Setting up a mail server can be complex and time-consuming, requiring a good understanding of networking, server management, and email protocols. Ongoing maintenance is necessary to ensure the server remains secure and functions properly, including software updates, backups, and troubleshooting.

  1. Security Risks:

Self-managed servers can be targets for attacks such as spam, phishing, and hacking. Proper security measures must be implemented and constantly monitored. Misconfigurations or neglected updates can lead to vulnerabilities.

  1. Reliability and Uptime:

Ensuring high availability and reliability of your mail server requires redundant infrastructure and careful monitoring, which can be challenging and costly. Downtime can lead to missed emails and disruptions in communication.

  1. Scalability:

Managing the growth of email traffic and storage needs can be challenging. Commercial services often provide scalable solutions that are easier to manage. Performance tuning and resource management become more critical as the user base grows.

  1. Support and Compliance:

Lack of professional support can be a drawback, as troubleshooting issues requires in-house expertise. Ensuring compliance with various email standards and regulations can be complex and requires continuous attention.

Update Domain Record

This section should first update your domain record, you can using cloudflare or namecheap as domain record like this example:

Ensure your records existing have the similar hostname of an email server

1
2
Name			Type	Value 		    TTL
example.com.	A	    xx.xxx.xxx.xxx	300

Because in this tutorial will using cloudflare as domain record, so let’s create DMARC and add SPF to at dns record:

  • DMARC in Cloudflare
    • Log in to the Cloudflare dashboard, and select your account and domain.
    • Go to Email > DMARC Management.
    • In Email record overview, select View records.
    • Use the available options to set up SPF, DKIM, and DMARC records. This page will also list any previous records you might already have in your account.

    you will see this record, for example:

    dmarc-cloudflare

  • SPF record:

On your cloudflare dashboard add record in spf, like this:

1
2
Name			Type	Value 		                                                        TTL
example.com.	TXT	    v=spf1 ip4:<your mail ip address> include:<your mail domain> -all	300

Configure Hostname

Configure your hostname for email server, the same hostname will be used by postfix and dovecot. Now open your terminal:

  • Check hostname
1
hostname

will give output

1
<current hostname>
  • Update hostname
1
sudo hostnamectl set-hostname change-hostname.example.com
  • And also update at the host file, make sure replace the ip address and hostname using your server ip address and domain.
1
sudo vim /etc/hosts

Update:

1
<your-ip-address> <your-hostname> <your-alias-hostname>

Save and exit with command ctrl + o -» Enter -» crtl + x

Install Postfix

This part is for installation postfix MTA (Mail Transfer Agent), execute this commands in this below to install postfix on ubuntu 22.04

1
2
3
4
5
6
7
8
9
sudo apt update -y
sudo apt install -y php-curl php-gd php-mbstring php-imap php-xml php-apcu

#Additional package
sudo apt install -y zip unzip rar unrar pyzor razor arj cabextract lzop nomarch p7zip-full \
rpm2cpio tnef unzip unrar-free zip bzip2 cpio file gzip pax

#Install postfix (include extension to mysql and policyd spf)
sudo apt install -y postfix postfix-mysql postfix-policyd-spf-python

When installing postfix, will show installer ask and choose the configuration below:

  • Figure 1, select to internet site

postfix-installer

Then press ok

postfix-confirm

Now type your hostname has setup earlier:

postfix-hostname

And installation postfix has completed.

Install Dovecot

Execute this command for install dovecot:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
install -y dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libexttextcat-2.0-0 libexttextcat-data
Suggested packages:
  dovecot-gssapi dovecot-ldap dovecot-lucene dovecot-managesieved dovecot-pgsql dovecot-sieve dovecot-solr dovecot-sqlite dovecot-submissiond ntp
The following NEW packages will be installed:
  dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-pop3d libexttextcat-2.0-0 libexttextcat-data
0 upgraded, 7 newly installed, 0 to remove and 0 not upgraded.
Need to get 3786 kB of archives.
After this operation, 12.2 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/main amd64 libexttextcat-data all 3.4.5-1build2 [179 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy/main amd64 libexttextcat-2.0-0 amd64 3.4.5-1build2 [13.7 kB]
Get:3 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 dovecot-core amd64 1:2.3.16+dfsg1-3ubuntu2.2 [3319 kB]
Get:4 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 dovecot-imapd amd64 1:2.3.16+dfsg1-3ubuntu2.2 [193 kB]
Get:5 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 dovecot-lmtpd amd64 1:2.3.16+dfsg1-3ubuntu2.2 [29.4 kB]
Get:6 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 dovecot-mysql amd64 1:2.3.16+dfsg1-3ubuntu2.2 [13.9 kB]
Get:7 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 dovecot-pop3d amd64 1:2.3.16+dfsg1-3ubuntu2.2 [37.7 kB]
Fetched 3786 kB in 2s (1804 kB/s)
Selecting previously unselected package libexttextcat-data.
(Reading database ... 95621 files and directories currently installed.)
Preparing to unpack .../0-libexttextcat-data_3.4.5-1build2_all.deb ...
Unpacking libexttextcat-data (3.4.5-1build2) ...
Selecting previously unselected package libexttextcat-2.0-0:amd64.
Preparing to unpack .../1-libexttextcat-2.0-0_3.4.5-1build2_amd64.deb ...
Unpacking libexttextcat-2.0-0:amd64 (3.4.5-1build2) ...
Selecting previously unselected package dovecot-core.
Preparing to unpack .../2-dovecot-core_1%3a2.3.16+dfsg1-3ubuntu2.2_amd64.deb ...
Unpacking dovecot-core (1:2.3.16+dfsg1-3ubuntu2.2) ...
Selecting previously unselected package dovecot-imapd.
Preparing to unpack .../3-dovecot-imapd_1%3a2.3.16+dfsg1-3ubuntu2.2_amd64.deb ...
Unpacking dovecot-imapd (1:2.3.16+dfsg1-3ubuntu2.2) ...
Selecting previously unselected package dovecot-lmtpd.
Preparing to unpack .../4-dovecot-lmtpd_1%3a2.3.16+dfsg1-3ubuntu2.2_amd64.deb ...
Unpacking dovecot-lmtpd (1:2.3.16+dfsg1-3ubuntu2.2) ...
Selecting previously unselected package dovecot-mysql.
Preparing to unpack .../5-dovecot-mysql_1%3a2.3.16+dfsg1-3ubuntu2.2_amd64.deb ...
Unpacking dovecot-mysql (1:2.3.16+dfsg1-3ubuntu2.2) ...
Selecting previously unselected package dovecot-pop3d.
Preparing to unpack .../6-dovecot-pop3d_1%3a2.3.16+dfsg1-3ubuntu2.2_amd64.deb ...
Unpacking dovecot-pop3d (1:2.3.16+dfsg1-3ubuntu2.2) ...
Setting up libexttextcat-data (3.4.5-1build2) ...
Setting up libexttextcat-2.0-0:amd64 (3.4.5-1build2) ...
Setting up dovecot-core (1:2.3.16+dfsg1-3ubuntu2.2) ...

Install MariaDB

If your server not installed mariadb, you should install first. Because the mail data like users, password will store to MariaDB. Execute this command:

1
sudo apt install -y mariadb-client mariadb-server

Install Postgrey, Clamav, Amavis and SpamAssassin

To secure the mail server need a several dependencies, execute this command:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Install Postgrey
sudo apt install -y postgrey

# Install Clam
sudo apt install -y clamav clamav-daemon

# Install Amavis
sudo apt install -y amavis 

# Install SpamAssassin
sudo apt install -y spamassassin 

# Install additional packages
sudo apt install -y libdbi-perl libdbd-mysql-perl

Install OpenDKIM

OpenDKIM is an open source implementation of the DKIM (Domain Keys Identified Mail) sender authentication system proposed by the E-mail Signing Technology Group (ESTG), now standardized by the IETF RFC6376. So that the other email servers can authenticate the emails sent from our server and confirm that the emails are not forged or altered and the emails are authorized by the domain owner, execute this command:

1
sudo apt install -y opendkim opendkim-tools

Configure Database - MariaDB

After installed mariadb, you should configure first. you can read in this article earlier here,

Configure Postfix

Now configure this postfix, follow this configurations below:

  • Backup config first:
1
2
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.orig
sudo cp /etc/postfix/master.cf /etc/postfix/master.cf.orig
  • Create virtualhost email directory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Mails Directory
sudo mkdir -p /<path to vmail>/vmail/

# Create mail group and user
sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /<path to vmail>/vmail

# Change mails directory owner
sudo chmod 770 /<path to vmail>/vmail
sudo chown -R vmail:vmail /<path to vmail>/vmail

# Check permissions
ls -ld /<path to vmail>/vmail

# Output
drwxrwx--- 2 vmail vmail 4096 Jul 1 21:30 /<path to vmail>/vmail

# Check UID
id -u vmail

# Output
5000

# Check GID
id -g vmail

# Output
5000
  • Create header and content checks
1
2
# Create Header Checks
sudo vim /etc/postfix/header_checks

put this file with this content:

1
2
3
4
5
6
7
# Content
/^Received:/ IGNORE
/^User-Agent:/ IGNORE
/^X-Mailer:/ IGNORE
/^X-Originating-IP:/ IGNORE
/^x-cr-[a-z]*:/ IGNORE
/^Thread-Index:/ IGNORE

save and exit, with vim editor to save and exist press esc + :wq

1
2
# MIME header checks
sudo vim /etc/postfix/mime_header_checks

fill this file in the below:

1
2
# Content
/name=[^>]*\.(bat|com|exe|dll)/ REJECT
1
2
3
4
# Body Checks
sudo vim /etc/postfix/body_checks

# Just add an empty line for now
1
2
3
4
# Client Checks
sudo vim /etc/postfix/client_checks

# Just add an empty line for now
1
2
3
4
# Sender Checks
sudo vim /etc/postfix/sender_checks

# Just add an empty line for now
  • jump first this section to database, because this email will using database. After configured, create database and user with this command:
1
2
3
4
5
6
7
8
9
10
11
MariaDB [(none)]> CREATE DATABASE <your-database-name> CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.001 sec)

MariaDB [(none)]> CREATE USER '<your-user>'@'localhost' IDENTIFIED WITH mysql_native_password BY '<your-password>';
Query OK, 0 rows affected (0.002 sec)

MariaDB [(none)]> GRANT ALL PRIVILEGES ON <your-database-name>.* TO '<your-user>'@'localhost';
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)

in above command use authentication plugin mysql_native_password, because sha256_password and caching_sha2_password does not currently support with mariadb. Here this article

  • Create and configure virtual domain
1
2
# Virtual domains
sudo vim /etc/postfix/mysql_virtual_mailbox_domains.cf

fill with this config:

1
2
3
4
5
6
# Content
hosts = 127.0.0.1
user = <your-user-mail>
password = <your-password>
dbname = <your-database>
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = 0 and active = 1
1
2
# Email addresses
sudo vim /etc/postfix/mysql_virtual_mailbox_maps.cf

fill with this config:

1
2
3
4
5
6
# Content
hosts = 127.0.0.1
user = <your-user-mail>
password = <your-password>
dbname = <your-database>
query = SELECT goto FROM alias WHERE address='%s' AND active = 1
1
2
# Aliases
sudo vim /etc/postfix/mysql_virtual_alias_maps.cf

fill with this config:

1
2
3
4
5
6
# Content
hosts = 127.0.0.1
user = <your-user-mail>
password = <your-password>
dbname = <your-database>
query = SELECT goto FROM alias WHERE address='%s' AND active = 1
1
2
# Relays
sudo vim /etc/postfix/mysql_relay_domains.cf

fill with this config:

1
2
3
4
5
6
# Content
hosts = 127.0.0.1
user = <your-user-mail>
password = <your-password>
dbname = <your-database>
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = 1
  • Configure postfix main, execute this command:
1
sudo vim /etc/postfix/main.cf

Insert this config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
append_dot_mydomain = no
#delay_warning_time = 4h
readme_directory = no
compatibility_level = 2

# SASL parameters
# -----------------------
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_local_domain =
smtpd_sasl_authenticated_header = yes

# TLS parameters
# -----------------------
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_CAfile=/etc/letsencrypt/live/mail.example.com/chain.pem
smtpd_use_tls=yes
smtpd_tls_security_level = may
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_auth_only = yes
smtpd_sasl_tls_security_options = noanonymous
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_ciphers = high
#smtp_tls_CApath=/etc/ssl/certs
smtp_use_tls=yes
smtp_tls_security_level = may
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_note_starttls_offer = yes
tls_random_source = dev:/dev/urandom

# SMTPD parameters
# -----------------------
unknown_local_recipient_reject_code = 450
maximal_queue_lifetime = 7d
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
smtp_helo_timeout = 60s
smtpd_recipient_limit = 25
smtpd_error_sleep_time = 1s
smtpd_soft_error_limit = 3
smtpd_hard_error_limit = 12
smtpd_delay_reject = yes
disable_vrfy_command = yes

# HELO Restrictions - Reject - HELO/EHLO information
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit

# Sender Restrictions - Reject - MAIL FROM
smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, check_sender_access hash:/etc/postfix/sender_checks, warn_if_reject reject_non_fqdn_sender, reject_authenticated_sender_login_mismatch, reject_unknown_sender_domain, reject_unauth_pipelining, permit

# Client Restrictions - Connecting server - Reject client host
#smtpd_client_restrictions = reject_rbl_client relays.ordb.org, reject_rbl_client blackholes.easynet.nl, reject_rbl_client cbl.abuseat.org, reject_rbl_client proxies.blackholes.wirehub.net, reject_rbl_client bl.spamcop.net, reject_rbl_client sbl.spamhaus.org, reject_rbl_client opm.blitzed.org, reject_rbl_client dnsbl.njabl.org, reject_rbl_client list.dsbl.org, reject_rbl_client multihop.dsbl.org, permit

smtpd_client_restrictions = check_client_access hash:/etc/postfix/client_checks, reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl, reject_rbl_client dnsbl.njabl.org

# Recipient Restrictions - Reject - RCPT TO
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_hostname, check_policy_service unix:private/policy-spf, check_policy_service inet:127.0.0.1:10023, permit

# Reject - DATA
smtpd_data_restrictions = reject_unauth_pipelining

# Relay Restrictions - Reject - RCPT TO
smtpd_relay_restrictions = permit_mynetworks, reject_unauth_pipelining, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service unix:private/policy-spf, check_policy_service inet:127.0.0.1:10023, permit

# General parameters
# -----------------------
myhostname = mail.example.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydomain = mail.example.com
myorigin = /etc/mailname
#mydestination = $myhostname, mail.example.com, localhost.example.com, , localhost
mydestination = localhost.$mydomain, , localhost
relayhost = 
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all
mynetworks_style = host
message_size_limit = 10240000

# Dovecot
# -----------------------
virtual_transport = lmtp:unix:private/dovecot-lmtp

# Virtual Mailbox
# -----------------------
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_mailbox_base = /<path to vmail>/vmail
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_mailbox_domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf
relay_domains = mysql:/etc/postfix/mysql_relay_domains.cf

queue_directory = /var/spool/postfix

# Header Checks
# -----------------------
header_checks = regexp:/etc/postfix/header_checks
mime_header_checks = regexp:/etc/postfix/mime_header_checks

# x-original-to
# -----------------------
enable_original_recipient = no

# Content Checks
# -----------------------
body_checks = regexp:/etc/postfix/body_checks

# Amavis
# -----------------------
content_filter = smtp-amavis:[127.0.0.1]:10024
#content_filter = amavis:[127.0.0.1]:10024
receive_override_options = no_address_mappings

# DKIM
# -----------------------
milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
  • Configure postfix master
1
sudo vim /etc/postfix/master.cf

Insert this config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================
smtp      inet  n       -       y       -       -       smtpd
#smtp      inet  n       -       y       -       1       postscreen
#smtpd     pass  -       -       y       -       -       smtpd
#dnsblog   unix  -       -       y       -       0       dnsblog
#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=
#  -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

# SMTP with TLS on port 587
submission inet n - - - - smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_tls_auth_only=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
  -o smtpd_sasl_tls_security_options=noanonymous
  -o milter_macro_daemon_name=ORIGINATING

# SMTP over SSL on port 465
smtps inet n - - - - smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
  -o smtpd_sasl_security_options=noanonymous,noplaintext
  -o smtpd_sasl_tls_security_options=noanonymous
  -o milter_macro_daemon_name=ORIGINATING

#628       inet  n       -       y       -       -       qmqpd
#pickup    unix  n       -       y       60      1       pickup
pickup fifo n - - 60 1 pickup
  -o content_filter=
  -o receive_override_options=no_header_body_checks
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
#qmgr     unix  n       -       n       300     1       oqmgr
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# ====================================================================
#
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
#
# Specify in cyrus.conf:
#   lmtp    cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
#
# Specify in main.cf one or more of the following:
#  mailbox_transport = lmtp:inet:localhost
#  virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus     unix  -       n       n       -       -       pipe
#  user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix  -       n       n       -       -       pipe
#  flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix	-	n	n	-	2	pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}

# Amavis
smtp-amavis unix - - - - 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 - - - - 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,no_milters

# Dovecot
dovecot unix - n n - - pipe
	flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(recipient)

# SPF
policy-spf  unix  -       n       n       -       -       spawn
     user=nobody argv=/usr/bin/policyd-spf

# SpamAssassin
spamassassin unix -     n       n       -       -       pipe
    flags=DROhu user=vmail:vmail argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Configure Dovecot

This section provides the configurations specific to Dovecot. Change the ownership of the dovecot installation as shown below.

1
2
sudo chown -R vmail:dovecot /etc/dovecot
sudo chmod -R o-rwx /etc/dovecot

Now backup the configuration files as shown below.

1
2
3
4
5
6
7
8
9
10
11
sudo cp /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig
sudo cp /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext.orig
sudo cp /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf.orig
sudo cp /etc/dovecot/conf.d/10-mail.conf /etc/dovecot/conf.d/10-mail.conf.orig
sudo cp /etc/dovecot/conf.d/10-master.conf /etc/dovecot/conf.d/10-master.conf.orig
sudo cp /etc/dovecot/conf.d/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf.orig
sudo cp /etc/dovecot/conf.d/15-lda.conf /etc/dovecot/conf.d/15-lda.conf.orig
sudo cp /etc/dovecot/conf.d/auth-sql.conf.ext /etc/dovecot/conf.d/auth-sql.conf.orig
sudo cp /etc/dovecot/conf.d/15-mailboxes.conf /etc/dovecot/conf.d/15-mailboxes.conf.orig
sudo cp /etc/dovecot/conf.d/20-lmtp.conf /etc/dovecot/conf.d/20-lmtp.conf.orig
sudo cp /etc/dovecot/conf.d/90-plugin.conf /etc/dovecot/conf.d/90-plugin.conf.orig

Now we will configure the files as listed above.

Main Configuration - Update the main configuration file of Dovecot as shown below.

1
2
# Main Configuration
sudo vim /etc/dovecot/dovecot.conf
1
2
3
4
5
6
7
8
# Updates
-----
# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap pop3 lmtp
-----

# Save and exit the editor

Mail Configuration - Update the mail configuration and specify the mails directory.

1
2
# Mail Configuration
sudo vim /etc/dovecot/conf.d/10-mail.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Updates
-----
#mail_location = mbox:~/mail:INBOX=/var/mail/%u
mail_location = maildir:/<path to vmail>/vmail/%d/%n
-----
mail_uid = vmail
mail_gid = vmail
-----
#mail_privileged_group = mail
mail_privileged_group = vmail
-----
first_valid_uid = 5000
last_valid_uid = 5000
-----

# Save and exit the editor

Auth Configuration - Update the auth configuration.

1
2
# Auth Configuration
sudo vim /etc/dovecot/conf.d/10-auth.conf
1
2
3
4
5
6
7
8
9
10
11
# Updates
-----
disable_plaintext_auth = yes
auth_mechanisms = plain login
-----
#!include auth-system.conf.ext
!include auth-sql.conf.ext
#!include auth-ldap.conf.ext
-----

# Save and exit the editor

SQL Auth Configuration - Update the auth configuration.

1
2
# Mail Configuration
sudo vim /etc/dovecot/conf.d/auth-sql.conf.ext
1
2
3
4
5
6
7
8
9
10
11
12
13
# Updates
-----
#userdb {
#  driver = sql
#  args = /etc/dovecot/dovecot-sql.conf.ext
#}
-----
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/<path to vmail>/vmail/%d/%n
}

# Save and exit the editor

DB Configuration - Update the database configuration.

1
2
# Mail Configuration
sudo vim /etc/dovecot/dovecot-sql.conf.ext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Updates
-----
driver = mysql
-----
connect = host=localhost dbname=mail user=mail password=dbpassword
-----
default_pass_scheme = SHA512-CRYPT
-----
password_query = \
SELECT username as user, password, '/<path to vmail>/vmail/%d/%n' as userdb_home, \
'maildir:/<path to vmail>/vmail/%d/%n' as userdb_mail, 5000 as userdb_uid, 5000 as userdb_gid \
FROM mailbox WHERE username = '%u' AND active = '1'
-----

# Save and exit the editor

Master Configuration - Update the master configuration.

1
2
# Master Configuration
sudo vim /etc/dovecot/conf.d/10-master.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# Updates
-----
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 submission-login {
  inet_listener submission {
    port = 587
  }
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
-----
service auth {
-----
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
    group = vmail
  }

  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }

  # Auth process is run as this user.
  user = dovecot
-----
service auth-worker {
  # Auth worker process is run as root by default, so that it can access
  # /etc/shadow. If this isn't necessary, the user should be changed to
  # $default_internal_user.
  user = vmail
}
-----

# Save and exit the editor

SSL Configuration - Update the SSL configuration.

1
2
# SSL Configuration
sudo vim /etc/dovecot/conf.d/10-ssl.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Updates
-----
ssl = yes
-----
#ssl_cert = </etc/dovecot/private/dovecot.pem
#ssl_key = </etc/dovecot/private/dovecot.key
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
-----
ssl_ca = </etc/letsencrypt/live/mail.example.com/chain.pem
-----
ssl_min_protocol = TLSv1
-----
# Refer - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
ssl_cipher_list = ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM
-----
ssl_prefer_server_ciphers = yes
-----

# Save and exit the editor

LDA Configuration - Update the LDA configuration.

1
2
# LDA Configuration
sudo vim /etc/dovecot/conf.d/15-lda.conf
1
2
3
4
5
6
# Updates
-----
postmaster_address = postmaster@example.com
-----

# Save and exit the editor

Will continue to part 2 ……

This post is licensed under CC BY 4.0 by the author.