# 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:** ```bash docker-compose build ``` **Start the service:** ```bash docker-compose up -d ``` **View logs:** ```bash docker-compose logs -f ``` **Restart service:** ```bash docker-compose restart ``` **Stop service:** ```bash docker-compose down ``` **Rebuild after code changes:** ```bash docker-compose up -d --build ``` ### Local Development **Run Python script directly (requires Python 3.11+):** ```bash # 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:** ```python 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:** ```bash docker-compose ps ``` **View recent logs:** ```bash docker-compose logs --tail=50 ``` **Test API connectivity:** ```bash # 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.