Wednesday, June 8, 2016

Making a Mailserver (Part 1) - What's in a Name

This is an instalment in my series on setting up a Linux based mailserver. See these posts:

You might want to start with this cautionary note, which gives you a quick overview of what's in front of you.

Some areas of what I'm writing about are more detailed than others. I'm trying to guide you into making the right decisions. I'm more verbose in areas where it's particularly tricky to understand or find the right information, but generally I expect you to find the right way of configuring  your own system.

I start with the assumption that you have your VPS or hosting machine sorted out. You should have SSH access to it and a way to console to it should you manage to hose the networking or lock yourself out.

Also, do not use your mailserver for anything else other than mail and if necessary DNS. For example, don't serve your fast and loose PHP pages on this machine. Your mailserver will become a silent but crucial part of your day. Don't expose the machine to unnecessary risk; limit services to those that are absolutely necessary.

Notes about your Server

I strongly urge you to do the following things before you go any further.

1. Set up a user other than "root" and make sure you have a damn strong user password.

Remove root SSH access (/etc/ssh/sshd_config):
PermitRootLogin no
2. Set up key based authentication over SSH. Disable password logins over SSH if you're brave.

3. Set up "denyhosts" or its heir apparent "fail2ban", to block hosts that are bruteforcing your SSH. Brute force attacks happen all day every day.

4. Install ntp and check that the time is synchronised.

5. Configure the right timezone (tzselect). After that, restart syslog and cron.

6. Install and configure iptables to accept port 22 and 53 on TCP and UDP and block everything else. This is not always necessary. For example. if you're using AWS you should customise a security policy and apply it to the Instance.

7. Reboot your machine to make sure that the system comes back up running the daemons you require. I prefer to use sysv-rc-conf to control the daemons that start at boot time. Disable as much as you dare.


Here's what we're about to do:
  1. Register the domain name.
  2. Update the glue records.and/or point to other nameservers outside your domain.
  3. Set up master and slave DNS server relationship.
  4. Set up a zone file on the master.
  5. Verify the MX record.

A Record of Sniffing Glue

Good registrars offer complimentary DNS services, which is nice, but I've never tried that. I've always done my own DNS hosting. The rest of this chapter assumes that you want to 'roll your own' DNS.

Once you've registered your domain with a reputable registrar, get the glue records sorted out. You want the glue records to point to your master and slave DNS servers.

The glue records tell the top level domain (TLD) root servers where your domain DNS servers live on the Internet.

You can verify that the glue records are active by finding your TLD servers (the registry itself) and querying them, in the following example, my TLD is "tech":
# dig tech
tech.                   2753    IN      NS
tech.                   2753    IN      NS
tech.                   2753    IN      NS
tech.                   2753    IN      NS
# dig NS
;; ADDITIONAL SECTION:     86400   IN      A       54.194.x.x     86400   IN      A       64.22.x.x
 The "additional section" is the critical part.

You need not set up glue records if your nameservers are outside your domain name. In which case, you only need to add the DNS server names via your registrar. That's not actually a glue record but the result is the same as long as the nameservers are reachable!

I've seen a registry requirement in the past to have a minimum of two nameservers. If you strike this and don't have a second nameserver, you can input any junk for the second nameserver and it is highly unlikely to be validated. That is, unless you live in Germany, where you can't even take control of a domain name until such time as you have two working nameservers that have both UDP and TCP open on port 53.

That was fun wasn't it? Did it seem to take forever for the glue records to get updated? One TLD for me can take between 30 to 60 minutes before the glue record changes come through.

Two Servers

My design choice was to go for two DNS servers, the mailserver itself is the master nameserver and an AWS machine is a slave. However, I configure the nameserver names so that the AWS is "ns1" and the mailserver is "ns2" in the hope that most hosts will prefer to lookup against "ns1". In truth, I have never measured the DNS lookup traffic per nameserver, I should do that...

First, tell "ns2" about the zone and that it should be a slave. The bind config is dead easy.

zone "" IN {
        type slave;
        masters { 64.22.x.x; };
        notify no;
        file "/var/lib/bind/";
The "notify no" part stops the annoying log message "refused notify from non-master" when the slave, for whatever reason, attempts to notify itself.

Zone Files

From this point we need only configure the master nameserver.

All the name to IP mappings are kept in zone files. One zone file per domain - okay, reverse DNS  makes that two files but I'm assuming you don't own your own IPv4 space. There's thousands of websites to help you with this, so I am only covering the critical bits and calling out the bind config. Remember to add the trailing dot on FQDNs.

We will revisit the bind config in later pages when we talk about mailserver reputation.

Here's a default starting point:
$TTL 86400      ; 1 day          IN SOA (
                          2016060100 ; serial
                          1800       ; refresh (30 minutes)
                          900        ; retry
                          1209600    ; expire RFC1912
                          1800       ; minimum (30 minutes)
Whenever you make changes to the file you need to increment the "serial" number and reload (not restart) bind. A notify is then sent to the slave server and the record transfer done.

Setup a default "A" record plus the "NS" nameservers. If you want to know what is correct for the default A record, I recommend it be the website host, if you have a website for the domain:
A       54.194.x.x
Mail record, remember this is why we're here!
MX      10
The "10" is a preference, if you have more than one mailserver then your primary would have a lower number to a second MX record. Two mailservers is quite tricky to setup; what's your plan to keep the mailboxes in sync? If you have two MX records, bad email delivery agents will deliver arbitrarily to either server. The moment your primary is knocked offline (even for a moment),  everyone charges off to the second mailserver.

Create a domain section and provide the real IPs of the nameservers - this should mirror the glue record!
ns1                     A       54.194.x.x
ns2                     A       64.22.x.x
mail                    A       64.22.x.x

That's about it.

Verification and Troubleshooting

Don't forget to verify the glue records as described above. If you didn't put in glue records but instead added nameservers from outside of your domain (you can do this and set up glue records), you should still see an authority section:
# dig
;; AUTHORITY SECTION:         3600  IN    NS         3600  IN    NS
Your domain will remain off the Internet until you have either the "authority" or "additional" sections.

Check that your slave DNS host is able to transfer the zone (able to read the master's complete zonefile). You should see these kinds of messages (probably in /var/log/syslog):
Jun  1 09:32:08 ns1 named[5221]: client 64.22.x.x#54642: received notify for zone ''
Jun  1 09:32:08 ns1 named[5221]: zone Transfer started.
Jun  1 09:32:08 ns1 named[5221]: transfer of '' from 64.22.x.x#53: connected using
Jun  1 09:32:08 ns1 named[5221]: zone transferred serial 2016060100
Jun  1 09:32:08 ns1 named[5221]: transfer of '' from 64.22.x.x#53: Transfer completed: 1 messages, 13 records, 398 bytes, 0.096 secs (4145 bytes/sec)
Failures in transfer could be related to port 53 TCP being blocked.

If changes to zonefiles aren't propagating, check that the serial has been incremented.

You can force the slave to re-read all the zones by deleting the cached copies (probably in /var/lib/bind/) and restarting bind. It's safe to do this on a slave because the master retains the original versions.

Check the syslog for configuration errors when restarting bind. The daemon will tell you that a line failed and then that zone will not be loaded at all, while other zones will still work.

Tracking back the root of a problem

From your own desktop, test the mailserver record as below and you should receive an answer section:
# dig MX
;; ANSWER SECTION:        3600  IN    MX    10
If that's not working, do the same thing and specifically ask your DNS server the same question:
# dig MX @ must be the IP of your DNS server.

If there is an answer section, the server is doing okay. Maybe your TLD registry records aren't up to scratch. If there is no answer section, go the the DNS server itself and run the command:
# dig MX @localhost
If you got no answer section there, then your MX record is set up incorrectly. If you did get an answer section (but none in the previous step), then there could be rules or a misconfiguration in bind that forbids the query from remote hosts.

Don't forget to verify that both of your DNS servers return an answer section. Use the "dig MX @x.x.x.x" for each DNS server IP.


After sweating blood, all you've managed to do is set up a basic nameserver. Your mailserver is still a long way off. Give up now.

Next up, we're configuring exim4 as a basic mailserver.  Much like this DNS section, it's not over after that. We want a good mailserver, not a basic one.

No comments:

Post a Comment