dokku-dns: Automated DNS Management for Self-Hosted Apps

12/4/2025

dokku-dns: Automated DNS Management for Self-Hosted Apps

Managing DNS records manually is tedious. You deploy an app, add a domain, then remember you need to log into your DNS provider, find the right zone, create an A record, wait for propagation, and hope you didn't typo anything. Then multiply that by every domain change, every app deployment, every subdomain you add.

I lived this workflow for years with DNS hosted on Hover.com. Every time I added a subdomain or deployed a new app, I'd switch to my browser, log in, navigate to the right zone, and manually create records. It was friction I accepted as part of self-hosting.

Then I built dokku-dns to eliminate this workflow entirely. It's a Dokku plugin that automatically manages DNS records across AWS Route53, Cloudflare, and DigitalOcean. I moved my DNS from Hover to AWS Route53 specifically because they have a proper API - and built support for Cloudflare and DigitalOcean since they're popular among self-hosters.

The magic happens through two commands: dns:triggers:enable and dns:zones:enable.

The Manual Tools Are There If You Want Them

Before diving into automation, it's worth noting that dokku-dns gives you full manual control. You can:

dokku dns:apps:enable myapp              # Enable DNS for an app
dokku dns:apps:sync myapp                # Manually sync DNS records
dokku dns:sync-all                       # Sync all apps at once
dokku dns:apps:disable myapp             # Turn off DNS management

These commands are useful for debugging, one-off situations, or if you prefer explicit control. But the real power comes from not needing them at all.

The Magic: Triggers + Zones

The automation happens when you enable two things:

dokku dns:zones:enable example.com       # Tell it which zones to manage
dokku dns:triggers:enable                # Enable automatic management

That's it. From this point forward, DNS management becomes invisible.

What Triggers Actually Do

Dokku has a powerful hook system that fires on lifecycle events. dokku-dns taps into these hooks:

  • post-domains-update - Fires when you add or remove domains
  • post-delete - Fires when you destroy an app
  • post-create - Fires when you create a new app

When triggers are enabled, dokku-dns listens to these events and automatically performs the right DNS operations.

Walking Through the Automation

Creating an App

The most common workflow is creating a new app with a domain:

$ dokku apps:create fresh-test-app1
-----> Creating fresh-test-app1...

-----> DNS: Record for 'fresh-test-app1.example.com' created successfully
-----> Creating new app virtual host file...

Behind the scenes, dokku-dns:

  1. Detects the post-domains-update trigger fired
  2. Checks if fresh-test-app1.example.com is in an enabled zone
  3. Adds the domain to DNS tracking for the app
  4. Automatically creates an A record pointing to your server's IP
  5. Confirms the record was created successfully (shown inline)

You see your normal Dokku output, plus a line confirming DNS was updated. No separate commands. No logging into your DNS provider. No waiting to remember which zones exist or what your server IP is.

Adding More Domains

dokku domains:add myapp www.example.com
dokku domains:add myapp api.example.com
dokku domains:add myapp admin.example.com

Each command triggers automatic DNS record creation. Three domains, three A records, zero manual DNS work.

Removing Domains and Apps

When you remove a domain or destroy an app:

dokku domains:remove myapp example.com
# or
dokku apps:destroy myapp

The plugin automatically detects the change and queues the DNS records for deletion rather than immediately removing them.

This queued deletion is a critical safeguard to protect your zones from accidental or premature removal of public records. DNS deletions are permanent and disruptive. If you accidentally remove a domain or destroy the wrong app, your DNS records remain intact until you explicitly confirm deletion.

When you're ready to clean up orphaned records:

dokku dns:sync:deletions

This batch-deletes all queued records at once. This manual step transforms from a minor annoyance into an intentional security feature - you're explicitly confirming that yes, these DNS records should be removed from the public internet. It prevents the common mistake of destroying an app in a panic or by accident, only to realize later that you've taken down public DNS records that other systems might still depend on.

Zone-Based Intelligence

The dns:zones:enable command tells dokku-dns which domains it should manage. This is crucial for two reasons:

  1. Multi-zone support - You might have example.com in Cloudflare and api.io in Route53
  2. Safety - It won't touch zones you haven't explicitly enabled

When you add a domain that's not in an enabled zone, dokku-dns ignores it. This prevents accidentally managing DNS for domains you handle elsewhere.

You can check which zones are enabled:

dokku dns:zones

And enable additional zones anytime:

dokku dns:zones:enable api.io
dokku dns:zones:enable staging.com

Multi-Provider Support

dokku-dns works with three DNS providers:

  • AWS Route53
  • Cloudflare
  • DigitalOcean

The plugin has no dependencies besides bash and jq. You only need to install the CLI tool for whichever DNS provider you use - aws-cli for Route53, doctl for DigitalOcean, or nothing extra for Cloudflare (uses their API directly).

Configure a provider once:

# Route53
dokku config:set --global AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy
dokku dns:providers:verify aws

# Cloudflare
dokku config:set --global CLOUDFLARE_API_TOKEN=xxx
dokku dns:providers:verify cloudflare

# DigitalOcean
dokku config:set --global DIGITALOCEAN_ACCESS_TOKEN=xxx
dokku dns:providers:verify digitalocean

The plugin automatically routes each domain to the correct provider based on which provider hosts that zone.

Cron Job for Dynamic IPs

If your server doesn't have a static IP address, dokku-dns includes a cron job feature:

dokku dns:cron --enable --schedule "*/15 * * * *"

This periodically checks if your server's IP has changed and automatically updates all DNS records. Perfect for home servers on residential internet connections where your ISP might change your IP unexpectedly.

Removing the Mental Load

The real benefit isn't just saving commands - it's removing DNS from your mental model entirely. When working with Dokku, you think:

  1. Deploy my app
  2. Add a domain
  3. It works

You don't think about DNS at all. The plugin handles record creation, IP updates, and cleanup invisibly.

This is especially valuable when:

  • Experimenting with domains - Try subdomains freely without DNS busywork
  • Managing multiple apps - DNS stays consistent across dozens of apps
  • Working with staging/production - Domain changes don't require separate DNS updates
  • Onboarding team members - They don't need DNS provider access or knowledge

Debugging and Visibility

When you do need to check DNS status:

dokku dns:report myapp

Shows:

  • Server IP
  • All domains for the app
  • DNS status for each domain (✅ CORRECT, ⚠️ WARNING, ❌ ERROR)
  • Which DNS provider manages each zone

This makes debugging DNS issues straightforward - you can immediately see if a record exists, if it points to the right IP, or if there's a problem.

Why Not Just Use wildcard DNS?

Wildcard DNS (*.example.com) is simpler for some use cases, but has limitations:

  1. No subdomain control - Can't delegate api.example.com to a different server
  2. Certificate challenges - Some cert issuers don't support wildcard validation
  3. External services - Can't point domains to external services
  4. Multi-server setups - Can't route different domains to different servers

dokku-dns gives you per-domain control while automating the tedious parts.

Installation and Setup

Getting started takes about 5 minutes:

# Install the plugin
sudo dokku plugin:install https://github.com/deanmarano/dokku-dns.git --name dns

# Configure your DNS provider (example: Route53)
dokku config:set --global AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy
dokku dns:providers:verify aws

# Enable automation
dokku dns:zones:enable example.com
dokku dns:triggers:enable

For existing apps with domains already configured:

# Enable DNS management for existing apps
dokku dns:apps:enable myapp

# Sync records for all existing domains
dokku dns:apps:sync myapp

Living With It

I've been running dokku-dns on my homelab for months. It manages DNS for 22 apps across multiple zones in AWS Route53. I honestly forget it exists most of the time - which is exactly the point.

The only time I interact with it manually is running dns:sync:deletions after removing apps.

If you're running Dokku and manually managing DNS, this plugin eliminates an entire category of operational work. Two commands (triggers:enable and zones:enable) and you're done thinking about DNS.

Check it out: github.com/deanmarano/dokku-dns