dyndns-docker/CLAUDE.md

3.7 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 the Hetzner DNS Console. It automatically detects IP changes and updates DNS records via the Hetzner DNS API.

Core Components:

  • dyndns.py: Main Python application that handles IP detection and DNS updates
  • Dockerfile: Container configuration for the application
  • docker-compose.yml: Docker Compose setup for easy deployment

Development Commands

Docker Operations

Build the container:

docker-compose build

Start the service:

docker-compose up -d

View logs:

docker-compose logs -f

Restart service:

docker-compose restart

Stop service:

docker-compose down

Rebuild after code changes:

docker-compose up -d --build

Local Development

Run Python script directly (requires Python 3.11+):

# Install dependencies
pip install -r requirements.txt

# Set environment variables or use .env file
export HETZNER_API_TOKEN="your_token"
export DOMAIN="example.com"
export RECORD_NAME="@"

# Run script
python dyndns.py

Test IP detection without updating DNS:

from dyndns import HetznerDynDNS
client = HetznerDynDNS(api_token, domain, record_name)
current_ip = client.get_current_ip()
print(f"Current IP: {current_ip}")

Architecture

Application Flow

  1. Initialization: Load configuration from environment variables
  2. Zone Lookup: Auto-detect Hetzner DNS Zone ID if not provided
  3. Main Loop:
    • Get current public IP (via api.ipify.org)
    • Fetch existing DNS record from Hetzner API
    • Compare IPs and update if changed
    • Wait for configured interval (default: 5 minutes)
    • Repeat

Hetzner DNS API Integration

The application uses Hetzner's DNS API v1 (https://dns.hetzner.com/api/v1):

  • Authentication: Via Auth-API-Token header
  • GET /zones: Find zone ID for domain
  • GET /records: List DNS records for zone
  • POST /records: Create new DNS record
  • PUT /records/{id}: Update existing DNS record

Configuration

All configuration is via environment variables (see .env.example):

  • Required: HETZNER_API_TOKEN, DOMAIN
  • Optional: RECORD_NAME (default: @), RECORD_TYPE (default: A), CHECK_INTERVAL (default: 300), LOG_LEVEL (default: INFO)

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:

  1. Update CHANGELOG.md with the change description
  2. Increment version according to change size
  3. Work in feature branches, merge to main when ready

Key Files

  • dyndns.py: Core application logic (250+ lines)
  • requirements.txt: Python dependencies
  • Dockerfile: Multi-stage build with non-root user
  • docker-compose.yml: Service configuration with restart policy
  • .env.example: Configuration template
  • CHANGELOG.md: Version history

Security Notes

  • API token is sensitive - never commit .env file
  • Container runs as non-root user (UID 1000)
  • Minimal Python slim image for reduced attack surface
  • API token should have minimal required permissions (DNS read/write only)

Troubleshooting

Check if container is running:

docker-compose ps

View recent logs:

docker-compose logs --tail=50

Test API connectivity:

# From host
curl -H "Auth-API-Token: YOUR_TOKEN" https://dns.hetzner.com/api/v1/zones

Debug mode: Set LOG_LEVEL=DEBUG in .env and restart container.