WWW.DUMAIS.IO

I am now hosting my own DNS and Mail servers on Amazon EC2Last edited on Sep 22, 2012


Using an Amazon EC2 virtual machine, I wanted to host my own domain by doing as much as I could myself. By that, I mean that I wanted to host my own DNS server, mail server and web server. So after registering a new domain name, the first thing I did was to change the nameserver of that domain to use my own server instead of the registrar's. After that, all the work is done on my EC2 machine. Note that for this to work, I needed to unblock TCP port 25 and 53 and also UDP port 53 on my virtual server. This can be done in the EC2 management console under the "security groups" section.

Configuring the DNS server

First thing to do is to add the new zone definition in /etc/named.conf. Let's assume that I registered "exampledomain.ca".

zone "exampledomain.ca" IN {
        type master;
        file "exampledomain.ca";
};

Then I need to define the zone in /var/named/exampledomain.ca. I wanted to create a subdomain called "www" so that my web server could be accessible from www.exampledomain.ca. I needed an MX record that points to the mail server that is also hosted on the same server as the DNS server. For this example, let's assume that the public IP address of my server is 1.2.3.4.

$TTL    300
@           IN SOA  exampledomain.ca. www.exampledomain.ca. (
                    2012220104      ;
                    1H      ; refresh
                    15M     ; retry
                    1W      ; expiry
                    1D )        ; minimum

            IN NS   ns.
            IN A    1.2.3.4
            IN MX 10 mail

ns              IN A 1.2.3.4
www             IN A 1.2.3.4
mail            IN A 1.2.3.4

Mail server

after looking for a solution to host multiple domains with virtual mailboxes that are not associated with a unix account, I discovered that that postix might be better for the job than sendmail. after installing postfix and setting it to run automatically at boot time, we need to configure the /etc/postfix/main.cf file. I am only telling it to listen to all network interface and where to look for the list of domains we are hosting and the mailbox definition.

The other nice thing about postfix VS sendmail is that you can easily add more mailboxes/forwards and domains without having to restart postfix. This is very usefull if you wanna make a webpage on which users can create their own mailboxes and add their own domains. But the nicest thing of all is that you can use a mysql server (or several other kinds of DB) so that your web site can configure the server more easily. But for now, I will stick with scripts. Here is an example of my main.cf script:

queue_directory = /var/spool/postfix
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
mail_owner = postfix

# listen to all interfaces so we can accept incomming connection from LAN and WAN.
inet_interfaces = all
inet_protocols = all
mydestination = $myhostname, localhost.$mydomain, localhost
unknown_local_recipient_reject_code = 550
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
debug_peer_level = 2
debugger_command =
        PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
        ddd $daemon_directory/$process_name $process_id & sleep 5
sendmail_path = /usr/sbin/sendmail.postfix
newaliases_path = /usr/bin/newaliases.postfix
mailq_path = /usr/bin/mailq.postfix
setgid_group = postdrop
html_directory = no
manpage_directory = /usr/share/man
sample_directory = /usr/share/doc/postfix-2.6.6/samples
readme_directory = /usr/share/doc/postfix-2.6.6/README_FILES

# mailboxes will be saved in /var/vhosts
virtual_mailbox_base = /var/vhosts

#/etc/postfix/vmbox will contain the list of mailboxes
virtual_mailbox_maps = hash:/etc/postfix/vmbox

#/etc/postfix/vdomains will contain the list of domains we are accepting mail for.
virtual_mailbox_domains = hash:/etc/postfix/vdomains
virtual_alias_maps = hash:/etc/postfix/valias
# The /var/vhosts folder must be writeable by user 4000 and group 4000
virtual_uid_maps = static:4000
virtual_gid_maps = static:4000

A note on postifx lookup tables. Postifx is great because it lets use use different type of lookup tables. In the example posted above, I use hash:/etc/postfix/valias. This is a reference to a Berkely DB file. You need to create a text file with key/pair values separated by a space and generate a DB with the "postmap" command in order to use this. But if you want to use another table type such as a mysql table, then you could specify mysql:/etc/postfix/valias. But in that case, the "valias" file's content would be different. It would contain information on how to access the database table.

More information on different types of tables can be found here: http://www.postfix.org/DATABASE_README.html

The virtual_uid_maps and virtual_gid_maps lines indicate that the mailboxes inside /var/vhosts will be owned by 4000:4000 on the system. This means that you have to create a user with ID 4000 and change ownership of the base folder to that user:group

useradd virtualmailbox -u 4000
chown virtualmailbox:virtualmailbox /var/vhosts

The virtual_mailbox_domains line indicates that postfix needs to look into that file to find the list of domains it is accepting mail for. Everytime that you modify the vdomains of vmbox file, you need to rebuild the hash database by issuing the "postmap /etc/postfix/vdomains" command. Of course, you would replace "vdomains" with "vmbox" if you need to rebuild the vmbox database. virtual mailboxes are files that will be stored on the server. But if you need to forward to another address, then you will need aliases. I'm not sure why, but I discovered that you should not use "virtual_alias_domains" if you want to use mailboxes and aliases for the same domains. Only list the domains in "virtual_mailbox_maps".

# This file will be compiled by the "postmap" tool. It needs
# to contain 2 columns on each line. Since this is just a list
# of domains, we only need one column but the tool will expect 2.
# So you can put anything you want in the second column. I decided
# to put the domain name a second time.
#
exampledomain.ca exampledomain.ca

vmbox file

#because there is a slash at the end of the path, mail will be saved in maildir format
admin@exampledomain.ca  exampledomain.ca/admin/

#because there is no slash at the end of the path, mail will be saved in linux mbox format
test@exampledomain.ca   exampledomain.ca/test

valias file

user1@exampledomain.ca  user1@gmail.com
user2@exampledomain.ca  user2@yahoo.com

Automation

It could become very handy to automate the process of adding domains and user mailbox though a perl of php script. The best way to do it would be by using a database, but let's see how to do it with files first.

Files

  • Add the domain name in /etc/postfix/vdomains
  • Add mailbox in /etc/postfix/vmbox
  • Add forwarding addresses in /etc/postfix/valias
  • Run "postmap /etc/postfix/vdomains"
  • Run "postmap /etc/postfix/vmbox"
  • Run "postmap /etc/postfix/valias"

Of course, this requires that the script locks the files to prevent two process from accessing the same files at the same time. And also, it would be better to schedule the "postmap" instead or running it everytime because if you have a large system where users create several mailboxes in 1 minute, you would want to wait a little bit before running postmap oherwise you would add a great load on your CPU.

Database

With this method, your scripts don't need to lock any files and you don't need to schedule a "postmap". All you need to do is to insert a mailbox/domain in the database and the change is instantaneous. In my opinion, this is the ideal way of doing thing if you have a server that hosts several domains and you allow users to create their own mailboxes. For an example on how to do this, you can refer to this post I did: Building a hosted mailserver service