Setting Up A Spam-Proof Home Email Server (The Somewhat Alternate Way) (Debian Squeeze)
Introduction
Email spam is a huge problem. I have found for myself quite a simple solution, however it'll take some time to "migrate" completely over to it.
The solution is to create a unique email address everytime I have to give an email address to someone else or to some website to sign up. If I want an account at twitter, I'd use "www.twitter.com@MYDOMAIN.COM". For webbased services, I use the full domain name incl. subdomain (www) on the left of the @ (some poorly designed websites do not recognizes the www. as valid email address, for those I just leave it away).
For people I use a format like that: "email.john.doe@MYDOMAIN.COM". You could also use like "from.john.doe@MYDOMAIN.COM". The good thing is, the left side of the @ for email addresses is almost "unlimited".
Because I generate unique email addresses for every contact, I can easily find out where my email address got leaked and then I can easily remove it.
This howto will set up a full functioning email server with according scripts to make easy email management. It includes also the DNS setup part - even if you are on a dynamic address - e.g. if you want to run your own little mailserver from home.
Summary
In this howto I use Debian Squeeze as server. For other Linux distros you'll have to make according changes yourself.
A short summary of what is being done in this howto is like this:
- Obtaining a domain name
- Taking care of a dynamic ip - if necessary
- Taking care of the dns and routing
- Setting up postfix
- Setting up procmail
- Setting up dovecot
- Setting up webserver for email address management
- Setting up Thunderbird with addon
Credits
In this howto I also relay on a few other howtos here - especially regarding the setup of the bind and email server. For those, I copied more or less from Falko's Perfect Debian Server howtos. Also the email relay section was borrowed from a howto here by sjau. Without those, I probably would not have been able to set this up.
Obtaining a Domain Name
Before you can start running your own mailserver you need a domain name for which you can also set MX records. I don't want to make any suggestion as there are tons and tons of domain registrars out there. One of the cheapest I know of is GoDaddy.
I don't use GoDaddy myself but as far as I've heard they provide a solid service.
Handle Dynamic IPs
Another challenge to be facing is how to handle things on a dynamic ip address. If you don't have a dedicated box rented somewhere but use your home internet connection, then very likely you have not a static ip.
In the web it's essential to have a static ip so that others always know where to reach you. However there are services that help you with that.
One of the services I use is EveryDNS. They let me host the DNS for the domain name.
As of now they still offer the service for free. Although they got bought up in 2010, the promise was, that then-customers who have donated money, can also in future use the system for free. On their webpage, they don't mention anything yet that new customers need to pay - but I don't know for sure.
The reason for EveryDNS is, that they offer also a little perl script that can be used to update the DNS. This is essential as your IP changes over time if you don't have a static IP address. You can get the perl script from here.
When you have a domain name then first go to What Is My IP. It will show you your current public ip address. Then create an account at EveryDNS and make at least the following entries where MYDOMAIN.COM would be your domain name:
(1) Make an "A" record type, set as fully qualified domain name "MYDOMAIN.COM" and set as value your public ip address
(2) Make a "CNAME" record type, set as fully qualified domain name "*.MYDOMAIN.COM" and set as "MYDOMAIN.COM"
(3) Make a "MX" record type, set as fully qualified domain name "MYDOMAIN.COM", set as value "MYDOMAIN.COM" and set as "MX Value" "10"
What we just did is setup the DNS for the domain. The main domain is found at your IP address (a-record), all other domains are also found there (the * in the cname record pointing to the main domain) and we also operate a mail server there (mx record).
root user
The following things are being done as root user - unless told otherwise.
Dyn. IP Update
As said before, if you don't have a static IP address you will need to regurarly update the DNS info.
(1) Get the perlscript and make it executable
cd /root
wget http://www.everydns.net/eDNS.pl
chmod 0755 eDNS.pl
(2) Create a bash script that calls the perl script (there's other ways but I found that the simplest):
touch eDNS.sh
echo "#!/bin/bash" > eDNS.sh
echo "perl /root/eDNS.pl -u USERNAME -p PASSWORD -d MYDOMAIN.COM" >> eDNS.sh
Replace USERNAME and PASSWORD with your everydns login credentials.
(3) Setup a cron to run it regurarly
I love to work with a cron.txt file that contains all crons. I think it's a lot simpler to maintain it like that.
First you have to check out if there is already a cron entry:
crontab -l
If there is no cron entry yet, then just run the following commands
touch cron.txt
chmod 0700 cron.txt
echo "*/5 * * * * /root/eDNS.sh >/dev/null 2>&1" > cron.txt
If there are already cron entries, copy them, create a cron.txt file and insert them and add the following command also:
*/5 * * * * /root/eDNS.sh >/dev/null 2>&1
Now we load the cron.txt as cron:
crontab cron.txt
And we check if it was added properly:
crontab -l
LAN/Routing/Bind
The next problem we're facing then is how to resolve the domain in your lan. If your mail server is behind a router then I will probably have a local ip like 192.168.0.x or 10.0.0.x.
If you are behind a router, you will need to forward the following ports to your server: 25, 80, 143, 443, 991. There could be more ports required like 587.
Also we face the problem on how to resolve the domain name from inside the lan. From outside the lan you have the DNS entry that should point to your current IP address. However when you are inside the lan and make a dns query it will only return your public ip and usuall it will fail then.
There are several solutions for that problem - if the problem even exists at all.
One way would be the use of dnsmasq in routers (e.g. dd-wrt or tomato-wrt). However as I can't guarantee for it to work, the only other option I see is to setup a full fledged DNS server on your mailserver.
In this tutorial I'll use a chrooted Bind9 as I am the most familiar with it. For other DNS servers you'll find plenty of documentation online.
(1) Install the software and stop it
apt-get install bind9
/etc/init.d/bind9 stop
(2) Change the /etc/default/bind9 config so that the options line is like this:
OPTIONS="-u bind -t /var/lib/named"
(3) Create the necessary directories under /var/lib:
mkdir -p /var/lib/named/etc
mkdir /var/lib/named/dev
mkdir -p /var/lib/named/var/cache/bind
mkdir -p /var/lib/named/var/run/bind/run
(4) Then move the config directory from /etc to /var/lib/named/etc:
mv /etc/bind /var/lib/named/etc
(5) Create a symlink to the new config directory from the old location (to avoid problems when BIND gets updated in the future):
ln -s /var/lib/named/etc/bind /etc/bind
(6) Make null and random devices, and fix permissions of the directories:
mknod /var/lib/named/dev/null c 1 3
mknod /var/lib/named/dev/random c 1 8
chmod 666 /var/lib/named/dev/null /var/lib/named/dev/random
chown -R bind:bind /var/lib/named/var/*
chown -R bind:bind /var/lib/named/etc/bind
(7) Edit the /etc/rsyslog.d/bind-chroot.conf file and add
$AddUnixListenSocket /var/lib/named/dev/log
(8) Restart services
/etc/init.d/rsyslog restart
/etc/init.d/bind9 start
and check /var/log/syslog for errors.
Now we have setup Bind9 in a chrooted environment. The next thing to do is to acutally add a zonefile for your domain.
(9) Edit /etc/bind/named.conf.local and add
zone "MYDOMAIN.COM" IN { type master; file "/etc/bind/zones/MYDOMAIN.COM.db"; allow-update { none; }; };
(10) Create the zone folder and zonefile
mkdir /etc/bind/zones
touch /etc/bind/zones/MYDOMAIN.COM.db
chown -R bind:bind /etc/bind/zones/MYDOMAIN.COM.db
(11) Add your zonefile info to MYDOMAIN.COM.db
$TTL 86400 @ IN SOA @ MYDOMAIN.COM. ( 1 ; serial 2600 ; refresh 15M ; retry 3600 ; expiry 360 ) ; minimum @ IN NS ns.MYDOMAIN.COM. ns IN A LOCALIP www IN A LOCALIP MYDOMAIN.COM. IN A LOCALIP MYDOMAIN.COM. IN MX 10 LOCALIP
Of course replace MYDOMAIN.COM with your actual domain name and LOCALIP with your static LAN IP address. Bascially we tell here that the nameserver for that domain is hosted on "ns.MYDOMAIN.COM" and "ns.MYDOMAIN.COM" is to be found at the static local ip address.
(12) Restart Bind9
/etc/init.d/bind9 restart
(13) Change router NS resolution
While Bind9 is setup now, there's one last thing to do. On your router you have to change the nameserver resolution order. The first nameserer must now be your "mail server" with the according static local ip. Otherwise the whole bind9 setup was for nothing. As the second nameserver enter the value of what was aleady in there as first one. Depending on your router it can be a bit trickier.