Running your own mail server

Motivation

Not too long ago there was some hubub around https://myaccount.google.com/purchases. In brief, if you use google mail, it tracks your purchases through receipts received in email. Now, some people see this as no big deal or even a feature. Others see it as a privacy invasion, and are reminded that all their data can be mined by the email provider and possibly third parties. Of those, some advoate getting a paid email provider. Agreed, that provides less incentive to monetize your data… but only a bit. Eventually, any company, however good its initial intentions, goes through leadership changes, is bought out, or goes bankrupt. At that point, your data is one of the assets being bargained with.

The other alternative, of course, is to run your own mail server. I won’t lie – this is not for everyone. But it’s not as bad as some make out. I recently reinstalled mine, so I wrote down the steps I took, and will leave them here. I’ve been holding onto this for at least 6 months hoping to eventually run through them again to work out some of the finer details. That hasn’t happened yet, so I’ll just post what I have now as a start.

Running your own mail server is not free. In particular, you’ll need to pay for a domain name ($10-15/year), and some place to run the mail server. If you have an always-on machine at home, and stable IP address, then you can run it there. You can pay for a tiny cloud instance on amazon/rackspace/digitalocean/etc. There are cheaper options (including “one year free” amazon micro instances), but a small digitalocean instance will be $5/month. Personally, I keep a large server online for running many VMs and containers, and run the mail server there.

You will also need a certificate. That’s now easy and free with letsencrypt.

There are also some non-monetary costs. You may get a bit more spam. And once in awhile, you may run into a case where your mail server is being rejected by another.

On the other hand, the server is entirely yours. You can create as many accounts for individual purposes as you like. You can point multiple domain names at it, so that you don’t give away your primary one for every little purchase you make. Ten, twenty years from now, you can still have all your friends’ and family emails in the same place, in the same format. This last one is too often overlooked, yet one of the best advantages of open source for all applications.

Setup

I picked up a new hosted server, and installed Ubuntu 18.04 on it. First thing I did was go to my dns provider and register a name for it, and set up the new mx record to point to it. The details of this vary a bit depending on your dns provider, so I won’t go into detail here (I’ll do a post if people ask for clarification). If you’re looking for a provider, I do recommend zoneedit.

I installed lxc and created a new container in which to run my mailserver:

apt-get -y install lxc1
lxc-create -t download -n mail -- -d ubuntu -r bionic -a amd64

I gave it a static ip address through dnsmasq:

echo "dhcp-host=mail,10.0.5.155" >> /etc/lxc/dnsmasq.conf
echo "LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf" >> /etc/default/lxc-net
sudo systemctl stop lxc-net
sudo systemctl start lxc-net

The point of the static ip address is to facilitate forwarding mail related ports into the container. I did this with a script started at boot by systemd:

cat > /usr/bin/container-ports-fwd << EOF
nic=enp0s31f6
iptables -t nat -A PREROUTING -p tcp -i ${nic} --dport 25 -j DNAT --to-destination 10.0.5.155:25
iptables -t nat -A PREROUTING -p tcp -i ${nic} --dport 465 -j DNAT --to-destination 10.0.5.155:465
iptables -t nat -A PREROUTING -p tcp -i ${nic} --dport 993 -j DNAT --to-destination 10.0.5.155:993
iptables -t nat -A PREROUTING -p tcp -i ${nic} --dport 587 -j DNAT --to-destination 10.0.5.155:587
EOF
chmod 755 /usr/bin/container-ports-fwd
cat > /etc/systemd/system/container-ports-forward.service << EOF
[Unit]
Description=Bring up port forwards for lxc
After=lxc-net.target
Before=lxc.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/container-ports-fwd

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable container-ports-fwd
systemctl start container-ports-fwd

I also installed and ran letsencrypt on the host:

sudo apt -y install letsencrypt
letsencrypt -d mail.example.org -m me@my.mail certonly

Next I started up the container and installed the basic mail tools:

sudo lxc-start -n mail
sudo lxc-attach -n mail apt -y install dovecot-imapd postfix mutt

New since my last mail server install is the removal of dovecot-postfix in favor of the mail-stack-delivery package:

sudo lxc-attach -n mail apt -y install mail-stack-delivery

After this I copied the letsencrypt keys into the container

lxc-attach -n mail -- mkdir -p /etc/letsencrypt/live/mail.example.org
cp /etc/letsencrypt/live/mail.example.org/* /var/lib/lxc/mail/rootfs//etc/letsencrypt/live/mail.example.org

and edited
/etc/postfix/main.cf and /etc/dovecot/conf.d/10-ssl.conf to point to those using these lines:

smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.org/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.org/privkey.pem

This is enough to be able to send and receive mail. Personally, I want to run this server in a uid-mapped container and from a luks-encrypted device. While you can setup the whole container that way from the start, for simplicity of examples, you could at this point copy over and uid-shift the container contents to a new device, and update the container configuration accordingly.

Some notes which I should elaborate on later:

    • SPF

    • postscreen setup
    • /etc/postfix/master.cf, i.e. uncomment smtps
    • /etc/dovecot/conf.d details
  • This entry was posted in Uncategorized. Bookmark the permalink.

    10 Responses to Running your own mail server

    1. You’re doing

      cat > /usr/bin/lxc-ports-fwd
      chmod 755 /usr/bin/lxc-ports-fwd

      but your systemd unit wants to run

      ExecStart=/usr/bin/container-ports-fwd

      You may want to reconcile that.

      How are you handling letsencrypt certificate renewals? A hook in /etc/letsencrypt/ that copies the files? Do you need to restart postfix/dovecot after replacing the certificate?

      • s3hh says:

        Oh, right. The actual filename I used was different. I’ll fix that, thanks.

        I’m actually just doing letsencrypt renewals by hand. Yes, the services need to be restarted each time the certificates are renewed.

        Several paths in my containers are actually bind mounted from a backup LV on the host, so making a single script that copies the certificates into place for all my containers would be trivial, I just haven’t done it. If I ever do another post on configuring container backing stores, that might be a good place to discuss it.

    2. Alex says:

      mail-stack-delivery seems to be an Ubuntu-only meta package, it seems to not exist anymore. A search seems to tell it only existed until Ubuntu Focal:

    3. lxc1 seems to be an obsolete package, replaced by lxc-utils.
      See:

      I’d like to link to , but it’s returning 500 all the time.

    4. The links got removed. Let’s try again.

      lxc1 seems to be an obsolete package, replaced by lxc-utils.
      See https://installati.one/install-lxc1-ubuntu-20-04/

      I’d like to link to https://packages.ubuntu.com/, but it’s returning 500 all the time.

    5. > and from a luks-encrypted device

      Some questions about this.

      If the server is up all the time, it’s decrypted for most purposes, isn’t it? Only for someone who physically steals the device, and is so stupid to shut it down first, will re-encrypt it. If they’re there to steal the data, they probably either do a copy while it’s still running, or freeze the RAM if they need to get away with it, and in any of those cases the LUKS partition is decrypted. If someone break in remotely, they’ll find the mounted (decrypted) partitions, so they’ll probably have no walls to the data

      Also, if you need to reboot the device remotely, you’ll be in trouble, no?

      I’m asking because I have LUKS in the server where I have my website, but am considering removing it when I reinstall the server.

      I guess that sending encrypted email is the real protection for the data in them.

      • s3hh says:

        Regarding luks: using Hetzner specifically as an example, it’s well advertised that after you stop using one box, they will ‘auction’ it and someone else will start using it. That’s the main person I’m protecting my data from with the luks encryption.

        • Alex says:

          Ahh, yes, I forgot about that detail. Having it at home is different than having it at a remote server. However, I’m reconsidering even for the home case: if the drive ever fails, I won’t be able to wipe it. Having it encrypted will protect against that.

    6. Is that really all of it? I guess I need to see some dovecot and postfix configs, hopefully in a git repo where I can understand why changes are made to them, to learn how I should configure the servers. (I never ever run those daemons.)

      Or maybe the default config is just good?

      What kind of access to the mail does this provide? IMAP? POP? Maybe both? Maybe none, and I should just get the mail via SSH?

      Also, I had an idea some time ago: set up the IMAP server via a Unix socket, so that it’s only available locally. Then, set up my MUA to set up an SSH tunnel to reach that Unix socket through the network, so to get the mail through a very secure channel. What do you think about that? Would it be viable in your set up?

    7. alx says:

      “””
      > Ten, twenty years from now, you can still have all your friends’
      > and family emails in the same place, in the same format.
      > This last one is too often overlooked,
      > yet one of the best advantages of open source for all applications.
      “””

      Actually, you can have that without running your own mail server. I use isync to download the mail from gmail’s IMAP server to a local folder, so that mutt(1) doesn’t know anything about gmail. As a side-effect, I have a backup of all of my mail, and have it available for grepping and similar operations (the fact that some email is encoded in base64 breaks that, but that’s Mozilla Thunderbird’s fault, which I used for some time) (encrypted email is not available for that, but that’s assumed; I use mutt(1) for that, but it’s slower, and slightly less convenient, but most of the mail I want to grep(1) is from mailing lists, so non-encrypted).

      Nevertheless, I don’t advocate for gmail either, for the other reasons, so I’m moving away from it. 🙂

      But maybe useful to anyone having any third-party email provider that you can get *your* mail in *your* computer in a reasonable format.

    Leave a comment