Skip to content

fix: clean up through the provider that published the record - #2

Merged
0xJacky merged 1 commit into
mainfrom
fix/cleanup-reuses-provider
Nov 12, 2026
Merged

0xJacky merged 1 commit into
mainfrom
fix/cleanup-reuses-provider

Conversation

@0xJacky

@0xJacky 0xJacky commented Nov 12, 2026

Copy link
Copy Markdown
Member

Problem

Every dns01.present and dns01.cleanup call built a new lego provider. Providers that keep the vendor's record ID in memory during Present (cloudflare, ispconfig and 55 others in lego v5.5.2) then failed the cleanup with unknown record ID, and the _acme-challenge TXT record stayed behind. Issuance itself still succeeded. Reported in 0xJacky/nginx-ui#2115 (Cloudflare) and 0xJacky/nginx-ui#2113 (ISPConfig).

Fix

The handler keeps the provider of each published record and CleanUp takes it back. The key is the provider code, a SHA-256 fingerprint of the credentials and options, the domain, the token and the key authorization, so a cleanup with other credentials never reuses it. A cleanup that finds nothing (for example after the plugin restarted) builds a fresh provider as before. Entries expire after six hours. The cleanup still runs inside the env scope, so LEGO_DISABLE_CNAME_SUPPORT is honoured when lego derives the record name.

Tests

  • TestCleanUpRemovesTheRecordPresentPublished drives Present then CleanUp against a fake ISPConfig API. On main it fails with ispconfig: unknown record ID for '_acme-challenge.example.com.' 'token'; with this change it passes and the published record ID is deleted.
  • Interleaved challenges (wildcard + apex), fallback with other credentials, dry run keeps nothing, expiry.
  • go test -race -count=1 ./...: all packages ok on main and on this branch; gofmt, go vet, webapp typecheck/build and the plugin.json check all clean.

🤖 Generated with Claude Code

Every dns01.present and dns01.cleanup call built a new lego provider. The
providers that keep the vendor's record ID in memory during Present, such
as cloudflare and ispconfig, then failed the cleanup with "unknown record
ID" and left the _acme-challenge record behind.

The handler now keeps the provider of each published record, keyed by the
provider code, a fingerprint of the credentials and options, the domain,
the token and the key authorization, and CleanUp takes it back. A cleanup
that finds none, for example after the plugin restarted, builds a fresh
provider as before. Entries expire after six hours so a missed cleanup
cannot leak them.

Refs 0xJacky/nginx-ui#2113, 0xJacky/nginx-ui#2115

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@0xJacky
0xJacky merged commit 9b3fc38 into main Nov 12, 2026
1 check passed
@0xJacky
0xJacky deleted the fix/cleanup-reuses-provider branch November 12, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant