Dynamic DNS (DDNS) is a method that automatically updates the name servers in the Domain Name System (DNS) with new IP addresses as they change, particularly for devices with dynamic IPs. In this blog, we’ll build a DDNS system using AWS services and TypeScript while leveraging DynamoDB for IP storage and S3 for hosting.

1. Introduction to Dynamic DNS Systems

Dynamic DNS allows devices where an ISP assigns dynamic IP addresses to maintain a stable domain name. Users can avoid disruptions in accessing services hosted on these devices by frequently updating DNS records as the IP changes.

AWS offers the ideal ecosystem to implement a serverless DDNS solution with cost-effective scalability. We’ll use S3 for static website hosting, DynamoDB for IP storage, API Gateway for interacting with the DDNS service, Lambda for backend processing, and Route 53 to manage custom domains.

2. Setting Up AWS for DDNS

Before diving into the code, we must ensure the AWS environment is set up for the DDNS system. Here are the services we will need:

  • Amazon S3 for hosting static content.
  • DynamoDB stores the IP addresses.
  • Lambda for updating the IP address.
  • API Gateway to trigger Lambda functions.
  • Route 53 for DNS management.

Ensure you have an AWS account with appropriate permissions to create these resources.

3. Creating an S3 Bucket for Hosting

The first step is to create an S3 bucket to host static content for the DDNS service, such as configuration files or simple status pages.

  • Navigate to the S3 console and create a new bucket with a unique name.
  • Enable static website hosting under the Properties tab.
  • Upload any static content, such as a status page or instructions, that will reside in the bucket.

4. Configuring S3 Bucket Permissions

Since we’re hosting content publicly, we need to set up the correct permissions for the S3 bucket:

  • In the Permissions tab, update the Bucket Policy to allow public read access:

{

  “Version”: “2012-10-17”,

  “Statement”: [

    {

      “Sid”: “PublicReadGetObject”,

      “Effect”: “Allow”,

      “Principal”: “*”,

      “Action”: “s3:GetObject”,

      “Resource”: “arn:aws:s3:::your-bucket-name/*”

    }

  ]

}

  • Ensure you also enable public access for objects by modifying the bucket settings.

5. Establishing a DynamoDB Table for IP Storage

We’ll use DynamoDB to store and manage the current IP address of the devices:

  • Go to the DynamoDB console and create a new table.
  • Set a Partition Key named hostname (this will store the domain or device name).
  • Optionally, set up an additional Sort Key for future use, such as logging timestamped IP changes.

This table will serve as our backend database to dynamically track IP addresses.

6. Crafting the Lambda Function for IP Updates

Now that our DynamoDB table is ready, the next step is to create a Lambda function that updates the IP address in the table.

  • Navigate to the Lambda console and create a new Lambda function.
  • Write the logic that extracts the current IP address from incoming requests and updates the DynamoDB table using TypeScript.

Here’s a basic TypeScript code snippet for the Lambda function:

import { DynamoDB } from “aws-sdk”;

const dynamoDb = new DynamoDB.DocumentClient();

exports.handler = async (event: any) => {

  const hostname = event.queryStringParameters?.hostname;

  const ip = event.requestContext.identity.sourceIp;

  if (!hostname) {

    return { statusCode: 400, body: “Hostname is required” };

  }

  const params = {

    TableName: “DDNS_IP_Table”,

    Key: { hostname },

    UpdateExpression: “set ip = :ip”,

    ExpressionAttributeValues: { “:ip”: ip },

  };

  await dynamoDb.update(params).promise();

  return { statusCode: 200, body: `IP updated to ${ip}` };

};

7. Integrating Lambda with API Gateway

We’ll now expose the Lambda function using API Gateway:

  • Go to API Gateway and create a new REST API.
  • Create a resource and method (such as a GET request) to trigger the Lambda function when called.
  • Add query string parameters (like hostname) to pass data to the Lambda function.
  • Deploy the API to a stage for public access.

8. Deploying the API Gateway

Once your API Gateway is configured, deploy the API and test its functionality by requesting the endpoint with the hostname parameter:

https://your-api-id.execute-api.region.amazonaws.com/Prod/update-ip?hostname=my-device

This will trigger the Lambda function and update the device’s IP in DynamoDB.

9. Configuring Custom Domain via Route 53

To make the DDNS system accessible via a custom domain, we’ll configure Route 53:

  • Register or transfer your domain to Route 53 if you haven’t already done so.
  • Create an A record in Route 53, pointing to the dynamic IP address we’ll manage via our system.
  • Use the Route 53 Alias feature to map your API Gateway’s custom domain to the domain name you own.

10. Testing the DDNS Setup

Once all the components are set up, test the full DDNS setup:

  • Make requests to your API Gateway endpoint to simulate IP address changes.
  • Verify that the DNS record is updated correctly in Route 53.
  • Test accessing your custom domain to ensure the updated IP is resolved correctly.

Conclusion

By combining TypeScript, DynamoDB, S3, Lambda, API Gateway, and Route 53, we’ve built a cost-effective, scalable, and serverless DDNS solution on AWS. This dynamic DNS system ensures that users can always reach their devices even if the IP addresses change frequently.

References

Building a serverless dynamic DNS system with AWS

Create a CRUD HTTP API with Lambda and DynamoDB