Add porkbun: DNS at Porkbun from the command line - #25
Merged
Conversation
Porkbun hosts most of the zones here and its API is the only way to change a
record without the dashboard. That is fine for one record and not fine for
"point the apex and www at a new host", which is four edits that have to land
together.
`unpark` is the reason this exists. A domain bought and left alone answers with
an ALIAS at the apex and a wildcard CNAME, both pointing at a *.porkbun.com
host, and those records are not independent: they are how a URL forwarding rule
is implemented. Adding your own ALIAS beside them does nothing at all -- the
forward keeps winning, the new host never sees a request, and the failure reads
as a broken deploy rather than a DNS problem. Deleting the forward takes its
records with it. That cost an afternoon on d3vices.com today; it is one command
now, with --dry-run to see the plan first.
What counts as parking is deliberately narrow -- only ALIAS and CNAME records
pointing at porkbun.com. The MX records at fwd1.porkbun.com are Porkbun's email
forwarding and the NS records are the zone's delegation, so sweeping either up
would break mail or take the domain off the internet.
Two API shapes drive the rest:
- Every call is a POST with the credentials in the JSON body, and `status` is a
field rather than the HTTP code. A refused key, an unknown domain and a
malformed record all come back 200 OK with {"status":"ERROR"}, so checking
response.ok reports success for every one of them. `unwrap` treats the body's
own status as the verdict and surfaces `message` verbatim.
- The API's `name` is the label relative to the zone and the apex is the empty
string, which nobody types. `@`, an empty value, the bare label and the full
name are all accepted and normalised, because the alternative is creating
www.example.com.example.com.
`set` is an upsert that edits in place, keeping the record id: delete-then-create
has a window where the name does not resolve. It reports `unchanged` and sends
no write when the value already matches, and refuses rather than guessing when
several records share a name and type.
keyVariable now treats `-` and `_` as the same separator. The single-word keys
never needed it; porkbun_secret_api_key and porkbun-secret-api-key are the same
key and both have to reach the same entry.
Verified against the live API: create, no-op re-set, in-place update, read-back
by both host forms, delete by host+type, and the missing-credential and
below-minimum-TTL error paths. The throwaway test record was removed and the
zone left at its original 13 records.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Hh54BWan1jXMzKqqwLMSr
| perplexity: 'PERPLEXITY_API_KEY', | ||
| elevenlabs: 'ELEVENLABS_API_KEY', | ||
| porkbun: 'PORKBUN_API_KEY', | ||
| porkbun_secret: 'PORKBUN_SECRET_API_KEY', |
ThreatCrush Security Scan12 finding(s) HIGH/CRITICAL: 5 | MEDIUM: 1 | LOW: 6
Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
porkbuncommand: DNS at Porkbun without the dashboard.porkbun ls example.com porkbun set example.com www CNAME app.up.railway.app porkbun unpark example.com --dry-runWhy
unparkexistsA domain bought and left alone answers with an
ALIASat the apex and a wildcardCNAME, both pointing at a*.porkbun.comhost. Those records are notindependent — they are how a URL forwarding rule is implemented. Adding your own
ALIAS beside them does nothing: the forward keeps winning, the new host never sees a
request, and it reads as a broken deploy rather than a DNS problem. Deleting the
forward takes its records with it.
This cost an afternoon on
d3vices.comtoday. It is one command now.What counts as parking is deliberately narrow — only
ALIAS/CNAMEpointing atporkbun.com. TheMXrecords atfwd1.porkbun.comare Porkbun's emailforwarding and the
NSrecords are the zone's delegation; sweeping either up wouldbreak mail or take the domain off the internet.
Two API shapes worth knowing
statusis a field,not the HTTP code. A bad key, an unknown domain and a malformed record all return
200 OKwith{"status":"ERROR"}— so checkingresponse.okreports success forall three.
unwraptreats the body's own status as the verdict.nameis the label relative to the zone, and the apex is the emptystring, which nobody types.
@, empty, the bare label and the full name are allaccepted and normalised — the alternative is creating
www.example.com.example.com.setis an upsertIt edits in place, keeping the record id. Delete-then-create has a window where the
name does not resolve at all. It reports
unchangedand sends no write when thevalue already matches, and refuses rather than guessing when several records share a
name and type (two TXT values is legitimate; silently replacing one is not).
Also
keyVariablenow treats-and_as the same separator. The single-word keysnever needed it;
porkbun_secret_api_keyandporkbun-secret-api-keyare the samekey and both have to reach the same entry.
Verification
381 tests pass, typecheck clean. Exercised against the live API: create, no-op
re-set, in-place update, read-back via both host forms, delete by host+type, plus the
missing-credential and below-minimum-TTL error paths. The throwaway test record was
removed and the zone left at its original 13 records.
🤖 Generated with Claude Code
https://claude.ai/code/session_016Hh54BWan1jXMzKqqwLMSr