DEV Community

Cover image for Split Horizon DNS in AWS Made Easy!
Dakota Lewallen
Dakota Lewallen

Posted on

Split Horizon DNS in AWS Made Easy!

Originally published to

A few months ago, I deployed my first private hosted zone to Route 53. Unbeknownst to me, I had set up a split horizon DNS scenario. My public zone was routing calls to my load balancer correctly. But every time my resources deployed in the VPC called into the same domain, it would result in errors like...
getaddrinfo ENOTFOUND _domain_...
I spun and thrashed and tried everything I could think of. Then after hours of debugging, while doing some "pair debugging" they made the suggestion that we duplicate the A record in the public zone into the private zone. Lo and behold problem is solved. So, if you have resources deployed to a VPC and a private zone attached to said VPC, and a public zone sharing the domain name. When your resources are all in the domain, it will use the private zone and the private zone only for resolution.
I spent some time learning and digging deeper into Route53 and DNS in general, to better understand the situation and why the solution was what it was. I found this article in the Route53 docs that explained almost the exact situation I was in. Considering how much I enjoy working with the CDK, and how much I struggled with this DNS configuration. I figured what better way to improve my understanding than to build a solution, that hopefully will help others avoid the headache I went through.


The aws-cdk-split-horizon-dns CDK construct!

import { SplitHorizonDns, AliasTarget } from 'aws-cdk-split-horizon-dns'

const firstTarget: AliasTarget = {
  target: [''],
  private: true,

const bucketWebsite = new s3.Bucket(stack, 'BucketWebsite', {
  bucketName: exampleDomain, //
  publicReadAccess: true,
  websiteIndexDocument: 'index.html',

const constructTarget: AliasTarget = {
  target: new targets.BucketWebsiteTarget(bucketWebsite),
  public: true,

new SplitHorizonDns(scope, 'MyDNS', {
  zoneName: '',
  privateZoneVpcs: [vpc],
  targets: [constructTarget, firstTarget],
Enter fullscreen mode Exit fullscreen mode

Pass it your domain name, any vpc's you want to be attached to the private zone, and a list of either resources or IPs you would like A records for, and boom. Pack it up and send it. For the resources, you can flag them as public, private, or both. And the rest is taken care of.
This project is still early stages. So if you try it and have success. Let me know! Or if this manages to bring the whole house down, please also let me know! Future goals will depend pretty highly on what's demanded of the construct. I would imagine there will be some want for being able to specify the record type that gets created. As with this initial release it is limited to A records. Additionally, a point of configuration that will likely be added soon is the ability to set the TTL of the record.
As of now, support for TypeScript is being tested. Python is included, but untested. If you want your stack included in the project, feel free to open an issue or PR here in the repository.

Hope this helps!

Find me on Mastodon | LinkedIn | Github | Substack

Top comments (0)