Take control of your e-mail

When it’s time to talk about regaining control of personal data, e-mail are on the top of my list.

I have never trusted Google to deal with my data (my photos, my e-mail, or my documents). Even if I admit Gmail offer a very convenient service and a wonderful anti-spam (thanks to all the data shared by 1.5 billion active users and their 10 millions of spam and malicious emails received every minute).

This guide will help you to recover control of your e-mail.

When your business relies on digital exchanges, your e-mail provider must be very reliable. A chance that the Simple Mail Transfer Protocol is robust, allowing your precious e-mail to be retransmitted in case of outage of a gateway. In fact, a gateway could be off-line during days before the e-mail would be returned to its sender.

By the time, in addition to SMTP, other protocols and standards has been added to provide a complete e-mail service:

  • IMAP (used by your client to retrieve e-mail from the server)
  • TLS/SSL (for security and privacy)
  • SPF, DKIM and DMARC (to authenticate senders and fight against phishing and spam)
  • Sieve (to define filtering rules)

Hey! I don’t want to build a rocket. I just need an e-mail service that respect my privacy.

Answer is simple: rely on a service provided by a recognized European entity (respecting GDPR, which is normally mandatory). In short, you can trust OVHcloud e-mail solutions.

Let’s do it!

For fun or if your needs are a bit specific, you can also do it yourself.

In my all life, I have built 3 times a complete e-mailing system for my personal use. Obsolescence of the underlying Debian system, and therefore security, was the main driver. This last time, I defined these requirements:

  • Operating System abstraction (ie I can easily upgrade/change the OS without risking a major impact on the e-mail application stack)
  • Sustainable Open-Source community supporting the entire stack
  • Hardware abstraction

Docker to the rescue

Looking for a stateless e-mail stack, I have rapidly identified docker-mailserver as a good candidate. Anti-spam is based on SpamAssassin (a personal choice based on my experience) and configuration is very simple (no web interface, no additional dabatase, KISS)).
If docker-mailserver does not fit you, have a look at those alternatives: mailcow or Mailu.

This (almost) stateless approach enables to easily upgrade or downgrade the VM (vertical scaling).

Requirements

Basic configuration

1 CPU
2 GB RAM + Swap (or 3 GB if you don’t want to use swap)
8 GB Storage for System and Container (don’t forget to add the Swap size if you need it)
+ Storage for e-mail accounts

ClamAV is memory consuming (more than 800MB for the virus signature database). If you don’t run ClamAV (for example if you use another ant-virus or gateway), you should be able to run with 512MB of RAM.

Advanced configuration

For e-mail accounts storage, my first thought was to use Object Storage but I was not able to find any Open-Source IMAP server. Then I have decided to go with a scalalable Block Storage solution (like Ceph-based OVH Block Storage).

For SMTP output, IP reputation is very important. Default VM’s IP does not seem to be a convenient choice. My preference goes to ‘Static’ IP (like an OVH Fail-Over IP). Another advantage is I could decide to replace the VM while keeping the same IP.

Step by step, using OpenStack-based OVH Public Cloud

I assume a new Public Cloud Project has been created, and you have downloaded the OpenRC environment file.
First, load the environment: source openrc.sh.

1. Instanciate a VM

If needed, push your SSH public key to OpenStack region openstack keypair create --public-key ~/.ssh/id_rsa.pub mykey

We can not purchase any IP without a running instance. So we will instanciate the VM without any OS:

# Download cloudinit script that will help later to setup our VM
curl -fsSLO https://raw.githubusercontent.com/gmasse/emailgw/master/cloudinit
# Instanciate the VM
openstack server create --flavor s1-4 --key-name mykey --user-data cloudinit --image "rescue-ovh" email

The cloudinit script will update the system, install packages for docker and unbound, and configure network with local dns and the static IP.

2. Purchase a ‘Static’ IP

Using Customer Interface:
Screenshot

And assign it to the VM named email.

3. Add Block Storage

There are two types of block storage: classic and high-speed (openstack volume type list). Performances of classic storage seems acceptable for an entry level mail gateway.

Create a 10GB volume and attache the volume to the instance:

# Create the volume
openstack volume create --type classic --size 10 email_storage
# Attach the volume to the VM
openstack server add volume email email_storage --device=/dev/sdb

4. Build the VM

Pass the Static IP as meta-data (replace 1.2.3.4 with your own IP) and build the VM:

openstack server rebuild --property static_ip=1.2.3.4 --image "Ubuntu 18.04" email

5. Setup Storage

Connect to the VM: ssh ubuntu@1.2.3.4

# LVM setup
sudo pvcreate /dev/sdb
sudo vgcreate vg-mail /dev/sdb
sudo lvcreate -n lv-mail -l 100%FREE vg-mail
# Format filesystem
sudo mkfs -t ext4 -L MAIL -E nodiscard /dev/vg-mail/lv-mail
# Mount it
sudo mkdir -p /mnt/mail
echo -e 'LABEL=MAIL\t/mnt/mail\text4\tdefaults,noatime\t0 2' | sudo tee -a /etc/fstab
sudo mount /mnt/mail

6. Configure local DNS resolver

Many Anti-spam blacklist systems rely on DNS, some of those blacklists rate-limit can be exceeded when using mutualized DNS resolver (your provider or global anycast like Quad9). Using your own local resolver with your Static IP would solve this issue.

Configure unbound to allow local resolution and use the Static IP for external request (replace 1.2.3.4 with your own IP):

/etc/unbound/unbound.conf.d/docker.conf
1
2
3
4
5
6
server:
interface: 127.0.0.1
interface: ::1
interface: 172.17.0.1
access-control: 172.16.0.0/12 allow
outgoing-interface: 1.2.3.4

Configure Systemd to start Unbound after Docker service: sudo systemctl edit unbound.service:

1
2
3
[Unit]
After=docker.service
Wants=docker.service

Reload service: sudo systemctl reload unbound.

To test your local DNS resolver, you can use a DNS reflector (like DNS Paranoia) and check it answers your Static IP:

$ dig +noall +answer reflect.dnsp.co
reflect.dnsp.co. 0 IN A 1.2.3.4

7. Generate Let’s encrypt SSL certificate

To generate certificate, run:

sudo docker run --rm -ti -v $PWD/log/:/var/log/letsencrypt/ -v $PWD/etc/:/etc/letsencrypt/ -p 80:80 certbot/certbot certonly --standalone -d mail.mydomain.com

9. Configure firewall

Review the rules, then copy and apply:

sudo curl -o /etc/iptables/rules.v4 https://raw.githubusercontent.com/gmasse/emailgw/master/etc/iptables/rules.v4
sudo curl -o /etc/iptables/rules.v6 https://raw.githubusercontent.com/gmasse/emailgw/master/etc/iptables/rules.v6
sudo ip6tables-restore --noflush < /etc/iptables/rules.v6
sudo iptables-restore --noflush < /etc/iptables/rules.v4

Do not restart the service iptables-persistent because it will overwrite the Docker default rules and prevent from accessing the container.

10. Configure the container

Download the configuration files:

sudo mkdir /mnt/mail/docker-mailserver
sudo chown ubuntu:ubuntu /mnt/mail/docker-mailserver
ln -s /mnt/mail/docker-mailserver/ ~/docker-mailserver
cd ~/docker-mailserver/
curl -o setup.sh https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh; chmod a+x ./setup.sh
curl -o docker-compose.yml https://raw.githubusercontent.com/gmasse/emailgw/master/docker-mailserver/docker-compose.yml
curl -o env-mailserver https://raw.githubusercontent.com/gmasse/emailgw/master/docker-mailserver/env-mailserver

Update env-mailserver according to your setup (OVERRIDE_HOSTNAME and POSTMASTER_ADDRESS).

By default, docker-mailserver uses Maildir format for mailboxes. This is a very common format where each e-mail is stored in one file. For better performances and/or to use Alternate storage, you can rely on Dovecot sdbox and mdbox (supported since the merge of my pull request).

Update and save .env file:

~/docker-mailserver/.env
1
2
3
4
HOSTNAME=mail
DOMAINNAME=mydomain.com
CONTAINER_NAME=mail
EXTERNAL_IP=1.2.3.4

11. Run it

Create at least one e-mail account: sudo ./setup.sh email add <user@domain> [<password>]
Then launch the container: sudo docker-compose up -d mail

12. To go further

Generate DKIM keys
Update the container

To be continued…

Let’s encrypt SSL auto-renew
Coudinit: add storage and dns configuration
Tiered storage, using Dovecot Alternate storage feature: recent emails on high-speed block storage, archives on normal speed
Volume (auto?) resize
IPv6
E-mail configuration auto-discover

HOW TO pre-configure your Ubuntu installation for a Raspberry Pi
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×