Setup AWS Route53 Private Hosted Zone - Beginners Guide

Route53 Private Hosted Zone

In this step-by-step guide, you will learn to setup AWS Route53 Private hosted zone for private DNS resolution.

Need for Route53 Private Hosted Zone

AWS Route53 is managed DNS service where you can manage your DNS for AWS hosted resources and non-AWS resources.

When it comes to production level implementions, most applications reside in private VPC subnets. And if you want to use DNS names for private hosted services you need a internal private DNS.

Meaning, DNS that can only be accessed within VPC or from users workstation through VPN connectivity.

Here, the AWS Route53 Private hosted zone comes into the picture.

With private hosted zone, the DNS resolution will happen in the AWS internal DNS server and only within the VPC.

AWS Route53 Hosted Zone Workflow

The workflow diagram explains the AWS Route53 private hosted zone configurations as well as the integration of a VPN Server.

Here’s how it works:

  1. The Route53 private hosted zone is linked to a specific VPC. This allows AWS to attach internal DNS servers to that VPC.
  2. You create an A record in the hosted zone to map a private IP to a hostname.
  3. A secure and encrypted VPN tunnel is set up between your local machine and the VPC. When the VPN tunnel is active, the VPN server can push DNS settings (like the VPC DNS IP x.x.x.2) to the client.
  4. When the user connects through the VPN and tries to access the hostname of a private AWS resource, the DNS query goes to Route53's private hosted zone.
  5. The DNS lookup is resolved securely, and the traffic reaches the right destination in the VPC.

AWS Route53 Private Hosted Zone Setup

Now lets get started with the setup.

💡
We assuming you already have a VPC on your AWS account. If you dont have one, please create a VPC.

Follow the below steps to setup a private hosted zone in AWS Route53.

Step 1: Create a Private Hosted Zone

Open the AWS Route53 service and select the Hosted zones tab from the left side panel.

On the following window, click the Create hosted zone button to create a new hosted zone.

Provide a domain name that you want techiescamp.com, you can provide any name.

Select the types as Private hosted zone and on the VPC association section, select the region of the VPC and its ID.

Once provide all the required information, click the Create hosted zone button to create the private hosted zone.

After the successful creation of the private hosted zone, two records will be available by default.

What are they?

  1. The first one is the NS record which represents the Name Server Record. These records define the internal name servers that are responsible for the DNS resolution only within the VPC.
  2. The second one is the SOA which represents the Start of Authority Records, this will provide the metadata about the hosted zone, such as admin contact, serial number, and timing values(refresh, retry, and expire).

The Route53 private hosted zone setup is done, now we can test the setup.

Validating Route53 Private Hosted Zone

The private hosted zone setup is completed now.

So how can we test it?

Well. we can create a simpe Nginx server on the private subnet and map the IP of that server to the Route53 private hosted zone.

Then try to access it from the public server using the hostname.

For that, we need to create an EC2 instance on both public and private subnets.

Step 1: Create Test Servers on Both Subnets

You can manually open the EC2 console and create instances on both subnets, but for now, I am using a Cloudformation template for that.

Create a Cloudformation template file ec2-instance-template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Description: Launch Ubuntu EC2 instances in public and private subnets

Parameters:
  VPCId:
    Type: String
    Description: ID of the existing VPC
  PublicSubnetId:
    Type: String
    Description: ID of the existing Public Subnet
  PrivateSubnetId:
    Type: String
    Description: ID of the existing Private Subnet
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 KeyPair to enable SSH access

Resources:
  # Security Group for Ubuntu Public EC2
  UbuntuPublicSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Ubuntu Public EC2
      VpcId: !Ref VPCId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: Ubuntu-Public-SG

  # Security Group for Ubuntu Private EC2
  UbuntuPrivateSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Ubuntu Private EC2
      VpcId: !Ref VPCId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref UbuntuPublicSG
      Tags:
        - Key: Name
          Value: Ubuntu-Private-SG

  # Ubuntu EC2 Instance in Public Subnet (with Public IP)
  UbuntuPublicInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      ImageId: ami-084568db4383264d4  
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          SubnetId: !Ref PublicSubnetId
          GroupSet:
            - !Ref UbuntuPublicSG
      Tags:
        - Key: Name
          Value: Ubuntu-Public-Server

  # Ubuntu EC2 Instance in Private Subnet (no public IP)
  UbuntuPrivateInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      ImageId: ami-084568db4383264d4  
      SubnetId: !Ref PrivateSubnetId
      SecurityGroupIds:
        - !Ref UbuntuPrivateSG
      Tags:
        - Key: Name
          Value: Ubuntu-Private-Server

Outputs:
  UbuntuPublicInstanceId:
    Description: ID of the Ubuntu EC2 in public subnet
    Value: !Ref UbuntuPublicInstance

  UbuntuPrivateInstanceId:
    Description: ID of the Ubuntu EC2 in private subnet
    Value: !Ref UbuntuPrivateInstance

To deploy this, use the following command.

 aws cloudformation create-stack \   
  --stack-name EC2InstanceStack \
  --template-body file://ec2-instance-template.yaml \
  --parameters \
    ParameterKey=VPCId,ParameterValue=<VPC_ID> \
    ParameterKey=PublicSubnetId,ParameterValue=<PUBLIC_SUBNET_ID> \
    ParameterKey=PrivateSubnetId,ParameterValue=<PRIVATE_SUBNET_ID> \
    ParameterKey=KeyName,ParameterValue=<KEY_PAIRS> \
  --capabilities CAPABILITY_NAMED_IAM \
  --region <REGION>

Change the VPC ID, Subnets, and Key name with your values.

Step 2: Install an Nginx Web Server on the Private Server

Since the private server doesn't have public access, we can only access it from the public server.

So open the public server and SSH, to the private server, but before that note down the private server's IP address.

Now open the public server.

Select the EC2 Instance Connect option to connect the public server through the web terminal.

Create a .pem file in the public server and store the public key contents.

Using the following command, we can SSH to the private server to install the Nginx server.

ssh -i key.pem ubuntu@<PRIVATE_SERVER_IP>

To install Nginx on the Ubuntu server, use the following command.

sudo apt update
sudo apt install nginx -y
Note: The private subnet should be attached with NAT, otherwise application packages won't be downloaded from the internet for the Nginx installation.

To check the service after the installation,

systemctl status nginx.service

This ensures that the service is active and running, so now we need to check the localhost access.

curl localhost
s

You can see the welcome page, which means that the web server page is actively loading on the private server itself.

Now, we need to check it directly from the public server.

So, you need to exit from the private server using the following command.

exit

Before directly accessing the Nginx server from the public server, ensure the private server's security group allows port 80 to the public server.

Once the security group rules are correctly set, we can access the private Nginx server from the public server using its private IP.

curl <PRIVATE_SERVER_IP>

But this is not we want, we need to access this private Nginx server via a domain name.

Step 3: Map Private IP to the Hostname on Route53

We can map the same private IP to the Route53 private hosted zone, so that we can access this Nginx server using the hostname.

When we try to access, the DNS resolution will happen by the internal DNS servers, which AWS manages.

To map the private IP, navigate to the Route53 console private hosted zone and create a new DNS record.

Create a prefix for the record name e.g., nginx and select the record type as A which will map the IP with hostname.

In the Value section, we need to add the IP of the private Nginx server, then click to Create records to create the record.

It will take a few minutes to complete and then you can see the record on the dashboard.

Now, we can access the Nginx server from the public server using this hostname instead of the IP address.

curl <HOST_NAME>

It is working, but what if I want to access it from my local machine?

First, you need to establish a VPN connection between your local machine and the AWS VPC.

Validating Route53 Private Hosted Zone From Local Workstation using VPN

In this section, we will initiate the DNS resolution from the local machine to access the AWS resources securly over a VPN encrypted tunnel.

For this to work, we need a VPN connection between our local machine and the specific AWS VPC.

I am using the Pritunl Self-hosted VPN server for this demo, but you can use any VPN setup like OpenVPN, AWS Client VPN Endpoint, etc.

To know about the setup of the Pritunl VPN in an EC2 instance, you can refer to this blog How to Setup Pritunl VPN

Once the VPN connection is established, we can access the private Nginx server from our local machine by using its private IP as like we did in the public server.

Here, you can see that the DNS resolution is not happening. This is because the local system is not part of the AWS VPC and doesn't have DNS server details.

So, we need to add the DNS server details.

In the Pritunl configuration, we can provide the DNS server details, but how can we identify the DNS server information, such as its IP?

Well, for the custom DNS servers in the VPC, the IP of the DNS server is the second IP from the CIDR range. For example, if the VPC CIDR is 10.0.0.0/16, then the DNS server IP is 10.0.0.2.

To learn more about this, please refer to the official documentation.

We need to configure this for the DNS resolution on the VPN server configuration.

After changing the DNS server on the VPN configuration, when you establish the VPN connection from your local machine, your default DNS server configuration on the local machine will automatically be changed, and you can check that from the /etc/resolve.conf

This ensures that the resolution will happen only through this DNS server.

Now, we can check access from the local machine using the hostname.

Not only check from the terminal, but you can also directly check from the web browser.

Bonus Configuration

Instead of configuring the DNS server information directly to the VPN server, we can only configure it in our local machine to harden the security.

First, we need to keep the DNS details on the VPN server dashboard empty.

Now, configure the DNS server information on the local machine.

I am setting up on the MAC workstation, but it would be similar to every operating system.

On the DNS configuration section, add the DNS server IP

After adding the DNS server details on the local machine, we can use the hostname to access the private server resources in a secure manner.

After the hands-on, you can use the following commands to destroy the setup.

aws cloudformation delete-stack --stack-name EC2InstanceStack --region us-east-1

Difference Between Route53 Public and Private Hosted Zone

  1. A public hosted zone is for the resources accessed by the user over the internet, such as public websites, etc. Here, the DNS resolution will happen on public DNS servers
  2. A private hosted zone is for internal resources, such as databases, etc. Here, the DNS resolution only occurs within the network by the internal DNS servers.
⚠️
AWS ACM certificates cannot be directly validated by the Route53 private hosted zone. So, instead, we can use the ACM Private CA.

Conclusion

This is the effective method of using the Route53 Private hosted zone to access the private resources from the local machine.

You can use any VPN server to communicate between the local machine and the AWS VPC.

A single hosted zone creation will cost $0.50 per month. This will be the same up to 25 hosted zones, and if it goes beyond that, each new one will cost an additional $0.10 per month.

About the author
Arun Lal

Arun Lal

Arun Lal is a DevOps Engineer & AWS Community Builder, also an Expert in AWS infrastructure, Terraform automation, and GitLab CI/CD pipelines.

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to DevOpsCube – Easy DevOps, SRE Guides & Reviews.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.