6.2.a. Set Up DuckDNS
Goal
Configure a free DNS subdomain using DuckDNS to enable SSL certificate issuance from Let’s Encrypt, which requires a domain name rather than an IP address.
What you’ll learn:
- Why Let’s Encrypt requires domain names for certificates
- How to set up a free dynamic DNS subdomain
- How DNS A records map domains to IP addresses
- How to verify DNS configuration with command-line tools
Prerequisites
Before starting, ensure you have:
- ✓ Completed Tutorial 06 (Nginx Reverse Proxy) - understanding of reverse proxy concepts
- ✓ Azure CLI installed and logged in (
az login)- ✓ SSH keys configured (
~/.ssh/id_rsa.pub)
Exercise Steps
Overview
- Understand Why You Need DNS
- Create a DuckDNS Account
- Create a Subdomain
- Provision a Test VM
- Update Your DuckDNS Subdomain
- Verify DNS Configuration
Step 1: Understand Why You Need DNS
Before setting up DuckDNS, it’s important to understand why Let’s Encrypt requires a domain name. This knowledge will help you troubleshoot issues and make informed decisions about DNS configuration in production applications.
Let’s Encrypt issues SSL certificates for domain names, not IP addresses. This is because:
- Certificates bind identity to a domain (e.g.,
hellojava.duckdns.org) - IP addresses can change and be reassigned
- Domain ownership can be verified through DNS challenges
DuckDNS is a free dynamic DNS service that provides:
- Free subdomains (e.g.,
yourname.duckdns.org) - Simple API for updating IP addresses
- No cost - completely free for personal use
- Quick setup - takes just a few minutes
ℹ️ Concept Deep Dive
DuckDNS is ideal for tutorials because it’s free, fast to set up, and designed for dynamic IP addresses. For production applications, you would typically use your own domain with a DNS provider like Cloudflare or Azure DNS.
✓ Quick check: You understand that Let’s Encrypt needs a domain, not an IP address
Step 2: Create a DuckDNS Account
Set up your DuckDNS account to get access to free subdomains and an API token. The token is essential for Tutorial 06.2b where you’ll automate DNS updates.
Navigate to https://www.duckdns.org in your browser
Sign in using one of the OAuth providers:
- GitHub
Locate your token on the account page:
- Your token appears as a UUID (e.g.,
a1b2c3d4-e5f6-7890-abcd-ef1234567890) - Your subdomains list will be empty initially
- Your token appears as a UUID (e.g.,
Save your token somewhere secure (password manager, secure note, etc.)
⚠️ Common Mistakes
- Sharing your token publicly allows anyone to update your DNS records
- Committing your token to git exposes it in repository history
- Forgetting to save the token means you’ll need to regenerate it later
✓ Quick check: You have your DuckDNS token saved securely for use in Tutorial 06.2b
Step 3: Create a Subdomain
Register a unique subdomain that will become your application’s address. Choose a name that’s memorable and relevant to your project.
Enter a subdomain name in the “sub domain” field. For example:
hellojava-yournamemyapp-demolearningcloud
The name must be:
- Unique across all DuckDNS users
- Lowercase letters, numbers, and hyphens only
- Between 1-30 characters
Click the “add domain” button
Verify your subdomain appears in the list showing:
- The full domain:
yoursubdomain.duckdns.org - Current IP: (may show your home IP or be empty)
- The full domain:
ℹ️ Concept Deep Dive
The current IP shown doesn’t matter yet - we’ll update it to point to our Azure VM in the next steps. DuckDNS is designed for “dynamic DNS” scenarios where IPs change frequently, which is why updating the IP is so easy.
✓ Quick check: Your subdomain appears in the DuckDNS list
Step 4: Provision a Test VM
To test your DuckDNS configuration, you need the public IP address of a VM. We’ll create a simple Azure VM running Nginx using the scripts in scripts/06.2a-setup-duckdns/.
cloud-init.yaml - Installs Nginx:
#cloud-config
package_update: true
packages:
- nginx
runcmd:
- systemctl enable nginx
- systemctl start nginx
provision-vm.sh - Creates the Azure VM:
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
RESOURCE_GROUP="hellojava-duckdns-rg"
VM_NAME="hellojava-duckdns-vm"
LOCATION="northeurope"
echo "Creating resource group..."
az group create --name $RESOURCE_GROUP --location $LOCATION --output none
echo "Creating VM (this takes ~2-3 minutes)..."
az vm create \
--resource-group $RESOURCE_GROUP \
--name $VM_NAME \
--image Ubuntu2404 \
--size Standard_B1s \
--admin-username azureuser \
--generate-ssh-keys \
--custom-data @"$SCRIPT_DIR/cloud-init.yaml" \
--public-ip-sku Standard \
--output none
echo "Opening port 80..."
az vm open-port --resource-group $RESOURCE_GROUP --name $VM_NAME --port 80 --output none
PUBLIC_IP=$(az vm show -d -g $RESOURCE_GROUP -n $VM_NAME --query publicIps -o tsv)
echo ""
echo "VM provisioned successfully!"
echo "Public IP: $PUBLIC_IP"
Navigate to the scripts directory:
cd scripts/06.2a-setup-duckdnsRun the provision script:
./provision-vm.shNote the public IP when the script completes:
Public IP: 20.xxx.xxx.xxxCopy this IP address - you’ll need it in the next step.
ℹ️ Concept Deep Dive
The script performs exactly 3 operations: creates a resource group, creates a VM with Nginx via cloud-init, and opens port 80. This minimal setup is perfect for testing DNS resolution without the complexity of a full application deployment.
⚠️ Common Mistakes
- Running the script from the wrong directory causes “cloud-init.yaml not found” errors
- Not having SSH keys configured results in authentication failures
- Forgetting to note the IP means you’ll need to look it up in Azure Portal
✓ Quick check: Script completes successfully and displays a public IP address
Step 5: Update Your DuckDNS Subdomain
Point your subdomain to the VM’s IP address by updating the A record in DuckDNS. This tells DNS resolvers that your domain should route traffic to your Azure VM.
Return to https://www.duckdns.org (you should still be logged in)
Find your subdomain in the list
Replace the current IP with your VM’s public IP from Step 4
Click the “update ip” button
Wait 1-2 minutes for DNS propagation
ℹ️ Concept Deep Dive
An A record (Address record) is the most fundamental type of DNS record - it maps a domain name directly to an IPv4 address. When someone types your domain in a browser, DNS resolvers look up this A record to find which IP to connect to. DuckDNS updates are typically instant, but DNS caches may take a minute to refresh.
✓ Quick check: DuckDNS shows your VM’s IP address next to your subdomain
Step 6: Verify DNS Configuration
Confirm that your subdomain correctly resolves to your VM and that the Nginx welcome page is accessible. This verification ensures everything is ready for Let’s Encrypt in Tutorial 06.2b.
Check DNS resolution:
dig +short yoursubdomain.duckdns.orgReplace
yoursubdomainwith your actual subdomain name.Expected output:
20.xxx.xxx.xxxThis should match your VM’s public IP.
Test HTTP access via domain:
curl http://yoursubdomain.duckdns.orgExpected output: Nginx welcome page HTML starting with:
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...Test in browser (optional):
Open
http://yoursubdomain.duckdns.orgin your browser to see the “Welcome to nginx!” page.
✓ Success indicators:
digreturns your VM’s IP addresscurlreturns Nginx welcome page HTML- Browser displays “Welcome to nginx!” page
✓ Final verification checklist:
- ☐ DuckDNS account created with token saved
- ☐ Subdomain registered and showing in list
- ☐ VM provisioned with public IP
- ☐ A record updated to point to VM IP
- ☐ DNS resolution verified with
dig- ☐ HTTP access verified with
curl
Common Issues
If you encounter problems:
DNS not resolving (dig returns nothing):
- Verify the IP is correct in DuckDNS dashboard
- Wait 2-3 minutes for DNS propagation
- Check for typos in subdomain name (remember it’s
.duckdns.orgnot.com)curl: Connection refused:
- Check VM is running:
az vm show -d -g hellojava-duckdns-rg -n hellojava-duckdns-vm --query powerState -o tsv- Check Nginx status:
ssh azureuser@<your-vm-ip> 'systemctl status nginx'- Verify port 80 is open in NSG
Permission denied running script:
- Add execute permission:
chmod +x provision-vm.shStill stuck? SSH to the VM and check Nginx logs:
sudo tail -f /var/log/nginx/error.log
Summary
You’ve successfully configured DuckDNS which:
- ✓ Provides a free subdomain for your application
- ✓ Maps your domain to your Azure VM’s IP address
- ✓ Prepares your infrastructure for SSL certificates
Key takeaway: DNS is the foundation for SSL certificates because Let’s Encrypt needs to verify domain ownership. DuckDNS provides a free, easy way to get started with domain-based deployments. You’ll use this pattern whenever you need a domain name for development or learning purposes.
Going Deeper (Optional)
Want to explore more?
- Research how the DuckDNS API works for automated IP updates
- Compare A records with CNAME, TXT, and MX records
- Investigate how DNS propagation works across global resolvers
- Try setting up a custom domain with Cloudflare for production use
Clean Up
You have two options for the test VM:
Option A: Keep for Tutorial 06.2b
If continuing to the Let’s Encrypt tutorial, you can reuse this VM or create a fresh one.
Option B: Delete resources now
az group delete --name hellojava-duckdns-rg --yes --no-wait
ℹ️ Note
Deleting the Azure VM does not affect your DuckDNS account. Your subdomain remains registered and you can update its IP to point to new VMs anytime.
Done! 🎉
Excellent work! You’ve learned how to configure DNS for cloud deployments and can now use domain names instead of IP addresses. This foundation is essential for obtaining SSL certificates and building production-ready applications.