Skip to content
AWS aws networking 5 min read

DNS Inside a VPC

Every resource inside a Virtual Private Cloud (VPC, your own private network in AWS) needs a way to turn names like db.internal or s3.amazonaws.com into IP addresses. That job is done by DNS (the Domain Name System, the internet’s “phone book”). AWS gives every VPC a built-in DNS resolver, but two small settings control how well it works — and getting them wrong is one of the most common reasons a custom VPC behaves strangely. This page explains how VPC DNS works and how to configure it correctly.

The Amazon-provided DNS resolver

When you create a VPC, AWS automatically runs a DNS resolver for you. This resolver is sometimes called the Amazon-provided DNS or the Route 53 Resolver. You reach it at a special, reserved IP address: the base of your VPC CIDR block plus two.

So if your VPC uses the range 10.0.0.0/16, the resolver lives at 10.0.0.2. There is also a fixed link-local address that always works from any VPC: 169.254.169.253.

This resolver does several jobs:

  • Resolves public internet names (like www.google.com) for instances that can reach the internet.
  • Resolves the internal AWS records for your instances (their private DNS names).
  • Resolves names in any private hosted zone you attach to the VPC (more on that below).
  • Resolves the special private DNS names used by VPC interface endpoints.

The .2 resolver address only answers queries that come from inside the VPC. You cannot query it from your laptop at home or from another VPC unless you set up a Route 53 Resolver inbound endpoint.

The two settings that control everything

VPC DNS behaviour is controlled by two attributes on the VPC. They are easy to overlook because they are buried in the VPC settings, but they decide whether your instances get DNS names at all.

AttributeWhat it doesDefault in your custom VPC
enableDnsSupportTurns the Amazon resolver at .2 on or off. When off, instances cannot resolve any DNS names through AWS.true (enabled)
enableDnsHostnamesDecides whether instances with a public IP receive a public DNS hostname (like ec2-203-0-113-25.compute-1.amazonaws.com).false (disabled)

Here is the gotcha that trips up almost everyone:

An instance only gets a public DNS hostname when BOTH enableDnsHostnames AND enableDnsSupport are turned on. The default VPC has both set to true, so it “just works”. A VPC you create yourself has enableDnsHostnames set to false, so your instances launch with a public IP but no public DNS name. This is the number-one reason custom VPCs “resolve oddly”.

These same two flags also gate interface endpoints. If you enable a VPC interface endpoint (for example, a private endpoint to reach Amazon S3 or Secrets Manager without using the internet) and turn on its private DNS, it will silently fail to resolve unless both DNS settings are on.

Checking and changing the settings (Console)

  1. Open the VPC console and choose Your VPCs in the left menu.
  2. Select your VPC (for example vpc-0a1b2c3d).
  3. Choose Actions → Edit VPC settings.
  4. Tick Enable DNS resolution (this is enableDnsSupport).
  5. Tick Enable DNS hostnames (this is enableDnsHostnames).
  6. Choose Save.

Checking and changing the settings (CLI)

Check the current values:

aws ec2 describe-vpc-attribute \
  --vpc-id vpc-0a1b2c3d \
  --attribute enableDnsHostnames

Output:

{
    "VpcId": "vpc-0a1b2c3d",
    "EnableDnsHostnames": {
        "Value": false
    }
}

Turn both attributes on (they must be set one at a time):

aws ec2 modify-vpc-attribute \
  --vpc-id vpc-0a1b2c3d \
  --enable-dns-support

aws ec2 modify-vpc-attribute \
  --vpc-id vpc-0a1b2c3d \
  --enable-dns-hostnames

These commands print no output on success.

Setting it in infrastructure as code

If you build VPCs with Terraform, set both flags when you create the VPC so you never hit the gotcha:

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "main-vpc"
  }
}

Private hosted zones for internal names

A private hosted zone is a Route 53 DNS zone that is only visible inside the VPCs you attach it to. It lets you use friendly internal names — like db.prod.internal or cache.prod.internal — instead of memorising private IP addresses. The names never leak to the public internet.

When to use this: when services inside your VPC need stable, human-readable names for each other (databases, internal APIs, caches), and you want those names hidden from the outside world. When NOT to: for names that must be reachable from the public internet — those belong in a public hosted zone.

Creating a private hosted zone (Console)

  1. Open the Route 53 console and choose Hosted zones.
  2. Choose Create hosted zone.
  3. Enter a Domain name, for example prod.internal.
  4. Under Type, choose Private hosted zone.
  5. Choose the Region and select your VPC (vpc-0a1b2c3d).
  6. Choose Create hosted zone, then add records (for example an A record db.prod.internal → 10.0.1.50).

Creating a private hosted zone (CLI)

aws route53 create-hosted-zone \
  --name prod.internal \
  --vpc VPCRegion=us-east-1,VPCId=vpc-0a1b2c3d \
  --caller-reference "prod-internal-$(date +%s)" \
  --hosted-zone-config PrivateZone=true

Output:

{
    "HostedZone": {
        "Id": "/hostedzone/Z0123456789ABCDEFGHIJ",
        "Name": "prod.internal.",
        "Config": {
            "PrivateZone": true
        },
        "ResourceRecordSetCount": 2
    },
    "VPC": {
        "VPCRegion": "us-east-1",
        "VPCId": "vpc-0a1b2c3d"
    }
}

A private hosted zone also requires enableDnsSupport and enableDnsHostnames to be true on the VPC, or the names will not resolve from your instances.

Cost note: the Amazon-provided resolver and standard query resolution are free. A private hosted zone costs about $0.50 per hosted zone per month, and DNS queries are billed at roughly $0.40 per million queries — effectively pennies for most workloads. Route 53 Resolver inbound/outbound endpoints cost more (around $0.125 per ENI per hour), so only add those when you need hybrid DNS with on-premises networks.

Best Practices

  • Always set both enableDnsSupport and enableDnsHostnames to true when you create a custom VPC — bake it into your Terraform or CloudFormation so you never debug it later.
  • Use private hosted zones for internal service names instead of hard-coding private IPs, so addresses can change without breaking callers.
  • Remember the resolver lives at VPC CIDR base + 2 (and 169.254.169.253); keep firewall and NACL rules from blocking UDP/TCP port 53 to it.
  • Enable both DNS settings before turning on private DNS for interface endpoints, or the endpoint names will silently fail to resolve.
  • Keep internal domains under a clearly private suffix (like .internal) so they never collide with real public domains.
  • Use VPC Flow Logs when DNS oddities persist — they help confirm whether traffic is even reaching the resolver.
Last updated June 15, 2026
Was this helpful?