How to Build Email Server with Exim on Alma Linux 9

How to Build Email Server with Exim on Alma Linux 9

Cloud Provider Consideration

Before we continue, be mindful when choosing the cloud provider in which your email server will be launched. Not all cloud providers open the email-sending port, e.g., 25, hence blocking your email-sending capabilities. You will need to request them to open the port, and they will ask for some information before they can approve your request. Some providers I have known like these close their email-sending port:

Digital Ocean
Vultr
Linode
AWS

You can host your email server at Contabo or Kamatera or even build it on your on-premise server.

Server Consideration

Installing from a new server is highly recommended, as it will avoid any unnecessary dependency conflict.

Screen Installation

First, we will install the screen package. The package is helpful if we get disconnected during the build session, we can reconnect to the session and continue what we left off.

sudo dnf install -y epel-release
sudo dnf install -y screen

Now, start a screen session.

screen -U -S email-server-build

Later, when you get disconnected from the ssh session, run this command to resume the session:

screen -R

To list active screen sessions, run this command:

screen -ls

To terminate current screen session, run:

exit

Setup Hostname

We will set up a hostname to identify the server uniquely.

hostnamectl set-hostname <server_name>

For example:

hostnamectl set-hostname mail.domain.com

Then, verify the change by running this command:

hostname

The output should look like this:

mail.domain.com

Next, update the hosts file:

vim /etc/hosts

Change an entry like this:

x.x.x.x vmi123456.server.net vmi123456

Note that, x.x.x.x is the server’s IP address.
To this:

x.x.x.x vmi123456.server.net vmi123456 mail.domain.com

Reboot the server to apply the changes.

shutdown -r now

System Update and Dependencies Installation

We need to update the existing packages.

sudo dnf update

Then, install vim as our text editor. You can install your own preferred text editor, e.g. nano. And, install tar and socat as they are required by acme.sh.

sudo dnf install vim tar socat -y

Acme.sh Installation

Next, we will install acme.sh, a command-line tool for managing SSL/TLS certificates. I prefer acme.sh over certbot, as it does not depend on the OS version. For more details about acme.sh, check its GitHub repo here.

Next, install acme.sh.

curl https://get.acme.sh | sh -s email=my@example.com

Note that change my@example.com accordingly.
Create an alias for the acme.sh command so we can run acme.sh directly without specifying its full path.

echo ‘alias acme.sh=”/root/.acme.sh/acme.sh”‘ >> ~/.bash_aliases
source ~/.bash_aliases

Before we issue an SSL certificate, we must configure the DNS record properly. I will use mail.domain.com in this tutorial, and its A and MX records has already been configured. Refer to the DNS Record Configuration section at the end of this article to get more details.

After that, let us start issuing a staging SSL certificate. This certificate cannot be used on production servers and is used primarily to test certificate generation. Note that generating a live LetsEncrypt certificate is limited to 50 per week, for more info check this documentation. If it works, we can continue issuing a live SSL certificate.

Before we issue the SSL certificate, let us create a folder to store the generated certificates.

mkdir -p /etc/pki/tls/certs/staging
mkdir -p /etc/pki/tls/certs/live

To issue a staging SSL certificate, run this command:

acme.sh –issue
-d “mail.domain.com”
–cert-home /etc/pki/tls/certs/staging
–standalone
–debug
–staging

Some notes:

-d: the domain name we want to issue the certificate for

–cert-home: the folder path where we want the generated certificate files to be stored.

–standalone: this assumes we do not have a web server capable of serving web files, e.g. apache or nginx

debug: display all information. Useful for tracing issues

staging: generate a staging certificate.

If things go well, you will see an output like this:

[Sun Mar 24 04:08:19 UTC 2024] Your cert is in: /etc/pki/tls/certs/staging/mail.domain.com_ecc/mail.domain.com.cer
[Sun Mar 24 04:08:19 UTC 2024] Your cert key is in: /etc/pki/tls/certs/staging/mail.domain.com_ecc/mail.domain.com.key
[Sun Mar 24 04:08:19 UTC 2024] The intermediate CA cert is in: /etc/pki/tls/certs/staging/mail.domain.com_ecc/ca.cer
[Sun Mar 24 04:08:19 UTC 2024] And the full chain certs is there: /etc/pki/tls/certs/staging/mail.domain.com_ecc/fullchain.cer
[Sun Mar 24 04:08:19 UTC 2024] _on_issue_success

Now, let us issue a live certificate:

acme.sh –issue
-d “mail.domain.com”
–cert-home /etc/pki/tls/certs/live
–standalone
–debug

This time we removed the –staging parameter, and changed the certificate home folder.

The output will look like this:

[Sun Mar 24 04:35:12 UTC 2024] Your cert is in: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/mail.mail.domain.com.cer
[Sun Mar 24 04:35:12 UTC 2024] Your cert key is in: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/mail.mail.domain.com.key
[Sun Mar 24 04:35:12 UTC 2024] The intermediate CA cert is in: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/ca.cer
[Sun Mar 24 04:35:12 UTC 2024] And the full chain certs is there: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/fullchain.cer
[Sun Mar 24 04:35:12 UTC 2024] _on_issue_success

Now, we need to change the future SSL generation configured via crontab. Run this command:

EDITOR=vim crontab -e

Replace the following cron:

11 16 * * * “/root/.acme.sh”/acme.sh –cron –home “/root/.acme.sh” > /dev/null

With:

11 16 * * * /root/.acme.sh/acme.sh –cron –home /root/.acme.sh –cert-home /etc/pki/tls/certs/live –standalone > /dev/null

Configure Firewall

We will use firewalld to protect our email server. First, install the firewalld package.

sudo dnf install -y firewalld

Then, enable and start firewalld on server startup.

sudo systemctl enable firewalld
sudo systemctl start firewalld

Now, configure firewall rules.

sudo firewall-cmd –zone=public –permanent –add-service=http
sudo firewall-cmd –zone=public –permanent –add-service=https
sudo firewall-cmd –zone=public –add-service=pop3 –permanent
sudo firewall-cmd –zone=public –add-service=pop3s –permanent
sudo firewall-cmd –zone=public –add-service=smtp –permanent
sudo firewall-cmd –zone=public –add-service=smtps –permanent
sudo firewall-cmd –zone=public –add-service=imap –permanent
sudo firewall-cmd –zone=public –add-service=imaps –permanent
sudo firewall-cmd –reload

Validate the result by checking the configured firewall rules.

sudo firewall-cmd –zone=public –list-all

The output should look like this:

Exim Installation and Configuration

We will install Exim, a mail transfer agent used to deliver and receive emails.

sudo dnf install -y exim

Before configuring exim, we need to back up the existing config file.

cp -p /etc/exim/exim.conf{,.orig}

This will copy exim.conf to exim.conf.orig.

After that, we can safely configure exim.

vim /etc/exim/exim.conf

Adjust the existing exim configuration so they look like these:

primary_hostname = mail.domain.com
domainlist local_domains = @ : domain.com
tls_advertise_hosts = *
tls_certificate = /etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.cer
tls_privatekey = /etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.key
auth_advertise_hosts = *

Next, find ROUTERS CONFIGURATION section, and then find localuser: block.

Adjust the whole block so it will look like these:

localuser:
driver = redirect
check_local_user
file_transport = local_delivery
reply_transport = local_delivery_autoreply
data = /home/${local_part_data}/Maildir

Next, find the TRANSPORTS CONFIGURATION section and then find local_delivery: block.

Adjust the whole block so it will look like this:

local_delivery:
driver = appendfile
directory = $home/Maildir
maildir_format
maildir_use_size_file
delivery_date_add
envelope_to_add
return_path_add

And add this block right after the local_delivery: block.

local_delivery_autoreply:
driver = autoreply
headers = Content-Type: text/plain; charset=utf-8nContent-Transfer-Encoding: base64
to = ${sender_address}
from = ${$local_part}@${$domain}
debug_print = “T: auto reply for $local_part@$domain”
once_file_size = 500K
log = /var/log/exim/sieve_autoreply.log

The autoreply transport will generate a new email message as an automatic reply to the incoming message. It is useful to generate an automatic email when we are on a vacation or out-of-office. We will utilize this later in Roundcube. For more details on autoreply, refer to the doc here.

Next, find AUTHENTICATION CONFIGURATION section.

Then, add these blocks at the end of the section.

dovecot_login:
driver = dovecot
public_name = LOGIN
server_socket = /var/run/dovecot/auth-client
server_set_id = $auth1

dovecot_plain:
driver = dovecot
public_name = PLAIN
server_socket = /var/run/dovecot/auth-client
server_set_id = $auth1

Save all the changes and then quit.

Start exim service, and automatically start the service on server startup.

sudo systemctl start exim
sudo systemctl enable exim
sudo systemctl status exim

Test the local_delivery transport and ensure there is no warning or error message.

exim -d+all -bP transport local_delivery

Next, change the certificate folder’s ownership so that Exim will be able to access the certificates later.

chown -R exim:exim /etc/pki/tls/certs/staging
chown -R exim:exim /etc/pki/tls/certs/live

Dovecot Installation and Configuration

We will use dovecot, an open-source IMAP and POP3 server. It takes responsibility for connecting your email client (Thunderbird, etc.) to your mail box.

Run this command to install dovecot.

sudo dnf install -y dovecot

SSL Configuration

Configure SSL in dovecot.

vim /etc/dovecot/conf.d/10-ssl.conf

Then adjust the existing config to this:

ssl = yes
ssl_cert = </etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.cer
ssl_key = </etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.key

Note that, ensure the file paths are prefixed by <. Otherwise, it will trigger an error.

Plain Authentication

Allow plain authentication in dovecot.

vim /etc/dovecot/conf.d/10-auth.conf

Adjust the existing config.

disable_plaintext_auth = no
auth_mechanisms = plain login

Mailbox Location

Configure mailbox location.

vim /etc/dovecot/conf.d/10-mail.conf

Adjust the existing config.

mail_location = maildir:~/Maildir

Allow Exim to Authenticate

Set up dovecot to allow Exim to use its authentication system.

vim /etc/dovecot/conf.d/10-master.conf

Find the unix_listener auth-userdb block.


Then, fully comment the block, and add this block beneath it.

unix_listener auth-client {
mode = 0660
user = exim
}

The final changes should look like this:

Start dovecot service, and automatically start the service on server startup.

sudo systemctl start dovecot
sudo systemctl enable dovecot
sudo systemctl status dovecot

Create an Email Address

We will create an email address, say email-test@domain.com.

useradd -m email-test

Set its password.

passwd email-test

Create info user (optional).

useradd -m info
passwd info

Note that, when sending an email to info@domain.com, you might encounter a problem, this is because info@domain.com is considered a root user. To fix the issue, remove it from the aliases list.

vim /etc/aliases

Then, comment this line by prefixing the line with #.

# info: postmaster

Test the email user routing, and ensure there is no error or warning message.

exim -bt email-test@domain.com

The output should look like this:

email-test@domain.com -> /home/email-test/Maildir
transport = local_delivery

And the other user.

exim -bt info@domain.com

The output should look like this:

info@domain.com -> /home/info/Maildir
transport = local_delivery

DNS Record Configuration

Before we can send and receive emails, ensure to have these records on your DNS Control Panel:
A record:

Change 1.2.3.4 with the IP Address of your email server.

MX record:

The MX record indicates it will point to your email server.

Leave a Reply

Your email address will not be published. Required fields are marked *