How I hosted a DNS server on AWS ?

Wait. I know what you are thinking now.

Who on earth would do such a crazy thing ?

Why would a person even host a DNS server on AWS when one could use Route53 to efficiently manage DNS records.

The answer is simple:

I’ve been a user of DNS since my first interaction with the internet, but have no clear idea on how DNS works.

So I started learning how DNS works and more on how DNS server works. You can check out my notes on DNS. I felt that the best way to learn about DNS is by practically hosting a DNS server.

Trust me this way is far better than learning DNS by using a third party DNS service or reading theoretical blog posts on how DNS works.

I had a few credits left on AWS, that’s when I asked myself this question: “Is it possible to host a DNS server on AWS?”

The steps are pretty simple:

  1. Create an EC2 instance. Free tier version of Ubuntu works fine. (Please read this article to learn how to create EC2 instance). Download the SSH key to access the instance.
  2. Create an elastic IP and associate it with the EC2 instance created in the first step. (If you have never worked with elastic IPs, you can read this article)
  3. Now the public IP of the EC2 instance will be replaced by the elastic IP.
  4. Create a Security Group which allows 0.0.0.0/0 access to port 53 (TCP and UDP) and add this security group to the EC2 instance. This allows DNS interactions from public internet.

I didn’t really want to spend money for this experiment. So ended up registering a free domain – machane.ga – for one month at FreeNom.

Did you know ? Machane is the malayalam slang word meaning “dude”

FreeNom allows user managed DNS name servers. One could create Glue records at the beginning of the registration. I entered two nameservers as ns1.machane.ga and ns2.machane.ga and gave the same AWS elastic IP in both the IP address fields.

Name servers

If you observe above, you can see that I am in the process of registering machane.ga and provided the nameservers as ns1.machane.ga and ns2.machane.ga. That’s the trick in glue records. So, basically we are saying the domain registrar that I am going to register machane.ga and I am also going to host the nameservers for it under the DNS paths ns1.machane.ga and ns2.machane.ga.

Once the registration of the domain is successful and logged in to the FreeNom domain nameserver administration panel, one should be able to see something similar to the following:

Glue records

I have done the first half of the job. The domain registration is instant but the propagation of the domain’s DNS would take some time (upto 72 hours on FreeNom). In the mean time I could setup the DNS server.

After much fiddling with the installation and configuration of BIND9 DNS server on Ubuntu, I finally created a bash script to automate the setup of DNS zones using BIND server.

If you are interested in setting up a DNS server, please make changes (domain name, subdomains, elastic IP, etc) to the following script. Also don’t forget to run it with sudo permission.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
apt install bind9 bind9-doc -y

echo 'include "/etc/bind/named.conf.log";' | tee -a /etc/bind/named.conf

# Store all the logs to /var/log/named/bind.log

tee /etc/bind/named.conf.log << EOF
logging {
 channel bind_log {
   file "/var/log/named/bind.log" versions 3 size 5m;
   severity info;
   print-category yes;
   print-severity yes;
   print-time yes;
 };
 category default { bind_log; };
 category update { bind_log; };
 category update-security { bind_log; };
 category security { bind_log; };
 category queries { bind_log; };
 category lame-servers { null; };
};
EOF

# Create the directory for storing logs

mkdir /var/log/named
chown bind:root /var/log/named
chmod 775 /var/log/named/

service bind9 restart

# Setup log rotation

tee /etc/logrotate.d/bind << EOF
/var/log/named/bind.log
{
    rotate 90
    daily
    dateext
    dateformat _%Y-%m-%d
    missingok
    create 644 bind bind
    delaycompress
    compress
    notifempty
    postrotate
        /bin/systemctl reload bind9
    endscript
}
EOF

# Change the zone to your domain name

tee /etc/bind/named.conf.local << EOF
zone "machane.ga" {
        type master;
        file "/etc/bind/zones/db.machane.ga";
};
EOF

mkdir /etc/bind/zones

# Creating the zone files
# Setting AWS elastic IP

ElasticIP=xx.xx.xx.xx

# Please dont forget . at the end of the DNS entries

tee /etc/bind/zones/db.machane.ga << EOF
\$TTL 900
@       IN      SOA     ns1.machane.ga. admin.machane.ga. (
                                1       ;<serial-number>
                              900       ;<time-to-refresh>
                              900       ;<time-to-retry>
                           604800       ;<time-to-expire>
                              900)      ;<minimum-TTL>
;List Nameservers
        IN      NS      ns1.machane.ga.
        IN      NS      ns2.machane.ga.
;Create A record
        IN      A       127.0.0.1
;address to name mapping
ns1     IN      A       $ElasticIP
ns2     IN      A       $ElasticIP
;wildcard DNS entry
*       IN      A       127.0.0.1
EOF

service bind9 restart

In the above script, I have explicitly mentioned that machane.ga and *.machane.ga (except the subdomains ns1 and ns2) resolve to 127.0.0.1. Once the registered domain has propagated its DNS changes around the world, anyone could query the domain and its subdomains.

I have finally created an authoritative DNS server which resolves any subdomain of machane.ga. It will not resolve DNS of any other domain.

I did this to experiment and learn more about how DNS works (in real life) and DNS servers. I gained a good experience and had a lot of fun along the learning process.

Until my next experiment, hasta la vista.

DISCLAIMER: I have registered the domain for experimental purpose for a single month. Any changes done to the domain’s DNS after a month (from the time of writing this article) will not be me. I am not be responsible for any damage done by reusing the above bash script.