Intro

Hey Everybody,

Happy New Year! This is my first post of 2026, and I’m excited to share how I currently manage DNS.

DNS is definitely something you need to be intentional with. It’s simple to launch VMs or services in your network, and have them floating around without a proper DNS record. While this might be acceptable for a temporary service, it is best practice to set a DNS record for anything permanent.

Setup

If you’re like me, then nothing is worse than needing to do things manually. Especially the extremely tedious task of clicking my way through Cloudflare’s portal and updating DNS by hand!

Luckily I’ve been able to navigate around this, please follow along below as I elaborate how:

  1. Cloudflare

Cloudflare is paramount to me, it is where I host all of my domains. While I do run a local DNS server, this is for performance reasons, and not for management of my DNS records. Another bonus is it provides me an API that I can use to programmatically create DNS records.

  1. Terraform

Terraform is the core component behind my DNS management. Terraform provides me a smooth, effortless method to automate the creation of my DNS records. I save my .tfstate file in an S3 bucket, but all my code is tracked via source control, which is extremely useful.

  1. CI/CD

Finally, I use CI/CD to tie it all together. My CI/CD pipeline is just a modest GitHub runner workflow. This enables me to run a few trivial checks (mainly linting) as well as retrieving my Cloudflare API token supplied as a secret in GitHub. Terraform then utilizes this secret to access Cloudflare and update DNS on my behalf!

Here is a high-level diagram of the flow:

alt text

While I won’t go into all the details of my Terraform code, I created a module that leverages Cloudflare’s DNS Provider. I can easily update the main.tf on a per zone basis and provision records for each zone(domain) hosted on Cloudflare.

alt text

An additional benefit is that everything is tracked in git. Each change must go through a CI/CD check and even though it’s only me who manages this at home, in a production environment you might have several developers committing changes to DNS at a time.

alt text

Here is my GitHub Actions workflow. It is extremely straightforward, but checks off all my boxes!

name: Terraform CI/CD

on:
  push:
    branches:
      - main
      - master

env:
  TF_IN_AUTOMATION: true

jobs:
  terraform:
    name: Terraform Fmt → Plan → Apply
    runs-on: ubuntu-latest

    env:
      TF_VAR_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.8

      - name: Terraform Init
        working-directory: dns/zone
        run: terraform init -backend-config="access_key=${{ secrets.AWS_ACCESS_KEY_ID }}" -backend-config="secret_key=${{ secrets.AWS_SECRET_ACCESS_KEY }}"

      - name: Terraform Fmt Check
        working-directory: dns/zone
        run: terraform fmt -check -recursive

      - name: Terraform Validate
        working-directory: dns/zone
        run: terraform validate

      - name: Terraform Plan
        working-directory: dns/zone
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
        run: terraform plan -out=tfplan

      - name: Terraform Apply
        working-directory: dns/zone
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
        run: terraform apply -auto-approve tfplan

Summary

At the end of the day, managing DNS is a huge PITA. That being said, with the help of some automation, we can make our lives a lot easier!