Skip to main content

Command Palette

Search for a command to run...

How I Developed a DNS Server to Explore Networking: The NexoralDNS Story

Updated
5 min read
A

System-level engineer building reliable backend systems with a focus on performance, correctness, and real-world constraints. I work across APIs, databases, networking, and infrastructure, enjoy understanding how systems behave under load and failure, and write to break down complex backend and distributed-systems concepts through practical, real-world learnings.

Why This Project Exists (The Real Reason)

NexoralDNS didn’t start as a “product idea”.

It started with curiosity.

When I first tried to learn how DNS servers work—from blogs and YouTube—the explanations felt abstract:

  • UDP call on port 53

  • recursive resolver

  • authoritative response

  • domain hierarchy

I understood the words, but not the flow.

So I asked myself a simple question:

If DNS is just a UDP server listening on port 53, what happens if I build one myself?

That question is where NexoralDNS was born.


The First Curiosity That Changed Everything

DNS uses UDP, and Node.js has dgram.

So I thought:

  • What if I start a UDP server on port 53?

  • What if I point my router’s DNS to my laptop’s private IP?

  • Will it actually resolve domains?

I tried it.

It worked.

That single experiment changed my understanding completely.

At that moment, DNS stopped being “magic infrastructure” and became:

Packets → Buffers → Logic → Response

And once that clicked, I went deeper.


What NexoralDNS Actually Provides

NexoralDNS is a LAN-focused, programmable DNS server built to understand and control DNS behavior at a low level.

It currently provides:

  • A custom DNS server handling UDP 53

  • Domain parsing from raw Buffer data

  • Recursive domain hierarchy understanding (sub → root → TLD)

  • Rule-based domain control (block, allow, redirect)

  • Admin panel to control DNS behavior

  • Internal service-to-service communication using a custom TCP broker

  • Automatic rebinding when IP changes via DHCP signals

It’s not meant to replace Cloudflare or public resolvers.
It’s meant for offices, labs, learning, and internal networks.


Architecture (Why Multi-Folder Matters)

The project is intentionally multi-folder, because I designed it for future evolution.

Folder Breakdown

  • Core DNS Engine

    • Handles UDP packets

    • Parses DNS queries from raw buffers

    • Generates responses

    • Uses Node Cluster for concurrency

  • DHCP

    • Listens for IP changes

    • Detects when DNS server IP changes

    • Notifies other services to rebind port 53

  • Broker

    • Custom TCP-based message broker

    • Built to understand service notifications

    • Replaced RabbitMQ intentionally to learn internals

  • Server

    • Admin APIs written in Fastify

    • Controls rules, domains, and configs

  • Web

    • Admin UI built with Next.js

    • Visual control over DNS rules and analytics

This separation makes one thing very important:

If I replace the Core DNS engine with Golang later,
I only need to change the core — not the Web or Admin layers.

That decision was deliberate.


Why I Chose Node.js Over Golang or Rust (Honestly)

Let me be blunt.

I didn’t choose Node.js because it’s the “best” language for DNS.

I chose it because:

  • I know Node.js deeply

  • I understand async behavior

  • I can move fast with logic

  • I trust myself to debug it

At the beginning, confidence matters more than performance.

I knew:

  • If I picked Golang without deep networking confidence, I’d stall

  • If I picked Rust, I’d fight the compiler instead of learning DNS

My belief:

Logic > Language

Languages can change.
Understanding packet flow, recursion, and hierarchy is permanent.


What I Learned While Building This

This project taught me things no tutorial ever could:

1. DNS Parsing from Raw Buffers

  • How queries arrive as binary

  • How to extract:

    • Domain name

    • Query type (A, AAAA, CNAME, etc.)

  • How compression pointers work

2. Recursive Domain Hierarchy

  • Why DNS is not just a lookup

  • How delegation works

  • How recursion actually flows internally

3. UDP Is Stateless (And That Matters)

  • No connection

  • No retry guarantee

  • You must respond fast

4. Node Cluster for DNS

To improve performance:

  • I used Node.js Cluster

  • Spread UDP load across CPU cores

With this setup, NexoralDNS handled:

~7,000 QPS, measured using dnsperf

That number surprised me.


Performance Reality Check

Let’s be honest again.

  • Node.js at ~7k QPS: good

  • Golang at the same logic: 10k+ QPS easily

I know this.

That’s why my future plan is clear:

  • Rewrite the Core DNS handler in Golang

  • Keep Admin, Web, and Control layers intact

Before that:

I need to understand networking deeply — not just write faster code.

I’m learning Go now, slowly and correctly.


Why I Built My Own TCP Broker

Before using RabbitMQ, I asked:

Do I really understand how message brokers work?

So I built one.

A simple TCP-based message broker that:

  • Allows one service to notify another

  • Used by DHCP → Web → DNS engine

  • Handles rebinding and runtime coordination

This taught me:

  • Why brokers exist

  • Where RabbitMQ adds value

  • Where custom solutions make sense

This wasn’t about replacing RabbitMQ.
It was about earning the right to use it knowingly.


The Bigger Picture

NexoralDNS is not about DNS alone.

It’s about:

  • Understanding networking fundamentals

  • Removing fear from “core systems”

  • Proving that curiosity + experiments beat tutorials

I didn’t build this to impress anyone.
I built it because I wanted answers.

And now I have them.


What’s Next

  • Rewrite Core DNS engine in Golang

  • Improve rule engine performance

  • Better analytics for LAN usage

  • Hardening broker communication

  • Deeper recursion optimizations

This project already did its job:

It turned DNS from theory into intuition.

And that was the real goal.

More from this blog

A

AnkanHub

16 posts