1
---
Postfix Mail Server Setup on Ubuntu 20.04
Outline of Packages and Configuration Steps
2 – Build out the LAMP Web Server
3 – Configure PHP
5 – Install and Configure Memcached
6 – Install the mail server Packages
7 – Creating a MySQL Database for the Mail Server
8.1 – Installing Postfix Admin
8.2 – Configuring Postfix Admin
9 – Adding User Accounts (mailboxes) to Postfix Admin
10 – Create a system user to handle Virtual Mail Directories
11 – Configuring Dovecot
12 – Configuring Spam and Anti-Virus Filters
13 – Configuring Postfix
14 – Reverse DNS Lookup
15 – Install RoundCube Webmail
Prerequisites
– Fully updated Ubuntu 20.04 Server, if you do not have an Ubuntu server running on a server like those on Atlantic.net’s Linux VPS hosting.
– Access to the domain name for which you will set up mail (we will be using “email.linuxbuz.com” in the examples in this article).
.
1 – Basic Server Preparation
The base installation of Ubuntu comes with a limited set of packages, so the first thing we want to do is install the tools we’ll be using to complete all tasks.
First, make sure that you are logged in as the root user account.
sudo su -
Now, let’s install the basic tools so that we can download files, and edit configuration files easily.
apt-get install wget nano ssl-cert
wget: package for retrieving files using HTTP, HTTPS and FTP, the most widely-used Internet protocols.
nano: command line text editor with easy to use controls.
ssl-cert: package that enables the ability to create SSL certificates.
Next, we are going to update the hostname and domain name of the server so that when you send email it will match the reverse pointer DNS record that we set up with your hosting provider. We will also update the /etc/hostname file. Make sure to replace example with your real hostname and domain name.
hostnamectl set-hostname email.linuxbuz.com
Now we are going to manually edit the /etc/hosts configuration file so that it matches the name we just entered.
nano /etc/hosts
Edit the first line and add your FQDN (fully qualified domain name) just after the 127.0.0.1 IP address.
127.0.0.1 email.linuxbuz.com localhost
We are now going to update the default SSL certificate on the server so that it matches our new hostname. If you purchased an SSL certificate for your mail server, you can skip this step.
make-ssl-cert generate-default-snakeoil --force-overwrite
This command tells the server to regenerate the default system SSL certificate and forces it to overwrite the original CRT and KEY files.
We have now completed the Basic Server Preparation and can move on to installing our web server services.
2 – Build out the LAMP Web Server
During this step, we are going to install the “LAMP” packages. LAMP stands for Linux, Apache, MySQL, and PHP. These packages combined will enable your server to provide dynamic web services with MySQL connectivity.
First, let’s install the packages. This is called a task package installation.
apt-get install lamp-server^
To see a list of the packages that are included in this group install, you can execute the following:
tasksel --task-packages lamp-server
After all the packages are installed, we will be ready to install some additional PHP modules. These additional modules will enable your server to support APC User Cache for PHP 5, memcached, cURL, an XML parser, and GD image processing.
apt-get install php-apcu php-memcache php-curl php-mbstring php-gd php-xml php-imap php-xmlrpc libdbi-perl libdbd-mysql-perl -y
Next, you will need to set the MySQL root password and secure the MySQL installation. You can do it with the following command:
mysql_secure_installation
Answer all the questions as shown below:
New password: Re-enter new password: Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : Y Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y
Next, log in to MySQL and change the password policy to low:
mysql -u root -p SET GLOBAL validate_password.policy = 0; FLUSH PRIVILEGES; EXIT;
3 – Configure PHP
We are now going to update the configuration of PHP. The default configuration is usually sufficient for most systems; however, we want to make sure that PHP does not expose information to potential attackers. We are going to edit the file /etc/php/7.4/apache2/php.ini.
nano /etc/php/7.4/apache2/php.ini
Locate the variable expose_php and update the value from On to Off. With nano, you can search by pressing CTRL-W and then enter your search word.
367 ;;;;;;;;;;;;;;;;; 368 ; Miscellaneous ; 369 ;;;;;;;;;;;;;;;;; 370 371 ; Decides whether PHP may expose the fact that it is installed on the server 372 ; (e.g. by adding its signature to the Web server header). It is no security 373 ; threat in any way, but it makes it possible to determine whether you use PHP 374 ; on your server or not. 375 ; http://php.net/expose-php 376 expose_php = Off 377
4 – Configure Apache2
We are now ready to move on to customizing the configuration of the Apache web services. The end result for Apache is that it will serve a single website with a couple of running web applications: Webmail (RoundCube) and Postfix Admin. All traffic will be directed to HTTPS (secured) web services.
First, we are going to minimize the information that Apache exposes to the public. Using nano, we are going to edit the configuration file /etc/apache2/conf-available/security.conf.
nano /etc/apache2/conf-available/security.conf
Search for the configuration variable ServerTokens and set the value from OS to Prod.
# ServerTokens # This directive configures what you return as the Server HTTP response # Header. The default is 'Full' which sends information about the OS-Type # and compiled in modules. # Set to one of: Full | OS | Minimal | Minor | Major | Prod # where Full conveys the most information, and Prod the least. #ServerTokens Minimal ServerTokens Prod #ServerTokens Full
Now search for the configuration variable ServerSignature and set the value from On to Off.
# Optionally add a line containing the server version and virtual host # name to server-generated pages (internal error documents, FTP directory # listings, mod_status and mod_info output etc., but not CGI generated # documents or custom error documents). # Set to "EMail" to also include a mailto: link to the ServerAdmin. # Set to one of: On | Off | EMail ServerSignature Off #ServerSignature On
You can now save and exit this configuration file.
We are now going to enable the additional modules rewrite and ssl in Apache so that we can redirect default HTTP traffic to the HTTPS port as well as support SSL certificates within Apache.
a2enmod rewrite ssl a2ensite default-ssl
We are now moving on to customize the website configuration. These files are located in the directory /etc/apache2/sites-available. We are going to update the existing default configuration files to support SSL services.
First, edit the configuration file 000-default.conf. You can replace the existing configuration with the below, just replace the ServerName variable with your hostname.
nano /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. ServerName email.linuxbuz.com DocumentRoot /var/www/html <Directory "/var/www/html"> Options FollowSymLinks AllowOverride All </Directory> # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf </VirtualHost>
You can now save and exit this configuration file.
If you have not purchased your own SSL certificate, the system default SSL configuration file default-ssl.conf will work for our needs. However, if you have purchased a custom SSL certificate, you will need to edit the configuration file and update the variables SSLCertificateFile, SSLCertificateKeyFile and SSLCertificateChainFile to point to the location where you have saved your certificate and key files (consult your certificate authority or vendor for additional configuration assistance).
We are now going to create an .htaccess configuration file that will force visitors to your web server to use the HTTPS (SSL) protocol.
nano /var/www/html/.htaccess
Copy and paste the following variables into the .htaccess configuration.
RewriteEngine On RewriteCond %{SERVER_PORT} 80 RewriteRule ^(.*) https://%{HTTP_HOST}/$1 [L]
These configuration variables tell Apache to enable the mod_rewrite engine, and then to redirect visitors on HTTP (port 80) to the HTTPS (port 443) URL.
5 – Install and Configure Memcached
Memcached is a high-performance, distributed memory object caching system. This package will help speed up dynamic web applications, such as RoundCube and Postfix Webadmin.
First, let’s install the package using apt-get.
apt-get install memcached
For smaller systems, the default configuration is usually sufficient. It locks down access to the localhost and provides sufficient memory allocation values. However, if you are building a larger server that may get heavy usage, you will most likely want to change the memory allocation values to be higher than the default of 64M.
The memcached configuration files is located at /etc/memcached.conf.
6 – Install the Mailserver Packages
We are now ready to install the mail server packages. Again, these are located in a tasksel package group.
apt-get install mail-server^
To see a list of the packages that are included in this group install, you can execute the following:
tasksel --task-packages mail-server
During the package installation, Postfix will ask you a series of questions:
Installation configuration type —
You will want to select “Internet Site” as the configuration type.
Hostname of the mail server —
Make sure to enter the same hostname (FQDN) that you used in Step #1
Create a self-signed SSL Certificate —
Select the ‘Yes’ option
Setup the SSL Certificate Common Name —
Enter the same hostname (FQDN) that you used in Step #1
We are now going to install the remainder of the packages that are needed for the mail server to support MySQL-based users as well as the Spam and AntiVirus detection packages. (Note: these packages could be installed via a single apt-get install command, with each package name separated by a space, but they are presented here as separate commands for ease of reading.)
apt-get install postfix-mysql dovecot-mysql dovecot-imapd postgrey apt-get install amavis clamav clamav-daemon spamassassin apt-get install php-imap
This next set of optional packages extends the abilities of the anti-spam and antivirus detection packages by allowing greater inspection of attached files that come into your mail server.
apt-get install libnet-dns-perl pyzor razor apt-get install arj bzip2 cabextract cpio file gzip nomarch pax unzip zip
Now, let’s restart the Apache2 services so that it will see the new modules we have provided it.
systemctl restart apache2
7 – Creating a MySQL Database for the Email Server
We are now ready to create the database for our user accounts and other mail server functions.
To begin, we need to log into the MySQL database service as the root user. You will need that password that you first entered in Step #2.
mysql -u root -p
You will now see a different command line prompt (mysql>). This is the MySQL CLI console where you can manage your MySQL server databases and tables.
First, we are going to create a new database named “mail”, and then we will create a system user account with full permissions to this new database. Make sure to replace the <secure password> variable with another *new* secure password for this account. Do not use the same password that you used for the root user account.
CREATE DATABASE mail; CREATE USER 'mail'@'localhost' IDENTIFIED BY 'mypassword'; GRANT ALL PRIVILEGES ON mail.* TO 'mail'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES; EXIT;
We have now setup the database that will be used by your mail server services.
8.1 – Installing Postfix Admin
Postfix Admin is a web-based management tool created for Postfix. It is a PHP-based application that handles Postfix-style virtual domains and users that are stored in MySQL or PostgreSQL.
First, we need to download the latest release of the application. This example will download version 2.92–always check the version on the provider’s website to make sure you are getting the latest release.
We are now going to extract the application and copy it to the HTML directory /var/www/html/postfixadmin on our server.
tar -xvf PostfixAdmin%203.3.1.tar.gz mv postfixadmin-postfixadmin-cc23eba /var/www/html/postfixadmin
Now we need to create a template directory and update the permissions of this new folder so that the www-data user account has access to it.
mkdir /var/www/html/postfixadmin/templates_c chown -R www-data:www-data /var/www/html/postfixadmin
8.2 – Configuring Postfix Admin
We now have some configurations to update in the Postfix Admin files. First, we will modify the config.inc.php file so that it knows how to communicate with the database that we just created in Step #7.
nano /var/www/html/postfixadmin/config.inc.php
Search for the variable 'configured' and reset the value from false to true.
$CONF['configured'] = true;
Now search for the variable 'database_' and replace the values for your MySQL server configuration. Make sure to replace the variable mypassword with the password for the database user “mail” that you entered in Step #7.
$CONF['database_type'] = 'mysqli'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'mail'; $CONF['database_password'] = 'mypassword'; $CONF['database_name'] = 'mail';
Now search for the variable 'admin_email' and replace the value with the email address you will setup for your administrator email account.
$CONF['admin_email'] = 'admin@linuxbuz.com';
Now search for the variable 'domain_path' and replace the value from ‘YES‘ to ‘NO‘.
$CONF['domain_path'] = 'NO';
Now search for the variable 'domain_in_mailbox' and replace the value from ‘NO‘ to ‘YES‘.
$CONF['domain_in_mailbox'] = 'YES';
These last configuration variables do not define the path to where the actual user mailbox data will be stored on the server. These will be defined later during the Dovecot configuration steps.
You are now ready to save the configuration file, but do not exit yet!
We are now going to open a web browser enter the URL of your mail server, pointing directly to the setup.php configuration page. Make sure to replace mail.example.tld with your real server hostname.
https://email.linuxbuz.com/postfixadmin/public/setup.php
When you access the URL, the script will automatically check the server and confirm that all the prerequisite modules are installed and working.
Postfix Admin setup checker output
Once the checks are completed, you will be prompted to enter a setup password. This password is used to create master admin accounts for the Postfix Admin web interface.
Enter a secure password and press the “Generate Password Hash” button.
Postfix Admin generate password hash
Postfix Admin example password hash
Do NOT close the web browser yet! We are coming back here in a few minutes.
After generating the password hash, we will then need to update the config.inc.php file again with this password. Search for the variable 'setup_password' and replace the value with the one generated from the script.
// In order to setup Postfixadmin, you MUST specify a hashed password here. // To create the hash, visit setup.php in a browser and type a password into the field, // on submission it will be echoed out to you as a hashed value. $CONF['setup_password'] = '<enter your hashed password here>';
You can now save and exit the configuration file.
We are now ready to return to the web browser and generate the “super admin” account for the Postfix Admin portal.
When you clicked the ‘Generate Password Hash’ button, the form fields changed to look like the example below. You can now fill out the form to generate a super admin account.
Creating a superadmin account with Postfix Admin
You can also create an admin user with the following command:
bash /var/www/html/postfixadmin/scripts/postfixadmin-cli admin add superadmin@linuxbuz.com --superadmin 1 --active 1 --password password@123 --password2 password@123
You should get the following output:
Welcome to Postfixadmin-CLI v0.3 --------------------------------------------------------------- The admin superadmin@linuxbuz.com has been added! ---------------------------------------------------------------
9 – Adding User Accounts (mailboxes) to Postfix Admin
We are now ready to create a virtual user account on our mail server. To do this, we will return to the Postfix Admin URL in our web browser and enter the URL of your mail server. Make sure to replace mail.example.tld with your real server hostname.
https://email.linuxbuz.com/postfixadmin/public
You will now be able to log in to the Postfix Admin portal where you can manage virtual domains and virtual user accounts. Enter the super admin username and password that you created above during the Postfix Admin configuration, and then press the “Login” button.
Admin login for Postfix Admin
Once you are logged in to the Postfix Admin portal, you will see a menu at the top of the page.
The menu options provide the ability to manage your Postfix mail server virtual domains and users and to view log files.
Postfix Admin menu
Postfix Admin Add Mailbox option
To create a user mailbox, click the quick link “Add Mailbox.” You will now be taken to the “Add Mailbox Wizard” screen. Fill out the details in the form and press the “Add Mailbox” button once completed. The wizard will create your first virtual user (mailbox) account.
Creating a new mailbox in Postfix Admin
Fig 4
Now press Enter to complete the installation. The installation logs should be similar as shown below.
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
libmysqlclient21
Suggested packages:
procmail postfix-pgsql postfix-ldap postfix-pcre postfix-lmdb postfix-sqlite sasl2-bin | dovecot-common resolvconf postfix-cdb mail-reader
postfix-doc
The following NEW packages will be installed:
libmysqlclient21 postfix postfix-mysql
-----
-----
Postfix (main.cf) is now set up with a default configuration. If you need to
make changes, edit /etc/postfix/main.cf (and others) as needed. To view
Postfix configuration values, see postconf(1).
After modifying main.cf, be sure to run 'systemctl reload postfix'.
Running newaliases
Created symlink /etc/systemd/system/multi-user.target.wants/postfix.service → /lib/systemd/system/postfix.service.
Setting up postfix-mysql (3.4.10-1ubuntu1) ...
Processing triggers for rsyslog (8.2001.0-1ubuntu1) ...
Processing triggers for ufw (0.36-6) ...
Processing triggers for systemd (245.4-4ubuntu3.1) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9) ...
# Additional Package
sudo apt install postfix-policyd-spf-python
This completes the installation of Postfix on Ubuntu 20.04 LTS.
Install Dovecot
This section provides the steps to install Dovecot on Ubuntu 20.04 LTS. The below-mentioned commands are required to install Dovecot.
# Install Dovecot
sudo apt install dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql
# Output
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
libexttextcat-2.0-0 libexttextcat-data liblua5.3-0
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 liblua5.3-0
----
----
Setting up dovecot-mysql (1:2.3.7.2-1ubuntu3.1) ...
Processing triggers for ufw (0.36-6) ...
Processing triggers for systemd (245.4-4ubuntu3.1) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9) ...
Processing triggers for dovecot-core (1:2.3.7.2-1ubuntu3.1) ...
This completes the installation of Dovecot on Ubuntu 20.04 LTS.
Install Postgrey, Clam, Amavis, and SpamAssassin
Now install Postgrey, Clam, Amavis, and SpamAssassin on Ubuntu 20.04 LTS as shown below.
# Install Postgrey
sudo apt install postgrey
# Install Clam
sudo apt install clamav clamav-daemon
# Install Amavis
sudo apt install amavis
# Install SpamAssassin
sudo apt install spamassassin
# Install additional packages
sudo apt install libdbi-perl libdbd-mysql-perl
Install OpenDKIM
We need to install and configure DKIM on our mail server 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. Use the below-mentioned commands to install OpenDKIM.
# Install OpenDKIM
sudo apt install opendkim opendkim-tools
# Output
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
dns-root-data libmemcached11 libmilter1.0.1 libopendbx1 libopendbx1-sqlite3 libopendkim11 librbl1 libunbound8 libvbr2
Suggested packages:
unbound
The following NEW packages will be installed:
dns-root-data libmemcached11 libmilter1.0.1 libopendbx1 libopendbx1-sqlite3 libopendkim11 librbl1 libunbound8 libvbr2 opendkim opendkim-tools
----
----
Setting up opendkim-tools (2.11.0~beta2-1) ...
Setting up opendkim (2.11.0~beta2-1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/opendkim.service → /lib/systemd/system/opendkim.service.
Processing triggers for systemd (245.4-4ubuntu3.1) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9) ...
This completes the installation of DKIM on Ubuntu 20.04 LTS.
Configure Postfix
This section provides the steps to configure Postfix on Ubuntu 20.04 LTS. Now complete the configurations as shown below.
Default SSL Certificate - Generate the default certificate if required.
sudo apt install --assume-yes ssl-cert
sudo make-ssl-cert generate-default-snakeoil --force-overwrite
Backup Config - We must backup the main and master configuration files as shown below.
# Backup Configurations
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.orig
sudo cp /etc/postfix/master.cf /etc/postfix/master.cf.orig
Virtual Hosts - Create the virtual hosts directory as shown below.
# 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 Jun 24 03:21 /<path to vmail>/vmail
# Check UID
id -u vmail
# Output
5000
# Check GID
id -g vmail
# Output
5000
Create Header and Content Checks - Create the header and content checks file as shown below.
# Create Header Checks
sudo nano /etc/postfix/header_checks
# Content
/^Received:/ IGNORE
/^User-Agent:/ IGNORE
/^X-Mailer:/ IGNORE
/^X-Originating-IP:/ IGNORE
/^x-cr-[a-z]*:/ IGNORE
/^Thread-Index:/ IGNORE
# MIME header checks
sudo nano /etc/postfix/mime_header_checks
# Content
/name=[^>]*\.(bat|com|exe|dll)/ REJECT
# Body Checks
sudo nano /etc/postfix/body_checks
# Add an empty line for now
# Client Checks
sudo nano /etc/postfix/client_checks
# Add an empty line for now
# Sender Checks
sudo nano /etc/postfix/sender_checks
# Add an empty line for now
Email Database - Create the database to store the virtual users.
# Create User
CREATE USER 'mail'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'dbpassword';
# Create Database
CREATE DATABASE mail CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
# Privileges
GRANT ALL PRIVILEGES ON mail.* TO 'mail'@'localhost';
FLUSH PRIVILEGES;
Now create and configure the virtual domains and users files as shown below.
# Virtual domains
sudo nano /etc/postfix/mysql_virtual_mailbox_domains.cf
# Content
hosts = 127.0.0.1
user = mail
password = dbpassword
dbname = mail
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = 0 and active = 1
# Email addresses
sudo nano /etc/postfix/mysql_virtual_mailbox_maps.cf
# Content
hosts = 127.0.0.1
user = mail
password = dbpassword
dbname = mail
query = SELECT goto FROM alias WHERE address='%s' AND active = 1
# Aliases
sudo nano /etc/postfix/mysql_virtual_alias_maps.cf
# Content
hosts = 127.0.0.1
user = mail
password = dbpassword
dbname = mail
query = SELECT goto FROM alias WHERE address='%s' AND active = 1
# Relays
sudo nano /etc/postfix/mysql_relay_domains.cf
# Content
hosts = 127.0.0.1
user = mail
password = dbpassword
dbname = mail
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = 1
Configure Postfix Main - Now configure the main file of Postfix as shown below.
# Configure Postfix Main
sudo nano /etc/postfix/main.cf
The complete configurations are shown below. You may refer to Postfix documentation to learn more about these parameters and their usage. Also, update the configurations based on your requirements.
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 - Now configure the master file of Postfix as shown below.
# Configure Postfix Master
sudo nano /etc/postfix/master.cf
The complete configurations are shown below.
#
# 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.
sudo chown -R vmail:dovecot /etc/dovecot
sudo chmod -R o-rwx /etc/dovecot
Now backup the configuration files as shown below.
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.
# Main Configuration
sudo nano /etc/dovecot/dovecot.conf
# 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.
# Mail Configuration
sudo nano /etc/dovecot/conf.d/10-mail.conf
# 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.
# Auth Configuration
sudo nano /etc/dovecot/conf.d/10-auth.conf
# 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.
# Mail Configuration
sudo nano /etc/dovecot/conf.d/auth-sql.conf.ext
# 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.
# Mail Configuration
sudo nano /etc/dovecot/dovecot-sql.conf.ext
# 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.
# Master Configuration
sudo nano /etc/dovecot/conf.d/10-master.conf
# 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.
# SSL Configuration
sudo nano /etc/dovecot/conf.d/10-ssl.conf
# 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.
# LDA Configuration
sudo nano /etc/dovecot/conf.d/15-lda.conf
# Updates
-----
postmaster_address = postmaster@example.com
-----
# Save and exit the editor
Configure Postgrey, Clam, Amavis, SpamAssassin, and OpenDKIM
We can whitelist the well know clients as shown below.
# Whitelist Clients
sudo nano /etc/postgrey/whitelist_clients.local
# Clients List
# Save and exit the editor
Create the Clam and Amavis users as shown below.
sudo adduser clamav amavis
sudo adduser amavis clamav
Configure the Amavis as shown below.
# Update filter mode
sudo nano /etc/amavis/conf.d/15-content_filter_mode
# Update
-----
@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);
-----
# Update User
sudo nano /etc/amavis/conf.d/50-user
# Update
-----
$max_servers = 3;
$sa_tag_level_deflt = -9999;
@lookup_sql_dsn = (
['DBI:mysql:database=mail;host=127.0.0.1;port=3306',
'mail',
'dbpassword']);
$sql_select_policy = 'SELECT domain from domain WHERE CONCAT("@",domain) IN (%k)';
-----
-----
Configure SpamAssassin as shown below.
# Enable SpamAssassin
sudo update-rc.d spamassassin enable
# Update Config
sudo nano /etc/default/spamassassin
# Update
CRON=1
Refresh the Clam Antivirus database.
sudo /etc/init.d/clamav-freshclam stop
sudo freshclam -v
sudo /etc/init.d/clamav-freshclam start
Now configure OpenDKIM as shown below.
# Configure OpenDKIM
sudo nano /etc/default/opendkim
# Comment out
#SOCKET=local:$RUNDIR/opendkim.sock
# Add at last
SOCKET="inet:8891@localhost"
# Save and exit the editor
# Configure OpenDKIM
sudo nano /etc/opendkim.conf
# Add at the last
SOCKET inet:8891@localhost
# Save and exit the editor
Configure Monit
This section provides the steps to configure Monit. You can follow How To Install And Configure Monit On Ubuntu 20.04 LTS.
Amavis - Add the configurations for Amavis as shown below.
# Amavis Configurations
sudo nano /etc/monit/conf.d/amavis
# Content
check process amavisd with pidfile /var/run/amavis/amavisd.pid
every 5 cycles
group mail
start program = "/usr/sbin/service amavis start"
stop program = "/usr/sbin/service amavis stop"
if failed port 10024 protocol smtp then restart
if 5 restarts within 25 cycles then timeout
Dovecot - Add the configurations for Dovecot as shown below.
# Dovecot Configurations
sudo nano /etc/monit/conf.d/dovecot
# Content
check process dovecot with pidfile /var/run/dovecot/master.pid
group mail
start program = "/usr/sbin/service dovecot start"
stop program = "/usr/sbin/service dovecot stop"
group mail
if failed port 993 for 5 cycles then restart
if 5 restarts within 25 cycles then timeout
Postfix - Add the configurations for Postfix as shown below.
# Postfix Configurations
sudo nano /etc/monit/conf.d/postfix
# Content
check process postfix with pidfile /var/spool/postfix/pid/master.pid
group mail
start program = "/usr/sbin/service postfix start"
stop program = "/usr/sbin/service postfix stop"
if failed port 25 protocol smtp then restart
if 5 restarts within 5 cycles then timeout
SpamAssassin - Add the configurations for SpamAssassin as shown below.
# SpamAssassin Configurations
sudo nano /etc/monit/conf.d/spamassassin
# Content
check process spamassassin with pidfile /var/run/spamassassin.pid
group mail
start program = "/usr/sbin/service spamassassin start"
stop program = "/usr/sbin/service spamassassin stop"
if 5 restarts within 5 cycles then timeout
Configure Fail2ban
This section provides the steps to configure Fail2ban for Postfix and Dovecot. You can follow How To Install Fail2ban On Ubuntu 20.04 LTS.
Default - Configure the DEFAULT block to send emails for the failed attempts as shown below. Make sure to create the email accounts for destemail and sender while installing the Postfix Admin.
# Local Jail
sudo nano /etc/fail2ban/jail.local
# Update
[DEFAULT]
mta = sendmail
destemail = netban@example.com
sendername = Admin
sender = admin@example.com
action = %(action_mwl)s
# Save and exit the editor
Postfix - The default filter of Postfix for Fail2ban is available at /etc/fail2ban/filter.d/postfix.conf. You may further update it if required. Now add the postfix jail as shown below.
# Add Postfix Jail
sudo nano /etc/fail2ban/jail.d/postfix.conf
# Content
[postfix]
enabled = true
logpath = /var/log/mail.log
Dovecot - The default filter of Postfix for Fail2ban is available at /etc/fail2ban/filter.d/dovecot.conf. You may further update it if required. Now add the dovecot jail as shown below.
# Add Dovecot Jail
sudo nano /etc/fail2ban/jail.d/dovecot.conf
# Content
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps
filter = dovecot
logpath = /var/log/mail.log
maxretry = 3
Restart Services
Now restart all the services as shown below.
# Restart Apache
sudo service apache2 restart
# Apache Status
sudo service apache2 status
# Output
● apache2.service - The Apache HTTP Server Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-06-24 14:39:08 UTC; 4s ago Docs: https://httpd.apache.org/docs/2.4/ Process: 600540 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS) Main PID: 600561 (apache2) Tasks: 6 (limit: 4622) Memory: 33.9M CGroup: /system.slice/apache2.service
-----
# Restart Postfix
sudo service postfix restart
# Postfix Status
sudo service postfix status
# Output - It shows status active (exited) - a known bug in debian, but postfix works fine
● postfix.service - Postfix Mail Transport Agent Loaded: loaded (/lib/systemd/system/postfix.service; enabled; vendor preset: enabled) Active: active (exited) since Wed 2020-06-24 14:39:29 UTC; 5s ago Process: 600985 ExecStart=/bin/true (code=exited, status=0/SUCCESS) Main PID: 600985 (code=exited, status=0/SUCCESS) Jun 24 14:39:29 mail.example.com systemd[1]: Starting Postfix Mail Transport Agent... Jun 24 14:39:29 mail.example.com systemd[1]: Finished Postfix Mail Transport Agent.
# Restart Dovecot
sudo service dovecot restart
# Dovecot Status
sudo service dovecot status
# Output
● dovecot.service - Dovecot IMAP/POP3 email server Loaded: loaded (/lib/systemd/system/dovecot.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-06-24 14:40:17 UTC; 22s ago Docs: man:dovecot(1) http://wiki2.dovecot.org/ Main PID: 601200 (dovecot) Tasks: 4 (limit: 4622) Memory: 3.5M CGroup: /system.slice/dovecot.service ----
# Restart Clam Antivirus
sudo service clamav-daemon restart
# Restart Amavis
sudo service amavis restart
# Restart SmapAssassin
sudo service spamassassin restart
# Start OpenDKIM
sudo service opendkim start
# Postgrey reload fails - patch available at - https://bugs.debian.org/cgi-bin/bugreport.cgi?att=1;bug=934068;filename=postgrey_init.patch
#sudo service postgrey reload
# Restart PostGrey
sudo service postgrey restart
# Restart Fail2ban
sudo service fail2ban restart
# Fail2ban Status
sudo service fail2ban status
# Output
● fail2ban.service - Fail2Ban Service Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-06-24 14:41:20 UTC; 4s ago Docs: man:fail2ban(1) Process: 601702 ExecStartPre=/bin/mkdir -p /run/fail2ban (code=exited, status=0/SUCCESS) Main PID: 601710 (f2b/server) Tasks: 23 (limit: 4622) Memory: 15.2M CGroup: /system.slice/fail2ban.service └─601710 /usr/bin/python3 /usr/bin/fail2ban-server -xf start ----
# Restart Monit
sudo service monit restart
Load Postfix maps.
sudo postmap /etc/postfix/client_checks
sudo postmap /etc/postfix/sender_checks
sudo postfix reload
# Output
postfix/postfix-script: refreshing the Postfix mail system
Open the Ports
After completing the installation of all the software and utilities, we can open the email ports by updating the firewall. You can either update the firewall provided by your hosting provider or use the UFW to open the ports 25, 465, 587, 995, 143, and 993.
Install Postfix Admin
This section provides the steps to install Postfix Admin. We can use the Postfix Admin to manage the virtual domains and virtual users. Now download and install the most recent version of Postfix Admin from SourceForge as shown below.
# Download Postfix Admin
# Extract Postfix Admin
sudo tar -xf postfixadmin-3.2.tar.gz
# Move to www
sudo mkdir -p /var/www/mailadmin.example.com/
sudo mv postfixadmin-3.2 /var/www/mailadmin.example.com/html
sudo chown -R www-data:www-data /var/www/mailadmin.example.com/html
# Create Templates Directory
sudo mkdir -p /var/www/mailadmin.example.com/html/templates_c
sudo chown -R www-data:www-data /var/www/mailadmin.example.com/html/templates_c
The above-mentioned commands installed Postfix Admin at /var/www/mailadmin.example.com/html. Now add the virtual hosts as shown below.
# Virtual Host - HTTP
sudo nano /etc/apache2/sites-available/mailadmin.example.com.conf
# Content
<VirtualHost *:80>
ServerName mailadmin.example.com
ServerAlias mailadmin.example.com
ServerAdmin admin@example.com
DocumentRoot /data/www/mailadmin.example.com/html/public
<Directory /data/www/mailadmin.example.com/html/public>
Options -Indexes +FollowSymLinks
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =mailadmin.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
In case you have used Let's Encrypt to install an SSL certificate, you can update your certificate by adding the mailadmin subdomain as shown below. It will also generate and enable the virtual host for SSL.
# Upgrade SSL Certificate
sudo letsencrypt --apache -d example.com,www.example.com,mail.example.com,mailadmin.example.com --email admin@example.com --agree-tos
# Output
-----
Do you want to expand and replace this existing certificate with the new
certificate?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(E)xpand/(C)ancel: e
-----
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
-----
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.com/privkey.pem
-----
You can also add the virtual host for SSL, in case you have generated a self-signed certificate or obtained the SSL certificate from the well-known providers. The virtual host for SSL should be similar as shown below.
# Virtual Host - HTTPS
sudo nano /etc/apache2/sites-available/mailadmin.example.com-le-ssl.conf
# Content
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName mailadmin.example.com
ServerAlias mailadmin.example.com
ServerAdmin admin@example.com
DocumentRoot /data/www/mailadmin.example.com/html/public
<Directory /data/www/mailadmin.example.com/html/public>
Options -Indexes +FollowSymLinks
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Now we will configure Postfix Admin to use the database created by us in the previous sections.
# Postfix Admin - Local Config
sudo nano /var/www/mailadmin.example.com/html/config.local.php
# Content
<?php
$CONF['configured'] = true;
$CONF['postfix_admin_url'] = 'https://mailadmin.example.com';
// Database connection details.
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'mail';
$CONF['database_password'] = 'dbpassword';
$CONF['database_name'] = 'mail';
$CONF['admin_email'] = 'admin@example.com';
$CONF['smtp_server'] = 'localhost';
$CONF['smtp_port'] = '25';
$CONF['encrypt'] = 'md5crypt';
$CONF['default_aliases'] = [
'abuse' => 'admin@example.com',
'hostmaster' => 'admin@example.com',
'postmaster' => 'admin@example.com',
'webmaster' => 'admin@example.com'
];
$CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Return to example.com';
$CONF['footer_link'] = 'https://www.example.com';
$CONF['domain_path'] = 'NO';
$CONF['domain_in_mailbox'] = 'YES';
$CONF['create_mailbox_subdirs_prefix']='';
# Save and exit the editor
sudo chown -R www-data:www-data /var/www/mailadmin.example.com/html/config.local.php
Now we can access the mail admin using the URL - https://mailadmin.example.com/setup.php. It will run the migration scripts and add the database tables using the configurations provided by us. The setup.php should be similar to Fig 5 and Fig 6.
Fig 3
Now press Enter Key to configure the hostname as shown in Fig 4.
Fig 2
Keep the option Internet Site selected and press the Right Arrow Key to highlight the OK option as shown in Fig 3 and.
Fig 1
Press the Right Arrow Key to highlight the OK option and press Enter Key. It will provide the options to choose configuration type as shown in Fig 2.
10 – Create a System User To Handle Virtual Mail Directories
Virtual users are those that don’t technically exist on your Linux server, and they don’t use the standard Linux methods for authentication or mail delivery and storage. Your mail server virtual user accounts are defined within the database created by Postfix Admin rather than existing as system user accounts, so we have to create a single system user account that will handle services like mail storage and Dovecot authentication.
First, let’s create a system user account called vmail and give it permissions to the required directories. This system account will be responsible for the backend operations for mailbox storage and services.
useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual MailDir Handler" vmail mkdir -p /var/vmail chown vmail:mail /var/vmail chmod 770 /var/vmail
An explanation of the above commands:
We created the system user account vmail, assigned the home directory as /var/vmail, and restricted the ability for this account to login via shell or console.
We then manually created the home directory /var/vmail for the new system user account.
We then set the owner and group for the /var/vmail directory.
We then gave full permissions to the system user vmail and the security group mail assigned to the directory /var/vmail.
11 – Configuring Dovecot
Dovecot is an open-source IMAP and POP3 email server written with security in mind. Dovecot has many built-in features, which you can view at their public website, http://www.dovecot.org.
Dovecot will be responsible for managing the IMAP and POP3 connections, managing local mail directories, and receiving the incoming mail handed off from the Postfix SMTP mail server process. Dovecot will also manage the authentication for SMTP connections. Many different files within the /etc/dovecot directory handle Dovecot configuration.
First, let’s configure Dovecot to use the database set up by Postfix Admin. We will first edit the configuration file /etc/dovecot/conf.d/auth-sql.conf.ext
nano /etc/dovecot/conf.d/auth-sql.conf.ext
Edit or update the contents to have the following configuration.
# Look up user passwords from a SQL database as # defined in /etc/dovecot/dovecot-sql.conf.ext passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } # Look up user information from a SQL database as # defined in /etc/dovecot/dovecot-sql.conf.ext userdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext }
Once done, save and exit the configuration file.
SQL Configuration File
Now we are going to back up the original SQL configuration file /etc/dovecot/dovecot-sql.conf.ext and create a new configuration file for Dovecot to use.
mv /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext.original nano /etc/dovecot/dovecot-sql.conf.ext
Now copy the below content into the configuration file and update the values for the mail database you set up in Step 7.
# Database driver: mysql, pgsql, sqlite driver = mysql # Database Connection: # connect = host=192.168.1.1 dbname=users # connect = host=sql.example.com dbname=virtual user=virtual password=blarg # connect = /etc/dovecot/authdb.sqlite # connect = host=localhost dbname=mail user=mail password=mypassword # Default password scheme. # # List of supported schemes is in # http://wiki2.dovecot.org/Authentication/PasswordSchemes # # Weak but common encryption scheme: default_pass_scheme = MD5-CRYPT # # Comment the above out and uncomment below # for stronger encryption: #default_pass_scheme - SHA256-CRYPT # Define the query to obtain a user password. password_query = \ SELECT username as user, password, '/var/vmail/%d/%n' as userdb_home, \ 'maildir:/var/vmail/%d/%n' as userdb_mail, 150 as userdb_uid, 8 as userdb_gid \ FROM mailbox WHERE username = '%u' AND active = '1' # Define the query to obtain user information. user_query = \ SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, \ 150 AS uid, 8 AS gid, concat('dirsize:storage=', quota) AS quota \ FROM mailbox WHERE username = '%u' AND active = '1'
Once done, save and exit this configuration file.
Authentication Definition File
We are now going to back up the authentication definition file /etc/dovecot/conf.d/10-auth.conf and create a new one.
mv /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf.original nano /etc/dovecot/conf.d/10-auth.conf
Now copy the below content into the definition file.
# Disable LOGIN command and all other plaintext authentications unless # SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP # matches the local IP (ie. you're connecting from the same computer), the # connection is considered secure and plaintext authentication is allowed. disable_plaintext_auth = yes # Space separated list of wanted authentication mechanisms: # plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey # gss-spnego # NOTE: See also disable_plaintext_auth setting. auth_mechanisms = plain login ## ## Password and user databases ## # # Password database is used to verify user's password (and nothing more). # You can have multiple passdbs and userdbs. This is useful if you want to # allow both system users (/etc/passwd) and virtual users to login without # duplicating the system users into virtual database. # # <doc/wiki/PasswordDatabase.txt> # # User database specifies where mails are located and what user/group IDs # own them. For single-UID configuration use "static" userdb. # # <doc/wiki/UserDatabase.txt> # Use the SQL database configuration rather than any of the others. !include auth-sql.conf.ext
Once done, save and exit the file.
Mail Definition File
Next, we are going to tell Dovecot where to store the virtual users’ mail. We will be backing up the mail definition file /etc/dovecot/conf.d/10-mail.conf and creating a new one.
mv /etc/dovecot/conf.d/10-mail.conf /etc/dovecot/conf.d/10-mail.conf.original nano /etc/dovecot/conf.d/10-mail.conf
Now copy the below content into the definition file.
# Location for users' mailboxes. The default is empty, which means that Dovecot # tries to find the mailboxes automatically. This won't work if the user # doesn't yet have any mail, so you should explicitly tell Dovecot the full # location. # # If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u) # isn't enough. You'll also need to tell Dovecot where the other mailboxes are # kept. This is called the "root mail directory", and it must be the first # path given in the mail_location setting. # # There are a few special variables you can use, eg.: # # %u - username # %n - user part in user@domain, same as %u if there's no domain # %d - domain part in user@domain, empty if there's no domain # %h - home directory # # See doc/wiki/Variables.txt for full list. Some examples: # # mail_location = maildir:~/Maildir # mail_location = mbox:~/mail:INBOX=/var/mail/%u # mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n # # <doc/wiki/MailLocation.txt> # mail_location = maildir:/var/vmail/%d/%n # System user and group used to access mails. If you use multiple, userdb # can override these by returning uid or gid fields. You can use either numbers # or names. <doc/wiki/UserIds.txt> mail_uid = vmail mail_gid = mail # Valid UID range for users, defaults to 500 and above. This is mostly # to make sure that users can't log in as daemons or other system users. # Note that denying root logins is hardcoded to dovecot binary and can't # be done even if first_valid_uid is set to 0. # # Use the vmail user uid here. first_valid_uid = 150 last_valid_uid = 150 # If you need to set multiple mailbox locations or want to change default # namespace settings, you can do it by defining namespace sections. # # You can have private, shared and public namespaces. Private namespaces # are for user's personal mails. Shared namespaces are for accessing other # users' mailboxes that have been shared. Public namespaces are for shared # mailboxes that are managed by sysadmin. If you create any shared or public # namespaces you'll typically want to enable ACL plugin also, otherwise all # users can access all the shared mailboxes, assuming they have permissions # on filesystem level to do so. namespace inbox { # Namespace type: private, shared or public #type = private # Hierarchy separator to use. You should use the same separator for all # namespaces or some clients get confused. '/' is usually a good one. # The default however depends on the underlying mail storage format. #separator = # Prefix required to access this namespace. This needs to be different for # all namespaces. For example "Public/". #prefix = # Physical location of the mailbox. This is in same format as # mail_location, which is also the default for it. #location = # There can be only one INBOX, and this setting defines which namespace # has it. inbox = yes # If namespace is hidden, it's not advertised to clients via NAMESPACE # extension. You'll most likely also want to set list=no. This is mostly # useful when converting from another server with different namespaces which # you want to deprecate but still keep working. For example you can create # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/". #hidden = no # Show the mailboxes under this namespace with LIST command. This makes the # namespace visible for clients that don't support NAMESPACE extension. # "children" value lists child mailboxes, but hides the namespace prefix. #list = yes # Namespace handles its own subscriptions. If set to "no", the parent # namespace handles them (empty prefix should always have this as "yes") #subscriptions = yes }
Once done, save and exit the file.
SSL Definition File
If you have an SSL certificate that you would like to install, you will need to modify the Dovecot SSL definition file /etc/dovecot/conf.d/10-ssl.conf with your valid certificate. Remember, you will have to also include your CA certificate bundle if one has been provided by the certificate issuer.
Dovecot Master Definition File
We are now going to update the Dovecot master definition file /etc/dovecot/10-master.conf to include the system user account and the postfix settings.
nano /etc/dovecot/conf.d/10-master.conf
Search for the config definition service auth and replace the definition block with the following.
service auth { # auth_socket_path points to this userdb socket by default. It's typically # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have # full permissions to this socket are able to get a list of all usernames and # get the results of everyone's userdb lookups. # # The default 0666 mode allows anyone to connect to the socket, but the # userdb lookups will succeed only if the userdb returns an "uid" field that # matches the caller process's UID. Also if caller's uid or gid matches the # socket's uid or gid the lookup succeeds. Anything else causes a failure. # # To give the caller full permissions to lookup all users, set the mode to # something else than 0666 and Dovecot lets the kernel enforce the # permissions (e.g. 0777 allows everyone full permissions). unix_listener auth-userdb { mode = 0600 user = vmail group = mail } # Postfix smtp-auth unix_listener /var/spool/postfix/private/auth { mode = 0660 # Assuming the default Postfix userid and groupid user = postfix group = postfix } }
Once done, save and exit the file.
LDA Definition File
In some cases, you may have to explicitly define the postmaster email address for your server. To do this, you will need to edit the LDA definition file /etc/dovecot/conf.d/15-lda.conf. If you see error messages like Invalid settings: postmaster_address setting not given showing up in the mail server logs, then this configuration change is the likely fix for that error.
nano /etc/dovecot/conf.d/15-lda.conf
Search for the definition postmaster_address and update the value to include your domain’s postmaster account.
# Address to use when sending rejection mails. # Default is postmaster@<your domain>. %d expands to recipient domain. #postmaster_address = postmaster_address = postmaster@linuxbuz.com
Once done, save and exit the file.
We now need to update the Dovecot configuration directory to be accessible to the Dovecot service account as well as the vmail system account.
chown -R vmail:dovecot /etc/dovecot chmod -R o-rwx /etc/dovecot
You have now completed the configuration of the Dovecot service and we can now move on to the antivirus and anti-spam services.
12 – Configuring Amavis, ClamAV, and SpamAssassin
What are these packages?
– Amavis is an interface between Postfix and content filtering packages such as SpamAssassin and ClamAV.
– ClamAV is a high-performance antivirus engine for detecting trojans, viruses, malware & other malicious threats.
– SpamAssassin is a high-performance anti-spam platform famous for its Bayesian spam filtering capabilities. It gives system administrators a filter to classify messages and block unsolicited bulk email.
We will now walk you through the process of installing some protection for your mail server. For the most part, the default configurations are sufficient for a good line of defense against spam and viruses getting through your mail server. If you have special requirements, you can, of course, spend a good amount of time crafting intricate processing rules.
Let’s first create the two system user accounts, amavis and clamav, and allow them to collaborate together.
adduser clamav amavis adduser amavis clamav
We are now going to enable the Amavis daemon by editing the /etc/amavis/conf.d/15-content_filter_mode configuration file.
nano /etc/amavis/conf.d/15-content_filter_mode
By default, the Amavis software is disabled. To enable the Amavis software, all you need to do is remove the comment tags from the bypass configuration lines.
use strict; # You can modify this file to re-enable SPAM checking through spamassassin # and to re-enable antivirus checking. # # Default antivirus checking mode # Please note, that anti-virus checking is DISABLED by # default. # If You wish to enable it, please uncomment the following lines: @bypass_virus_checks_maps = ( %bypass_virus_checks, @bypass_virus_checks_acl, $bypass_virus_checks_re); # # Default SPAM checking mode # Please note, that anti-spam checking is DISABLED by # default. # If You wish to enable it, please uncomment the following lines: @bypass_spam_checks_maps = ( %bypass_spam_checks, @bypass_spam_checks_acl, $bypass_spam_checks_re); 1; # ensure a defined return
Once done, you can save and exit the file.
We are now going to enable the SpamAssassin software by editing the /etc/default/spamassassin configuration file.
nano /etc/default/spamassassin
Now search for the variable CRON=0 in the configuration file and change the value to 1.
# Cronjob # Set to anything but 0 to enable the cron job to automatically update # spamassassin's rules on a nightly basis CRON=1
Next, enable the SpamAssassin software with the following command:
update-rc.d spamassassin enable
We are now going to set up Amavis to use the database from Postfix Admin to identify mail that is arriving for local delivery. By default, SpamAssassin and Amavis will only check mail that is determined to be arriving for local delivery. Because we are set up to use virtual user mailboxes, we have to tell the services where to locate the user accounts.
To do this, we need to update the configuration file /etc/amavis/conf.d/50-user.
nano /etc/amavis/conf.d/50-user
Replace the contents of this configuration file with the below. Be sure to update the MySQL database password to use the password for the database user “mail” that you entered in Step #7.
use strict; # # Place your configuration directives here. They will override those in # earlier files. # # See /usr/share/doc/amavisd-new/ for documentation and examples of # the directives you can use in this file # # Three concurrent processes. This should fit into the RAM available on an # AWS micro instance. This has to match the number of processes specified # for Amavis in /etc/postfix/master.cf. $max_servers = 3; # Add spam info headers if at or above that level - this ensures they # are always added. $sa_tag_level_deflt = -9999; # Check the database to see if mail is for local delivery, and thus # should be spam checked. @lookup_sql_dsn = ( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'mail', 'mypassword']); $sql_select_policy = 'SELECT domain from domain WHERE CONCAT("@",domain) IN (%k)'; # Uncomment to bump up the log level when testing. # $log_level = 2; #------------ Do not modify anything below this line ------------- 1; # ensure a defined return
Once done, save and exit the configuration file.
We will now need to restart the Amavis and SpamAssassin services so that they see the new configuration settings.
service amavis restart services spamassassin restart
13 – Configuring Postfix
We are now ready to configure the Postfix mail server. Postfix handles all of the incoming and outgoing mail via the SMTP protocol, and we are going to configure it to integrate will all of the other software packages that we have just configured.
From a high level view, we are needing Postfix to hand off incoming mail to the SpamAssassin and ClamAV scanners for filtering, and then to pass unblocked mail messages on to the Dovecot services for final mailbox delivery. Postfix will also authenticate the virtual users who connect via SMTP in order to send email messages.
We are going to create a definition file for Postfix to identify users and mailboxes. Please note that the “hosts” directive in these configuration files must be exactly the same as the “bind-address” in the /etc/mysql/my.cnf configuration files.
First, let’s look up the value of the bind-address in the MySQL configuration files.
cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep bind-address
<< output >> bind-address = 127.0.0.1
Now that we have the configuration value, we are going to create the required Postfix definition files.
Copy and paste the content for each file. Make sure to update the password value with the password for the database user “mail” that you entered in Step #7.
/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf
nano /etc/postfix/mysql_virtual_alias_domainaliases_maps.cf
user = mail password = mypassword hosts = 127.0.0.1 dbname = mail query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' AND alias.address=concat('%u', '@', alias_domain.target_domain) AND alias.active = 1
Once done, save and exit the configuration file.
/etc/postfix/mysql_virtual_alias_maps.cf
nano /etc/postfix/mysql_virtual_alias_maps.cf
user = mail password = mypassword hosts = 127.0.0.1 dbname = mail table = alias select_field = goto where_field = address additional_conditions = and active = '1'
Once done, save and exit the configuration file.
/etc/postfix/mysql_virtual_domains_maps.cf
nano /etc/postfix/mysql_virtual_domains_maps.cf
user = mail password = mypassword hosts = 127.0.0.1 dbname = mail table = domain select_field = domain where_field = domain additional_conditions = and backupmx = '0' and active = '1'
Once done, save and exit the configuration file.
/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf
nano /etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf
user = mail password = mypassword hosts = 127.0.0.1 dbname = mail query = SELECT maildir FROM mailbox, alias_domain WHERE alias_domain.alias_domain = '%d' AND mailbox.username=concat('%u', '@', alias_domain.target_domain ) AND mailbox.active = 1
Once done, save and exit the configuration file.
/etc/postfix/mysql_virtual_mailbox_maps.cf
nano /etc/postfix/mysql_virtual_mailbox_maps.cf
user = mail password = mypassword hosts = 127.0.0.1 dbname = mail table = mailbox select_field = CONCAT(domain, '/', local_part) where_field = username additional_conditions = and active = '1'
Once done, save and exit the configuration file.
We are now going to create the Postfix header-checking directives. These directives remove certain headers when relaying mail through the system. This helps improve privacy for sending users by removing specific headers like origin IP Address and the mail software identifiers. Copy and paste the below content into the file.
nano /etc/postfix/header_checks
/^Received:/ IGNORE /^User-Agent:/ IGNORE /^X-Mailer:/ IGNORE /^X-Originating-IP:/ IGNORE /^x-cr-[a-z]*:/ IGNORE /^Thread-Index:/ IGNORE
Once done, save and exit.
We are now ready to make some changes to the system default Postfix /etc/postfix/main.cf configuration file.
This file contains a large amount of complex choices and options for a Postfix server installation. It is far beyond the scope of this article to explain every option or best practice available, so we strongly suggest that you read through the Postfix configuration options /usr/share/postfix/main.cf.dist or the software vendor online manual. O’Reilly has also published a very good book named Postfix: The Definitive Guide.
First, we are going to create a backup of the original main.cf configuration file and then create a new copy of the file.
mv /etc/postfix/main.cf /etc/postfix/main.cf.original nano /etc/postfix/main.cf
Now, copy the below content into the /etc/postfix/main.cf configuration file.
# See /usr/share/postfix/main.cf.dist for a commented, more complete version # The first text sent to a connecting process. smtpd_banner = $myhostname ESMTP $mail_name biff = no # appending .domain is the MUA's job. append_dot_mydomain = no readme_directory = no # SASL parameters # --------------------------------- # Use Dovecot to authenticate. smtpd_sasl_type = dovecot # Referring to /var/spool/postfix/private/auth smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes broken_sasl_auth_clients = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = smtpd_sasl_authenticated_header = yes # TLS parameters # --------------------------------- # Replace this with your SSL certificate path if you are using one. smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key # The snakeoil self-signed certificate has no need for a CA file. But # if you are using your own SSL certificate, then you probably have # a CA certificate bundle from your provider. The path to that goes # here. #smtpd_tls_CAfile=/path/to/ca/file smtp_tls_note_starttls_offer = yes smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/urandom #smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache #smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache # Note that forcing use of TLS is going to cause breakage - most mail servers # don't offer it and so delivery will fail, both incoming and outgoing. This is # unfortunate given what various governmental agencies are up to these days. # These are Postfix 2.2 only. # # Enable (but don't force) use of TLS on incoming smtp connections. smtpd_use_tls = yes smtpd_enforce_tls = no # Enable (but don't force) use of TLS on outgoing smtp connections. smtp_use_tls = yes smtp_enforce_tls = no # These are Postfix 2.3 and later. # # Enable (but don't force) all incoming smtp connections to use TLS. smtpd_tls_security_level = may # Enable (but don't force) all outgoing smtp connections to use TLS. smtp_tls_security_level = may # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for # information on enabling SSL in the smtp client. # SMTPD parameters # --------------------------------- # Uncomment the next line to generate "delayed mail" warnings #delay_warning_time = 4h # will it be a permanent error or temporary unknown_local_recipient_reject_code = 450 # how long to keep message on queue before return as failed. # some have 3 days, I have 16 days as I am backup server for some people # whom go on holiday with their server switched off. maximal_queue_lifetime = 7d # max and min time in seconds between retries if connection failed minimal_backoff_time = 1000s maximal_backoff_time = 8000s # how long to wait when servers connect before receiving rest of data smtp_helo_timeout = 60s # how many address can be used in one message. # effective stopper to mass spammers, accidental copy in whole address list # but may restrict intentional mail shots. smtpd_recipient_limit = 16 # how many error before back off. smtpd_soft_error_limit = 3 # how many max errors before blocking it. smtpd_hard_error_limit = 12 # This next set are important for determining who can send mail and relay mail # to other servers. It is very important to get this right - accidentally producing # an open relay that allows unauthenticated sending of mail is a Very Bad Thing. # # You are encouraged to read up on what exactly each of these options accomplish. # Requirements for the HELO statement smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit # Requirements for the sender details smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit # Requirements for the connecting server # This is primarily the RBL (Realtime Blacklist) Filtering smtpd_client_restrictions = reject_rbl_client b.barracudacentral.org, reject_rbl_client zen.spamhaus.org, reject_rbl_client spam.dnsbl.sorbs.net # Requirement for the recipient address. Note that the entry for # "check_policy_service inet:127.0.0.1:10023" enables Postgrey. smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023, permit smtpd_data_restrictions = reject_unauth_pipelining # This is a new option as of Postfix 2.10+, and is required in addition to # smtpd_recipient_restrictions for things to work properly in this setup. smtpd_relay_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023, permit # require proper helo at connections smtpd_helo_required = yes # waste spammers time before rejecting them smtpd_delay_reject = yes disable_vrfy_command = yes # General host and delivery info # ---------------------------------- myhostname = email.linuxbuz.com myorigin = /etc/hostname # Some people see issues when setting mydestination explicitly to the server # subdomain, while leaving it empty generally doesn't hurt. So it is left empty here. # mydestination = mail.example.com, localhost mydestination = # If you have a separate web server that sends outgoing mail through this # mailserver, you may want to add its IP address to the space-delimited list in # mynetworks, e.g. as 111.222.333.444/32. mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all mynetworks_style = host # This specifies where the virtual mailbox folders will be located. virtual_mailbox_base = /var/vmail # This is for the mailbox location for each user. The domainaliases # map allows us to make use of Postfix Admin's domain alias feature. virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf, mysql:/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf # and their user id virtual_uid_maps = static:150 # and group id virtual_gid_maps = static:8 # This is for aliases. The domainaliases map allows us to make # use of Postfix Admin's domain alias feature. virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf, mysql:/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf # This is for domain lookups. virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf # Integration with other packages # --------------------------------------- # Tell postfix to hand off mail to the definition for dovecot in master.cf virtual_transport = dovecot dovecot_destination_recipient_limit = 1 # Use amavis for virus and spam scanning content_filter = amavis:[127.0.0.1]:10024 # Header manipulation # -------------------------------------- # Getting rid of unwanted headers. See: https://posluns.com/guides/header-removal/ header_checks = regexp:/etc/postfix/header_checks # getting rid of x-original-to enable_original_recipient = no
Once done, save and exit.
We are now ready to move on to the Postfix /etc/postfix/master.cf configuration file. This configuration file also contains a large number of complex choices and options for a Postfix server installation that is far beyond the scope of this article to explain.
We are going to create a backup of the original master.cf configuration file and then create a new file.
mv /etc/postfix/master.cf /etc/postfix/master.cf.original nano /etc/postfix/master.cf
Now, copy the below content into the /etc/postfix/master.cf configuration file.
# # Postfix master process configuration file. For details on the format # of the file, see the master(5) manual page (command: "man 5 master"). # # Do not forget to execute "postfix reload" after editing this file. # # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== # SMTP on port 25, unencrypted. smtp inet n - - - - smtpd #smtp inet n - - - 1 postscreen #smtpd pass - - - - - smtpd #dnsblog unix - - - - 0 dnsblog #tlsproxy unix - - - - 0 tlsproxy # 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_enforce_tls=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject -o smtpd_sasl_tls_security_options=noanonymous # 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 #628 inet n - - - - qmqpd pickup fifo n - - 60 1 pickup -o content_filter= -o receive_override_options=no_header_body_checks cleanup unix n - - - 0 cleanup qmgr fifo n - n 300 1 qmgr #qmgr fifo n - n 300 1 oqmgr tlsmgr unix - - - 1000? 1 tlsmgr rewrite unix - - - - - trivial-rewrite bounce unix - - - - 0 bounce defer unix - - - - 0 bounce trace unix - - - - 0 bounce verify unix - - - - 1 verify flush unix n - - 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - - - - smtp relay unix - - - - - smtp # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - - - - showq error unix - - - - - error retry unix - - - - - error discard unix - - - - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - - - - lmtp anvil unix - - - - 1 anvil scache unix - - - - 1 scache # # ==================================================================== # 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} # The next two entries integrate with Amavis for anti-virus/spam checks. amavis unix - - - - 3 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 # Integration with Dovecot - hand mail over to it for local delivery, and # run the process under the vmail user and mail group. dovecot unix - n n - - pipe flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(recipient)
Once done, save and exit.
We are now ready to restart all of the mail services and test the server.
service postfix restart service spamassassin restart service clamav-daemon restart service amavis restart service dovecot restart
While testing your new mail server, make sure to watch the log files closely for any errors or unusual responses.
The mail server log files are located here:
General Logging: /var/log/mail.log
Error Logging: /var/log/mail.err
14 – Reverse DNS Lookup
You will now need to set up reverse DNS lookup for your mail server.
Reverse DNS is IP-address-to-domain-name mapping – the opposite of forward (normal) DNS which maps domain names to IP addresses. Reverse DNS is mostly used by people for such things as tracking where a website visitor came from or where an email message originated, for example. Reverse DNS is also important for mail server applications. Many email servers on the Internet are configured to reject incoming emails from any IP address which does not have reverse DNS record configured.
Unless you also administer your own DNS server, you can update reverse DNS with your ISP (Internet Service Provider) or via the hosting provider of your server.
15 – Install RoundCube Webmail
Now we are going to install the RoundCube Webmail application. This application will allow your remote users to connect to their mailbox through a web browser.
apt-get install roundcube roundcube-mysql roundcube-plugins roundcube-plugins-extra
During the installation process, the system will ask you the prerequisite install questions. Note: you will need the password for the MySQL root user you set up in Step 2.
Configure database for roundcube with dbconfig-common? >> Select 'YES' Database type to be used by roundcube: >> Select 'mysql' Password of the database's administrative user: >> Enter the 'root' MySQL password that you created. MySQL application password for roundcube: >> Enter a new secure password for the RoundCube application to use.
Once you are finished with the pre-installation questions, you should see the following output. Double check the output to make sure there are not errors posted during the installation process.
dbconfig-common: writing config to /etc/dbconfig-common/roundcube.conf Creating config file /etc/dbconfig-common/roundcube.conf with new version Creating config file /etc/roundcube/debian-db.php with new version granting access to database roundcube for roundcube@localhost: success. verifying access for roundcube@localhost: success. creating database roundcube: success. verifying database roundcube exists: success. populating database via sql... done. dbconfig-common: flushing administrative password Creating config file /etc/roundcube/config.inc.php with new version apache2_invoke: Enable configuration roundcube.conf * Reloading web server apache2 * * Reloading web server apache2 * Setting up roundcube (1.4.3) ... Setting up roundcube-plugins (1.4.3) ... Setting up roundcube-plugins-extra (0.9.2-20130819) ... Processing triggers for dictionaries-common (1.20.5) ... aspell-autobuildhash: processing: en [en-common] aspell-autobuildhash: processing: en [en-variant_0] aspell-autobuildhash: processing: en [en-variant_1] aspell-autobuildhash: processing: en [en-variant_2] aspell-autobuildhash: processing: en [en-w_accents-only] aspell-autobuildhash: processing: en [en-wo_accents-only] aspell-autobuildhash: processing: en [en_CA-variant_0] aspell-autobuildhash: processing: en [en_CA-variant_1] aspell-autobuildhash: processing: en [en_CA-w_accents-only] aspell-autobuildhash: processing: en [en_CA-wo_accents-only] aspell-autobuildhash: processing: en [en_GB-ise-w_accents-only] aspell-autobuildhash: processing: en [en_GB-ise-wo_accents-only] aspell-autobuildhash: processing: en [en_GB-ize-w_accents-only] aspell-autobuildhash: processing: en [en_GB-ize-wo_accents-only] aspell-autobuildhash: processing: en [en_GB-variant_0] aspell-autobuildhash: processing: en [en_GB-variant_1] aspell-autobuildhash: processing: en [en_US-w_accents-only] aspell-autobuildhash: processing: en [en_US-wo_accents-only] Setting up aspell (0.60.7~20110707-1ubuntu1) ... Processing triggers for dictionaries-common (1.20.5) ... Setting up aspell-en (7.1-0-1) ... Processing triggers for libc-bin (2.19-0ubuntu6.6) ... Processing triggers for dictionaries-common (1.20.5) ... root@host#
Next, we need to customize some of the RoundCube configuration files. First, we are going to add the RoundCube application into our current Apache configuration files using path alias directives. The default configuration file is installed at /etc/apache2/conf-available/roundcube.conf
nano /etc/apache2/conf-available/roundcube.conf
We now need to remove the two comment flags in front of the alias directives. If you would like to use a different alias name, you can change that here as well. The default alias will use the URL http://<your-server-url>/roundcube/
Alias /roundcube/program/js/tiny_mce/ /usr/share/tinymce/www/ Alias /roundcube /var/lib/roundcube
Once done, save and exit the file.
Now we are going to modify the /etc/roundcube/config.inc.php configuration file. This file is where you can customize the RoundCube advanced settings.
nano /etc/roundcube/config.inc.php
Locate the following directives and update the values to match the following.
$config['default_host'] = ''; $config['smtp_server'] = 'localhost'; $config['smtp_port'] = 25; $config['smtp_user'] = '%u'; $config['smtp_pass'] = '%p'; $config['support_url'] = '';
Once done, save and exit the configuration file.
Finally, restart the apache service to apply the changes:
systemctl restart apache2
You should now be able to use your new RoundCube webmail application for sending and receiving message.
Congratulations!
Install Mail Server On Ubuntu
Update Domain Record
This section provides the configurations required at the DNS record to continue installing the email server. Make sure that your domain record is configured as shown below.
A Record - An A Record exists having the hostname and IP address of your email server. The hostname of an email server should be similar to email.example.com.
Name Type Value TTL
mail.example.com. A xx.xxx.xxx.xxx 300
CNAME Records - Add CNAME records for Postfix Admin and RoundCube.
Name Type Value TTL
mailadmin.example.com. CNAME mail.example.com 300
webmail.example.com. CNAME mail.example.com 300
MX Record - The domain record must have an MX record as shown below.
Name Type Value TTL
mail.example.com. MX 0 xx.xxx.xxx.xxx 300
SPF Record - A text record to check authorized hosts to send an email for a domain. A generic SPF record should be similar as shown below.
Name Type Value TTL
mail.example.com. TXT "v=spf1 a mx -all" 300
PTR Record - A valid PTR record should exist. You may contact your hosting provider to configure an appropriate PTR record in case the control panel does not provide options to set the reverse domain for your email server IP address. On AWS, it can be done by submitting this form. We can also check the reverse DNS using the command dig as shown below.
# Dig
dig -x <your server ip> +short
# Example
dig -x xx.xxx.xxx.xxx +short
# Output
DMARC record - Add DMARC record as mentioned below.
Name Type Value TTL
_dmarc.mail.example.com. TXT "v=DMARC1;p=reject;pct=100;rua=mailto:postmaster@example.com" 300
Configure Hostname
This section provides the commands to configure the Hostname of the email server. The same hostname will be used by the Postfix and Dovecot. Now execute the below-mentioned commands to update the server hostname.
# Check Hostname
hostname
# Output
<current hostname>
# Update Hostname
sudo hostnamectl set-hostname mail.example.com
# Check Hostname
hostname
# Output
Also, update the hosts file as shown below. Make sure to replace the IP address and hostname using your server IP address and domain.
# Update Hosts
sudo nano /etc/hosts
# Update
127.0.0.1 localhost
xxx.xxx.xxx.xxx mail.example.com mail
-----
-----
# Save and exit the editor by pressing Ctrl + o -> Enter -> Ctrl + x
This completes the hostname configuration. You may reboot your server and again check the hostname. It must reflect the new hostname configured by you.
Install Postfix
This section provides the steps to install Postfix MTA on Ubuntu 20.04 LTS. Now execute the commands as shown below to install Postfix.
# Refresh Packages Index
sudo apt update
# Update to most recent Ubuntu 20.04 - make sure to backup your server before executing it
sudo apt dist-upgrade
# Autoclean
sudo apt autoclean
# Autoremove
sudo apt autoremove
# OR
sudo apt --purge autoremove
# Install PHP Packages
sudo apt install php7.4-curl php7.4-gd php7.4-mbstring php7.4-imap php7.4-xml php-apcu
# Install Additional Packages
sudo apt install zip unzip rar unrar
sudo apt install pyzor razor arj cabextract lzop nomarch p7zip-full rpm2cpio tnef unzip unrar-free zip bzip2 cpio file gzip pax
# Install Postfix
sudo apt install postfix postfix-mysql
sudo apt-get install postfix-policyd-spf-python
While installing Postfix, the installer asks to choose the configuration type as shown in Fig 1.
Fig 5
Fig 8
Hover the Domain List option on the Main Menu and click the New Domain option. Specify the domain name as example.com and click the Add Domain Button. It will add the virtual domain example.com.
Hover the Virtual List option on the Main Menu and click Add Mailbox option. Specify the username as admin, fill other details and click the Add Mailbox Button. It will add the virtual user admin@example.com. Similarly, add another mailbox netban@example.com as configured with Fail2ban to receive all the emails from it.
Notes: There is a known bug in PostfixAdmin as shown below.
Invalid query: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'row FROM `mailbox` LEFT JOIN `alias` ON `mailbox`.username=`alias`.address L' at line 2
In case you get the above error, it means you have already created 10 mailboxes for a domain. The workout is to increase the pagination size as shown below.
# Postfix Admin - Local Config
sudo nano /var/www/mailadmin.example.com/html/config.local.php
# Add configuration
-----
$CONF['create_mailbox_subdirs_prefix']='';
-----
$CONF['page_size'] = '1000';
-----
Configure DKIM
This section provides the steps to generate the DKIM signature for example.com. Though we can use DKIM for multiple domains, this section only provides the configurations for the single domain as shown below.
# Update OpenDKIM Conf
sudo nano /etc/opendkim.conf
# Add at the last
Domain example.com
KeyFile /etc/postfix/dkim.key
Selector dkim
Now generate the domain key as shown below.
cd /mydata/secure
sudo mkdir dkim
sudo opendkim-genkey -t -s dkim -d example.com
sudo mv dkim.private /etc/postfix/dkim.key
sudo chmod 660 /etc/postfix/dkim.key
sudo chown root:opendkim /etc/postfix/dkim.key
# Restart OpenDKIM
sudo service opendkim restart
# Reload and restart Postfix
sudo service postfix reload
sudo service postfix restart
We are also required to update the DNS record by adding the txt record as shown below.
# Read DKIM record
sudo cat dkim.txt
# Output
dkim._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; t=y; "
"p=KAABIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/fedRNEFQvCdtN0akUCMG686J7Kv7DfjP6CBNYbq0zppCF+gEnXmeRIAG1BNGtqE0DnpiOaePwXpuAC+izWHE4pBltSwczhTOz7dNHxQV3YmPs3pg12Zqm4ARuD9sCdJky/Tz+uPHUYp8GUuAJPOmqmg3lWw9AooPOYfJMLte5BeQ7KtSiyxirT5VfZdYj0VJXvvlIKT8X92OY"
"WN8G0212XiFLyyQuxJixQL04BMG0bvBW8xrNDiNuiAkDGea/nUxKRMnuVKOvAa5JAhi/hNikCOP9NCibllwZLlS2E94bY9FVw+ymbBt0f4MMn/Y2LBLfEhLZq0AAx0KXkpPpkWbQIDLSRP" ) ; ----- DKIM key dkim for example.com
Remove all the double quotes and generate a single line record as shown below.
# Valid DKIM
v=DKIM1;p=KAABIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/fedRNEFQvCdtN0akUCMG686J7Kv7DfjP6CBNYbq0zppCF+gEnXmeRIAG1BNGtqE0DnpiOaePwXpuAC+izWHE4pBltSwczhTOz7dNHxQV3YmPs3pg12Zqm4ARuD9sCdJky/Tz+uPHUYp8GUuAJPOmqmg3lWw9AooPOYfJMLte5BeQ7KtSiyxirT5VfZdYj0VJXvvlIKT8X92OYWN8G0212XiFLyyQuxJixQL04BMG0bvBW8xrNDiNuiAkDGea/nUxKRMnuVKOvAa5JAhi/hNikCOP9NCibllwZLlS2E94bY9FVw+ymbBt0f4MMn/Y2LBLfEhLZq0AAx0KXkpPpkWbQIDLSRP
Add a TXT record as shown below.
Name Type Value TTL
dkim._domainkey.example.com. TXT "single line record" 300
This completes the DKIM configuration for example.com. Now we will verify the DKIM record using the keycheck utility. Paste your DKIM record to the Key record textarea and click the Check Button. It should successfully verify your DKIM record as shown in Fig 9.
Fig 7
Fill the superadmin account form by providing the Setup password, admin email, and admin password. The admin email could be admin@example.com. After filling the form, click the Add Admin Button to create the super admin. Also, log in to Postfix Admin by using the URL - https://mailadmin.example.com/login.php. It shows the dashboard as shown in Fig 8.
Fig 6
Now provided the Setup password as shown in Fig 6 and click the Generate password hash button. It will generate the password hash and provide the configuration option as shown below.
$CONF['setup_password'] = 'a115c57a6d1d42b32dbb7dc57335c9f6:926c3682w5b3f2bb72aaf3cc4f86b567c17ae8ok';
Now copy the configuration line and add it to the end of the local config file - /var/www/mailadmin.example.com/html/config.local.php. It also provides the options to configure the superadmin account as shown in Fig 7.
Fig 9
Check Email Server Health
This section provides the steps to check the emails and also check the email server health using the standard services.
DKIM Test - We can perform the DKIM testing using DKIM Test. Login to your Postfix Admin and Hover the Send Email option on the Main Menu and click Send Email option. It will show the form to send an email. Now click the Next Step Button after opening the DKIM Test webpage. It will generate the endpoint to receive the email. Now send an email to this endpoint using the Postfix Admin - Send Email form. It should successfully pass the DKIM test as shown in Fig 10.
Fig 10
Now send an email to Gmail and check the Mailed By and Signed By parameters as shown in Fig 11.
Fig 12
Install RoundCube
In the previous sections, we have installed the software and tools required to complete the set up of an email server on Ubuntu 20.04 LTS using Postfix and Dovecot. We have also installed the mail admin to manage the virtual domains and users. Apart from all these software and tools, we also need an interface so that the email users can access their emails and send emails. This section provides the steps to install the popular web interface i.e. RoundCube on Ubuntu 20.04 LTS. The below-mentioned steps are required to install RoundCube on Ubuntu. We can also download RoundCube from the Official Website.
# Download RoundCube
# Extract RoundCube
sudo tar xvfz roundcubemail-1.4.6-complete.tar.gz
# Install RoundCube
sudo mkdir /var/www/webmail.example.com/
sudo mv roundcubemail-1.4.6 /var/www/webmail.example.com/html
sudo chown -R www-data:www-data /var/www/webmail.example.com/html
The above-mentioned commands installed RoundCube at /var/www/webmail.example.com/html. Now add the virtual hosts as shown below.
# Virtual Host - HTTP
sudo nano /etc/apache2/sites-available/webmail.example.com.conf
# Content
<VirtualHost *:80>
ServerName webmail.example.com
ServerAlias webmail.example.com
ServerAdmin admin@example.com
DocumentRoot /data/www/webmail.example.com/html
<Directory /data/www/webmail.example.com/html>
Options -Indexes +FollowSymLinks
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =webmail.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
In case you have used Let's Encrypt to install an SSL certificate, you can update your certificate by adding the webmail subdomain as shown below. It will also generate and enable the virtual host for SSL.
# Upgrade SSL Certificate
sudo letsencrypt --apache -d example.com,www.example.com,mail.example.com,mailadmin.example.com,webmail.example.com --email admin@example.com --agree-tos
# Output
-----
Do you want to expand and replace this existing certificate with the new
certificate?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(E)xpand/(C)ancel: e
-----
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
-----
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.com/privkey.pem
-----
You can also add the virtual host for SSL, in case you have generated a self-signed certificate or obtained the SSL certificate from the well-known providers. The virtual host for SSL should be similar as shown below.
# Virtual Host - HTTPS
sudo nano /etc/apache2/sites-available/webmail.example.com-le-ssl.conf
# Content
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName webmail.example.com
ServerAlias webmail.example.com
ServerAdmin admin@example.com
DocumentRoot /data/www/webmail.example.com/html
<Directory /data/www/webmail.example.com/html>
Options -Indexes +FollowSymLinks
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Now we will configure RoundCube and test the login mechanism. Create the RoundCube database as shown below.
# Create User
CREATE USER 'roundcube'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'rcpassword';
# Create Database
CREATE DATABASE roundcube CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
# Privileges
GRANT ALL PRIVILEGES ON roundcube.* TO 'roundcube'@'localhost';
FLUSH PRIVILEGES;
We can access RoundCube using the URL - https://webmail.example.com/installer. It makes several checks as shown in Fig 13.
Fig 11
This ensures that your emails are properly signed by your domain.
MXToolbox Test - Open MX Lookup Page, provide your domain name, and click MX Lookup Button. It will perform MX lookup and shows the MX record details. Now click the Find Problems Button. It will show the problems associated with your email server. You may further fine-tune your email server in case errors or warnings are listed by MXToolbox.
ESG Web Tool - Similar to MXToolbox, we can also use ESG Web Tool to check the Mail Server health. The ESG report of the email server setup done while writing this tutorial is shown in Fig 12.
Fig 14
Fig 13
Now click the NEXT Button to continue with the installation. The next page provides several options to configure RoundCube including the name and logo to be displayed on the web interface. It also provides the configuration options to configure the roundcube database created by us. Configure IMAP and SMTP as shown in Fig 14 and Fig 15.
Fig 15
Also, enable the plugins required by your RoundCube installation. I recommend having at least three plugins including archive, attachment_reminder, password. Now click the CREATE CONFIG Button to generate the configuration file. It will show the configuration path as shown in Fig 16.
Fig 16
Click the CONTINUE Button to initialize the RoundCube database and test the connectivity. Click the Initialize Database button to initialize the RoundCube database. It initializes the database as shown in Fig 17.
Fig 17
Now try to send an email as shown in Fig 18. It should show the status OK.
Fig 18
Also, try to log in. It should show the OK message as shown in Fig 19.
Fig 20
This completes the installation of RoundCube on Ubuntu 20.04 LTS.
Summary
This tutorial provided all the steps and configurations required to set up and secure an email or mail server on Ubuntu 20.04 LTS using Postfix and Dovecot. It also provided the steps to install and configure the additional software, tools, and utilities including Clam as Antivirus, Amavis for Content Filter, SpamAssassin to detect spam emails, OpenDKIM, Postfix Admin, and Roundcube. It also provided the steps to configure Fail2ban and Monit for Postfix and Roundcube.
--
Fig 19
In case you have enabled the password plugin, it can be configured as shown below.
# Mode to Password plugin
cd /var/www/webmail.example.com/site/plugins/password
# Copy config
sudo cp config.inc.php.dist config.inc.php
# Update Config
sudo nano config.inc.php
# Update
-----
$config['password_minimum_length'] = 8;
-----
$config['password_minimum_score'] = 3;
-----
$config['password_force_save'] = true;
-----
// Refer - $config['db_dsnw'] - /var/www/webmail.example.com/html/config/config.inc.php
$config['password_db_dsn'] = 'dsn from main config';
-----
$config['password_query'] = "UPDATE `mailbox` SET `password`= %c, modified=now() WHERE `username` = %u LIMIT 1";
-----
After configuring the password plugin, the virtual users can change their password from RoundCube. Now remove the installer folder from the RoundCube root, else disable installer by updating the main config file as shown below.
# Update Config
sudo nano /var/www/webmail.example.com/html/config/config.inc.php
# Add configuration
$config['enable_installer' ] = false;
# Save and exit the editor
Now login to RoundCube using the URL - https://webmail.example.com. It should log in and shows the dashboard as shown in Fig 20.