4.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a Docker-based Dynamic DNS client for Hetzner DNS (and 50+ other providers) using qmcgaw/ddns-updater - a universal, production-ready DDNS solution with web UI.
Core Components:
docker-compose.yml: Service configuration using qmcgaw/ddns-updater imagedata/config.json: DDNS configuration (domains, tokens, providers)config.json.example: Configuration template for Hetzner setup
Development Commands
Docker Operations
Start the service:
docker-compose up -d
View logs:
docker-compose logs -f
Restart service:
docker-compose restart
Stop service:
docker-compose down
Check status:
docker-compose ps
Configuration Management
Create initial config:
mkdir -p data
cp config.json.example data/config.json
# Edit data/config.json with your credentials
Validate config JSON:
cat data/config.json | jq .
Get Hetzner Zone ID via API:
curl -H "Auth-API-Token: YOUR_TOKEN" https://dns.hetzner.com/api/v1/zones
Web UI
Access Web UI:
Open browser to http://localhost:8000
The Web UI shows:
- Current IP status
- Last update timestamp
- Update history
- Errors and warnings
- Per-domain status
Architecture
Application Flow
- Initialization: Load configuration from
data/config.json - Main Loop:
- Get current public IP (IPv4/IPv6)
- Compare with DNS records for each configured domain
- Update DNS if IP has changed
- Wait for configured period (default: 5 minutes)
- Repeat
Configuration Structure
Configuration is in JSON format at data/config.json:
{
"settings": [
{
"provider": "hetzner",
"zone_identifier": "zone_id",
"domain": "example.com",
"host": "@",
"ttl": 60,
"token": "api_token",
"ip_version": "ipv4"
}
]
}
Key Parameters:
provider: DNS provider name (hetzner, cloudflare, duckdns, etc.)zone_identifier: Hetzner DNS Zone IDdomain: Base domain namehost: Subdomain or@for rootttl: Time-to-live in secondstoken: Hetzner API token with DNS edit permissionsip_version:ipv4,ipv6, oripv4 or ipv6
Multi-Domain Support
Add multiple entries in the settings array to manage multiple domains or subdomains.
Environment Variables
Optional variables in .env:
PERIOD: Update check interval (default: 5m)LOG_LEVEL: Logging verbosity (debug, info, warning, error)
Versioning Strategy
This project uses a simplified versioning scheme:
- 0.1: Large changes (new features, breaking changes)
- 0.0.1: Small changes (bugfixes, minor improvements)
- 1.x: Major releases (only by explicit instruction)
When making changes:
- Update
CHANGELOG.mdwith the change description - Increment version according to change size
- Work in feature branches, merge to main when ready
Key Files
docker-compose.yml: Service definition using qmcgaw/ddns-updaterconfig.json.example: Template for Hetzner configurationdata/config.json: Active configuration (not in git).env.example: Optional environment variables templateCHANGELOG.md: Version history
Security Notes
- API token is sensitive - never commit
data/config.jsonor.env - Container runs with minimal privileges
- Only ports 8000 (web UI) exposed
- Use HTTPS reverse proxy for production deployments
- API token should have minimal required permissions (DNS read/write only)
Troubleshooting
View Web UI status:
# Open http://localhost:8000 in browser
Check container logs:
docker-compose logs --tail=50 -f
Validate configuration:
# Check JSON syntax
cat data/config.json | jq .
Test API connectivity:
# List zones
curl -H "Auth-API-Token: YOUR_TOKEN" https://dns.hetzner.com/api/v1/zones
# List records for a zone
curl -H "Auth-API-Token: YOUR_TOKEN" "https://dns.hetzner.com/api/v1/records?zone_id=ZONE_ID"
Debug mode:
Set LOG_LEVEL=debug in .env and restart container.
Container won't start:
- Check
docker-compose logs - Verify
data/config.jsonexists and is valid JSON - Check port 8000 is not in use
Provider Migration
To switch from Hetzner to another provider:
- Check supported providers
- Update
providerfield indata/config.json - Adjust provider-specific fields
- Restart:
docker-compose restart
No code changes needed - just configuration!