Syncing AWS Route53 records to GoDaddy with Laravel
I was recently working in a project where I had to work with a lot of domains, I mean a lot... I was getting tired of constantly making DNS updates every time my client purchase a domain in GoDaddy. I do have terraform setup for the project, which means I can simply add a domain to AWS with couple of lines, but I couldn't find a terraform module to sync the nameserver records back to GoDaddy. So I ended up writing a simple artisan command in Laravel which can do this for me. There could be many ways (better ways) to do it, but I did in a pretty short time and it saves me a lot of time. Let's see how I did it.
Step 1 : Grab the API keys from Godaddy
- Go to https://developer.godaddy.com/
- Sign into your Go Daddy account.
- Select API Keys
- Select Create New API Key
- Give a name like AWS-GODADDY
- Select Production under Environment.
- Click Next and Grab the Keys
Step 2 : Create AWS Credentials [TLDR; version]
- Login to your AWS Account
- Go to IAM
- Create API keys with Route53 permissions
Now that we have what we need, let's prepare the Laravel side of the app.
Step 3: Install the required packages
composer require aws/aws-sdk-php-laravel
PS: If you have the league/flysystem-aws-s3-v3
package installed, then you don't need the above step.
Let's create the command next.
php artisan make:command SyncDNSRecordsCommand
Then I created a method to fetch the NS records from AWS.
private function getAWSHostedZoneDNS($domain){
$key = 'YOUR\_AWS\_KEY\_HERE';
secret = 'YOUR\_AWS\_SECRET\_HERE';
$region = 'YOUR\_AWS\_REGION\_HERE';
$credentials = ['region' => $region, 'version' => 'latest', 'credentials' => [ 'key' => $key, 'secret' => $secret,], ];
$client = new Route53Client($credentials);
$awsDomain = $client->listHostedZones(['dnsname' => "$domain."] )->toArray()['HostedZones'];
$hostedZoneId = collect($awsDomain)
->filter(fn($zone) => $zone['Name'] == "$domain.")
->map(fn($zone) => $zone['Id'])
->values()
->get(0);
return $client->getHostedZone(['Id' => $hostedZoneId])->toArray(['DelegationSet']['NameServers'];
}
and then another helper to update the DNS records to GoDaddy
private function updateGodaddyDNS($domain, $hostedZone){
$url = "https://api.godaddy.com/v1/domains/{$domain}";
$header = ['Authorization' => 'sso-key ' . $this->godaddyAPIKey . ':' . $this->godaddyAPISecret];
return \Http::withHeaders($header)->patch($url, [ 'nameServers' => $hostedZone
])->body();
}
I also made another method to fetch the updated DNS records, so that I can verify it once updated.
private function getGodaddyDNS($domain){
$url = "https://api.godaddy.com/v1/domains/{$domain}";
$header = ['Authorization' => 'sso-key ' . $this->godaddyAPIKey . ':' . $this->godaddyAPISecret];
$domainDetails = \Http::withHeaders($header)->get($url)->body();
$domainDetails = json_decode($domainDetails, true);
return $domainDetails['nameServers'];
}
With these methods in place, my final logic looked like this.
public function handle(){
$domain = $this->argument('domain');
$this->godaddyAPIKey = 'GODADDY\_KEY\_HERE'; $this->godaddyAPISecret = 'GODADDY\_SECRET\_HERE';
$godaddyDNS = $this->getGodaddyDNS($domain);
$AWSHostedZoneDNS = $this->getAWSHostedZoneDNS($domain);
if (collect($godaddyDNS)->diff(collect($AWSHostedZoneDNS))->isNotEmpty()) {
$this->info("NAMESERVERS Not Matching");
$this->info(join(', ', $godaddyDNS));
$this->info(join(', ', $AWSHostedZoneDNS));
if ($this->confirm("Update Nameservers?")) {
$resp = $this->updateGodaddyDNS($domain, $AWSHostedZoneDNS);
$this->info($resp);
}
}
else { $this->info("Nameservers matched");
}
}
You can see that I have collection returned from AWS, and I had to filter the domain I am looking for to update, that's because I cannot get the correct hosted zone without the ID and I am looking to find the hosted zone with the domain.
I hope this helps someone. If you have any doubts or issues, you can leave a comment 🙃 . I will try to get back to you as soon as possible.