DEV Community

budiantoip
budiantoip

Posted on • Edited on

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


Enter fullscreen mode Exit fullscreen mode

Now, start a screen session.



screen -U -S email-server-build


Enter fullscreen mode Exit fullscreen mode

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



screen -R


Enter fullscreen mode Exit fullscreen mode

To list active screen sessions, run this command:



screen -ls


Enter fullscreen mode Exit fullscreen mode

To terminate current screen session, run:



exit


Enter fullscreen mode Exit fullscreen mode

Setup Hostname

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



hostnamectl set-hostname <server_name>


Enter fullscreen mode Exit fullscreen mode

For example:



hostnamectl set-hostname mail.domain.com


Enter fullscreen mode Exit fullscreen mode

Then, verify the change by running this command:



hostname


Enter fullscreen mode Exit fullscreen mode

The output should look like this:



mail.domain.com


Enter fullscreen mode Exit fullscreen mode

Next, update the hosts file:



vim /etc/hosts


Enter fullscreen mode Exit fullscreen mode

Change an entry like this:



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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Reboot the server to apply the changes.



shutdown -r now


Enter fullscreen mode Exit fullscreen mode

System Update and Dependencies Installation

We need to update the existing packages.



sudo dnf update


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Now, let us issue a live certificate:



acme.sh --issue \
    -d "mail.domain.com" \
    --cert-home /etc/pki/tls/certs/live \
    --standalone \
    --debug


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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



EDITOR=vim crontab -e


Enter fullscreen mode Exit fullscreen mode

Replace the following cron:



11 16 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null


Enter fullscreen mode Exit fullscreen mode

With:



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


Enter fullscreen mode Exit fullscreen mode

Configure Firewall

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



sudo dnf install -y firewalld


Enter fullscreen mode Exit fullscreen mode

Then, enable and start firewalld on server startup.



sudo systemctl enable firewalld
sudo systemctl start firewalld


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Validate the result by checking the configured firewall rules.



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


Enter fullscreen mode Exit fullscreen mode

The output should look like this:

Firewall Rule List

Exim Installation and Configuration

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



sudo dnf install -y exim


Enter fullscreen mode Exit fullscreen mode

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



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


Enter fullscreen mode Exit fullscreen mode

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

After that, we can safely configure exim.



vim /etc/exim/exim.conf


Enter fullscreen mode Exit fullscreen mode

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 = *


Enter fullscreen mode Exit fullscreen mode

Next, find ROUTERS CONFIGURATION section, and then find localuser: block.
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


Enter fullscreen mode Exit fullscreen mode

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

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


Enter fullscreen mode Exit fullscreen mode

And add this block right after the local_delivery: block.



local_delivery_autoreply:
   driver = autoreply
   headers = Content-Type: text/plain; charset=utf-8\nContent-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



Enter fullscreen mode Exit fullscreen mode

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.

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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



exim -d+all -bP transport local_delivery


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

SSL Configuration

Configure SSL in dovecot.



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


Enter fullscreen mode Exit fullscreen mode

Then adjust the existing config to this:



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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Adjust the existing config.



disable_plaintext_auth = no
auth_mechanisms = plain login


Enter fullscreen mode Exit fullscreen mode

Mailbox Location

Configure mailbox location.



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


Enter fullscreen mode Exit fullscreen mode

Adjust the existing config.



mail_location = maildir:~/Maildir


Enter fullscreen mode Exit fullscreen mode

Allow Exim to Authenticate

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



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


Enter fullscreen mode Exit fullscreen mode

Find the unix_listener auth-userdb block.

unix_listener auth-userdb block
Then, fully comment the block, and add this block beneath it.



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


Enter fullscreen mode Exit fullscreen mode

The final changes should look like this:

unix_listener auth-client

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



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


Enter fullscreen mode Exit fullscreen mode

Create an Email Address

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



useradd -m email-test


Enter fullscreen mode Exit fullscreen mode

Set its password.



passwd email-test


Enter fullscreen mode Exit fullscreen mode

Create info user (optional).



useradd -m info
passwd info


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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



# info:          postmaster


Enter fullscreen mode Exit fullscreen mode

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



exim -bt email-test@domain.com


Enter fullscreen mode Exit fullscreen mode

The output should look like this:



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


Enter fullscreen mode Exit fullscreen mode

And the other user.



exim -bt info@domain.com


Enter fullscreen mode Exit fullscreen mode

The output should look like this:



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

Enter fullscreen mode Exit fullscreen mode




DNS Record Configuration

Before we can send and receive emails, ensure to have these records on your DNS Control Panel:
A record:
A Record
Change 1.2.3.4 with the IP Address of your email server.

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

Top comments (4)

Collapse
 
khnaz35 profile image
Ali

Great job! What about setting it up for multiple domains on the same server?

Collapse
 
budiantoip profile image
budiantoip

My apologies for the late reply. I've been busy with work lately. I haven't tried it yet. But, you can try to change the domainlist and transport configurations. I'll try to write an article about this someday.

Collapse
 
khnaz35 profile image
Ali

can you send me email or share your mail so i can share more details khnaz35 (@) gmail.com

Collapse
 
khnaz35 profile image
Ali

Sure, will wait to see that day :)