Hosting your own email server is probably one of the most challenging things to set up. Sending a send-only email server is easy, but receiving emails and setting up mailboxes and client access is very difficult. It is necessary to configure multiple pieces and integrate them together properly to have a proper functioning Email Server. I personally tried to do it on my own (more on that later), but why reinvent the wheel? Today, we will use Mailcow to create a fully functioning email server!
What is Mailcow?
Mailcow is a fully automated piece of software which installs a fully functional mail server on your machine. I personally feel that Mailcow is one of the best options to install a fully functioning mail server. Mailcow makes use of dockers, which makes it very portable (unlike Mail-in-a-box, which is limited to Ubuntu 14.04). If you are unfamiliar with dockers, they are basically a way to package applications in containers, and these containers share the same Operating System. This is similar to how VMs share the same resources as their host using a hypervisor. Mailcow comes with an excellent web-based administration tool, but an nice-ish(my opinion) web-based client email access tool. Mailcow requires minimal configuration, and is a very quick install.
Step-by-step guide
Requirements:
I am using a fresh install of Ubuntu Server 16.04. I recommend atleast 2GB of RAM (4 if possible). If using a VM, use atleast 2 vCPUs, or atleast 1 GHz of processing power for acutal computers. Make sure to have atleast 25 GB of free space for the install and subsequent data. Your system architecture must be x86_64.
Check your ports using the following command:
sudo netstat -tulpn | grep -E -w '25|80|110|143|443|465|587|993|995'
If the command results in any programs, shut those programs down! It is okay if port 80 and 443 is occupied by an existing web server if you intend to reverse proxy to the Mailcow Web UI using this mail server.
-
First you need to install Docker on your system, and enable it
sudo apt-get install curl -y curl -sSL https://get.docker.com/ | CHANNEL=stable sh systemctl enable docker.service systemctl start docker.service
-
Next, install Docker-Compose on your system
curl -L https://github.com/docker/compose/releases/download/$(curl -Ls https://www.servercow.de/docker-compose/latest.php)/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose
-
Next, clone the mailcow repository
sudo umask 0022 cd /opt git clone https://github.com/mailcow/mailcow-dockerized cd mailcow-dockerized
-
Next, generate the configuration file using
./generate_config.sh
. Use your fully-qualified domain when asked -
You can change the
mailcow.conf
file to edit the paramters.- If you intend to reverse proxy to the Mailcow web server using the existing web server on the system (guide to reverse-proxy below), you may want to change the
HTTP_PORT
andHTTPS_PORT
parameters to different, unused ports. Also changeSKIP_LETS_ENCRYPT=y
for reverse proxying (Not necessary, but recommended). - I also recommend changing
SYSCTL_IPV6_DISABLED=1
if you don't intend to use IPv6. - Change
SKIP_CLAMD=y
if you have RAM contraints. ClamAV can be a RAM hog.
- If you intend to reverse proxy to the Mailcow web server using the existing web server on the system (guide to reverse-proxy below), you may want to change the
-
Next, start all the dockers!
cd /opt/mailcow-dockerized sudo docker-compose pull sudo docker-compose up -d
You should now be able to access the web administration page at https://<domain-name>
with default credentials admin
and password moohoo
. But wait, even the easiest mail servers need some extra work!
Ubuntu Firewall configuration
You can find a list of required ports here and what they do. If your Ubuntu machine has multiple IPs, you may want to bind your services to a particular IP based on the guide to the link. My assumption is that your machine is behind a router/firewall, and you are port forwarding to the ports you are about to open. You can obviously disable Ubuntu Firewall via sudo ufw stop
and sudo ufw disable
, if you control and own the entire network behind the firewall. Configuring Ubuntu Firewall is extremely important if you machine has a public IP.
ufw allow 25
ufw allow 80
ufw allow 110
ufw allow 143
ufw allow 443
ufw allow 465
ufw allow 587
ufw allow 993
ufw allow 995
ufw allow 22
DNS configuration
This is probably one of the most important aspects of configuring an email-server. Without proper DNS configuration, other SMTP servers may reject emails from your servers, or may not be able to deliver emails to your server. It might be beneficial to use a DNS service like Cloudflare to manage the DNS of your domain. While I am listing the DNS records as they would be inserted into a BIND zone file, you can use the data to enter it to any other DNS provider that you have.
First, add the A records for the domain you used for your mail server (I am using mail as an example):
mail IN A <Your IP>
Next, you should add 2 CNAME records that point to your mail
A record:
autodiscover IN CNAME mail
autoconfig IN CNAME mail
Now, add the MX record for your domain:
@ IN MX 10 mail
Next, add the SPF record to your DNS, which ensures that only the servers with the IP of your MX records are allowed to send emails for your domain:
@ IN TXT "v=spf1 mx ~all"
Next, add the DKIM TXT record to your DNS. To get the value of this TXT record, you need to access the Mailcow administration UI and get the key. To generate the key, log into the Mailcow UI, go to Configuration
-> ARC/DKIM keys
. Next, generate a key for your domain. (Note: you may need to first add the domain by going to the Configuration
menu at the top -> Mailboxes
-> Domains
tab)
After generation, the key should look like something below:
Add that value to the DNS:
dkim._domainkey IN TXT "value-from-UI"
Last, add the DMARC record which ensures and reassures the servers receiving emails from your domain that the email did in fact come from your server. This is a great way to combat scammers and phishers who may use your domain to spoof emails. DMARC ensures that if both the SPF and DKIM checks fail, the server on the other hand rejects or quaratines that email. Here's a neat diagram which explains how DMARC works:
Source
Here's the DNS record:
_dmarc IN TXT v=DMARC1; p=reject; rua=mailto:<email-to-mail-reports-to>
Obviously, add the email where you want stats. Also, you can change the reject to quarantine if you want the server at the other end to only quarantine the email to the spam folder.
Last, you can add the following DNS records for advanced configuration. I recommend doing this. Again, email servers are complicated!
_imap._tcp IN SRV 0 1 143 mail.example.org.
_imaps._tcp IN SRV 0 1 993 mail.example.org.
_pop3._tcp IN SRV 0 1 110 mail.example.org.
_pop3s._tcp IN SRV 0 1 995 mail.example.org.
_submission._tcp IN SRV 0 1 587 mail.example.org.
_smtps._tcp IN SRV 0 1 465 mail.example.org.
_sieve._tcp IN SRV 0 1 4190 mail.example.org.
_autodiscover._tcp IN SRV 0 1 443 mail.example.org.
_carddavs._tcp IN SRV 0 1 443 mail.example.org.
_carddavs._tcp IN TXT "path=/SOGo/dav/"
_caldavs._tcp IN SRV 0 1 443 mail.example.org.
_caldavs._tcp IN TXT "path=/SOGo/dav/"
Domain and Mailbox configuration
Finally, you start setting up domains that you want to manage, and mailboxes.
- Go to
Configuration
menu at the top ->Mailboxes
- Add all the domains that you want to manage (and make sure you have appropriate DNS records for all of them as detailed above)
- Create Mailboxes for each email ID you want to manage!
You can do all sorts of fun things and tinker with quotas, settings, and more! I will let you guys figure that one out!
You access the webmail client, you can go to Apps
menu at top -> SOGo
. There is also a link for this webmail client on the default Mailcow page, right below the login fields. The SOGo
email client looks something like this:
I am not the biggest fan of SOGo interface, as it can sometimes be slightly laggy, but on the other hand, it integrates address books and calendars into one easy interface, which is a HUGE plus! You can even mark certain emails as Spam or not-Spam through this client. Overall, it fits the bill VERY WELL. I may have just convinced myself to change my own opinion about the interface :P .
Few nice things about Mailcow:
- Regular users can also log into the Mailcow UI to change passwords, and add temporary email aliases (for junk email)
- Check out the Rspamd web interface, which is located in
Configuration
->Debug
->Rspamd
. The debug menu is also where you find all the logs. - To shut down mailcow, just do
cd /opt/mailcow-dockerized
, andsudo docker-compose down
, and that should shut down all the dockers. To start, usesudo docker-compose up -d
- To update Mailcow, just go to the folder using
cd /opt/mailcow-dockerized
, and dosudo ./update.sh
. To simply check, usesudo ./update.sh --check
. If you made any changes to the mailcow repository that you want to prevent from being overwritten during update, you can do./update.sh --ours
. For overwrites, use./update.sh --theirs
- Client configurations for various devices and apps can be accessed in the Mailcow UI
Reverse-proxy guide
I am only writing example configurations from Apache. You can probably find equivalent configuration for Nginx and other web servers online. Why is reverse-proxying useful? With reverse proxying, you can have a single web server facing the outside world on a public IP which reverse proxies to the internal network for all the services (One IP mo' problems amirite?). You can also offload all the SSL stuff on your front-end machine, which only using less processing intensive HTTP on the internal network. Reverse-proxying is also an excellent way of load-balancing services over multiple internal web servers. A reverse-proxy front-end can also act as a cache in front of the actual web server to accelerate most-accessed content.
Add a VirtualHost configuration in your Apache configuration to handle all the HTTP traffic:
<VirtualHost *:80>
ServerName <domain-name>
ServerAlias <alternate-domain-name>
ServerAdmin <your-actual-email>
Redirect permanent / https://<domain-name>/
ErrorLog ${APACHE_LOG_DIR}/error-http.log
CustomLog ${APACHE_LOG_DIR}/access-http.log combined
</VirtualHost>
Here is a sample VirtualHost config for all incoming HTTPS connections:
<VirtualHost *:443>
ServerName <domain-name>
ServerAlias <alternate-domain-name>
ServerAdmin <your-actual-email>
ProxyPreserveHost On
ProxyPass "/" "http://<IP>:<port>/"
ProxyPassReverse "/" "http://<IP>:<port>/"
ErrorLog ${APACHE_LOG_DIR}/error-ssl.log
CustomLog ${APACHE_LOG_DIR}/access-ssl.log combined
SSLEngine On
#Uncomment the line below if using Let's Encrypt
#Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile <Path-To-Certificate>
SSLCertificateKeyFile <Path-To-Private-Key>
</VirtualHost>
That's it for the reverse proxy!
Enjoy your functioning Mail Server! You deserve it after the hard work!