mholt

caddy-dynamicdns

Caddy app that keeps your DNS records (A/AAAA) pointed at itself.

by mholt

Go

Go100%

Commit activity

Last 12 weeks · 1 commit

Full graph →

Community health

2 of 6 standards met

Community profile →
42
✓README✓License○Contributing○Code of Conduct○Issue Template○PR Template

Recent PRs & issues

Quiet · 7 in progress · Last activity 2mo ago
See all on GitHub →
lordwelch

The github.com/google/cel-go dependency needs to be updated to cel.dev/cel-go See https://github.com/google/cel-go#-read-only-compatibility-repository This causes issues for me when building

lordwelch · 4w ago
Pedro-HNetworking

A DNS record set is replaced as a whole, but the diff loop in compares each current IP on its own and, after the update, remembers only the single IP it just wrote. With two addresses of the same family — e.g. a host with two uplinks configured as — that means each check publishes only the address it considers missing, which wipes the other one from the set. The next check then finds the first address missing and publishes it back. The record flip-flops between the two addresses forever, and never holds both. Fix Diff per (name, record type) rather than per IP: if any current IP of a type is missing from the last-seen set, publish that type's full current set and remember all of it. Providers group by (name, type) into one UPSERT, so this is a single call per record set, as before. Seeding from existing DNS records now keeps every value found for a type as well (it previously kept only the last one seen), so a record that already holds both addresses is not needlessly rewritten on startup. Single-IP setups are unaffected: a one-element set behaves exactly as before. Test in : two static IPv4 addresses with DNS seeded holding one of them — the first check produces one record set containing both, and the second check produces no update at all. It fails on master with the record set containing only the missing address and a second, redundant update on the next cycle.

Pedro-HNetworking · 1mo ago
PurplestViper

The global options are set by the tls app, but the field is empty and the field is not exported. Get field data by reflection. #92

PurplestViper · 2mo ago
asio

This allows updating domains across multiple DNS providers — or multiple accounts of the same provider (e.g. different API credentials per zone) — from a single app. Repeating the whole global option doesn't work (Caddy keeps only the last occurrence), so the app itself now holds a list of providers. Config The directive can now be repeated, with each provider's domains nested inside its block. Caddyfile config (global options): Equivalent JSON config: All other options (, , , /, , , ) remain global and apply to all providers, so no existing option changes semantics. The public IP is looked up once per check and shared across providers. (Per-provider variants of e.g. could be follow-ups if there's demand.) Implementation notes Caddyfile parsing:* the parser takes the provider directive's segment via , splits out sub-blocks, and hands the remaining tokens to the DNS provider module through a rebuilt dispenser — so provider modules parse exactly the tokens they'd parse today. is the only name reserved inside a provider block; it seemed safe to claim since providers receive zones at runtime via libdns rather than via config, any collision would be a loud parse error rather than silent misbehavior, and JSON config bypasses the Caddyfile entirely. Backward compatibility: top-level / are folded into a one-entry list at provision time, and a legacy Caddyfile still adapts to identical JSON as before (covered by regression tests). Mixing top-level with per-provider is rejected with a clear error. Seeding: looking up current IPs from existing DNS records is now tracked per domain name instead of once globally, so every provider's domains get seeded — and as a side effect, domains added by a config reload now get seeded too (previously they were skipped if any earlier config had already seeded). Error semantics unchanged: the boot-time retry backoff still triggers only on total IP-source failure; per-provider failures are logged, as before, so one provider's bad credentials can't wedge the check loop. Testing New parser tests using a dummy in-test DNS provider module (which errors on unrecognized subdirectives — proving reserved tokens never leak into the provider module), covering multi-provider configs, before/after module config in the block, and legacy-format regressions. Unit tests for the legacy config normalization and its error cases. Built with xcaddy + caddy-dns/glesys: produces the expected array, and a legacy Caddyfile produces byte-identical JSON to master. Live test:* ran one Caddy instance against 4 real GleSYS accounts (4 zones, different API credentials each). All four seeded from existing records, created A+AAAA records, verified in public DNS, and subsequent cycles correctly no-op'd. On master, only the last-configured provider ever acts.

asio · 2mo ago
kthchew

Is it possible to use multiple providers to update different domains? I tried this config (simplified) but it seems like only the second block (for DuckDNS) is functional; is not updated at all.

kthchew · 2mo ago
laur3n7ius

body: Add pluggable IP updaters and ZTE IPv6 firewall module

laur3n7ius · 2mo ago
Structured data for AI agents

Repository: mholt/caddy-dynamicdns. Description: Caddy app that keeps your DNS records (A/AAAA) pointed at itself. Stars: 373, Forks: 40. Primary language: Go. Languages: Go (100%). License: Apache-2.0. Open PRs: 7, open issues: 11. Last activity: 2mo ago. Community health: 42%. Top contributors: mholt, francislavoie, dependabot[bot], jm355, caiych, otaconix, cobyge, eliasvasylenko, asio, matthewpi and others.