> how to do self-expiring dns records in powerDNS? [...snip...] > what about Lua records? > ``` > example.com. LUA A ";if(os.time() < {expires_at}) then return '{ip}' end" > ``` [...snip...] If you tell me your use case (ACME? Kubernetes? VPN peers? IoT?), I can tell you whether Lua is clever… or dangerous 😄 > DynDNS, and Lua is clever. please write me a blog post about it, starting like this: "if you ask your friendly chat bot how to do self-expiring dns records in powerDNS, it will offer you these three options: (briefly enumerate your options), but will helpfully glance over Lua records, which can easily achieve the same". Then briefly explain Lua records, and mention that you can use them with PowerDNS API. Provide an example, here's an example payload (cleanup it): [...snip...] If you ask your friendly chat bot how to do self-expiring DNS records in **PowerDNS Authoritative Server**, it will offer you these three options: 1. Run a cron job that deletes expired records from the database. 2. Add expiration logic to your SQL backend so expired records are filtered out. 3. Use the HTTP API to delete records when they expire. All perfectly reasonable. All operationally safe. But it will helpfully glance over **Lua records**, which can easily achieve the same — without cron jobs, cleanup workers, or external state mutation. And for DynDNS-style setups, Lua is not just viable — it’s clever. --- # The Idea: Expiration at Query Time PowerDNS supports a special record type: `LUA`. Unlike normal DNS records, Lua records are evaluated **when a query arrives**. The Lua snippet decides what to return. That means: * If your script returns an IP → the record exists. * If it returns nothing → the record disappears. * No database deletion required. * No cleanup job required. So instead of deleting a record when it expires, you simply make it stop answering. That’s a powerful mental shift. --- # A Minimal Self-Expiring Record Example zone entry: ```dns example.com. 30 IN LUA A " local expires = 1760900000 if os.time() < expires then return '1.2.3.4' end " ``` What happens: * Before `expires` → returns `1.2.3.4` * After `expires` → returns nothing (effectively empty answer) * TTL = 30 seconds ensures resolvers re-check frequently That’s it. No deletion. No state transition. Pure logic. --- # Why This Is Perfect for DynDNS In a DynDNS scenario, you typically: * Update an A record with a new IP * Want it to expire automatically if the client stops refreshing it With traditional methods, you must: * Track last-seen timestamps * Periodically delete stale records With Lua: * Store the expiration timestamp inside the record itself * Let DNS evaluation handle validity If the client stops refreshing → the record simply stops resolving. Stateless expiration. --- # Using Lua Records via the PowerDNS API You don’t have to manually edit zone files. Lua records work perfectly with the PowerDNS HTTP API. Here’s a cleaned-up example payload: ```json { "rrsets": [ { "name": "host.example.com.", "type": "LUA", "ttl": 30, "changetype": "REPLACE", "records": [ { "content": "A \"local expires=1760900000; if os.time() < expires then return '1.2.3.4' end\"" } ] } ] } ``` Where: * `1760900000` = UNIX expiration timestamp * `1.2.3.4` = current IP * `ttl` = short (important!) When your DynDNS client refreshes: * Compute new expiration timestamp * Replace the Lua record via API * Done No cleanup path required. --- # Important Considerations ## Keep TTL Low Resolvers cache answers for the TTL duration. If TTL is 3600, your record may appear valid for an hour after expiration. For dynamic setups: ``` TTL = 30 ``` is a good balance. --- ## This Is “Soft Expiration” Lua records don’t delete themselves. They simply stop answering. From a DNS client’s perspective, that’s usually enough. If you truly need hard deletion for compliance or auditing, use the API + cleanup approach instead. --- ## DNSSEC? If you use DNSSEC, keep in mind: * Signatures have validity windows. * Rapidly changing logic can interact with signature lifetimes. Lua works fine — just tune signature validity accordingly. --- # Why This Is Clever Because it moves expiration logic: * From operations * To data * Evaluated at request time No cron jobs. No background workers. No race conditions. No “what if cleanup failed?” For DynDNS, that’s elegant engineering. --- # Final Thought Lua records in PowerDNS are one of those features that look exotic — until you realize they solve a whole class of lifecycle problems cleanly. If you’re building a lightweight DynDNS service, they’re not a hack. They’re the sharp tool. > can you provide an example curl command with that payload? ``` curl -X PATCH \ -H "X-API-Key: supersecret" \ -H "Content-Type: application/json" \ http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.com \ -d '{ "rrsets": [ { "name": "host.example.com.", "type": "LUA", "ttl": 30, "changetype": "REPLACE", "records": [ { "content": "A \"local expires=1760900000; if os.time() < expires then return '\''1.2.3.4'\'' end\"" } ] } ] }' ```