Repository navigation
Conversation
a040f3a to
0c77d72
Compare
| await backupAcmeContent(serverId, original); | ||
| await writeAcmeContent(serverId, `${JSON.stringify(storage, null, 2)}\n`); | ||
| await restartWithUndo(serverId, () => writeAcmeContent(serverId, original)); |
There was a problem hiding this comment.
Cleanup overwrites newly saved certificates
removeOnce replaces acme.json while Traefik is still running. If Traefik saves a newly issued or renewed certificate between readAcmeContent and writeAcmeContent, cleanup overwrites it with the older snapshot. The SSH backup adds another network round trip to this window.
The retry checks only whether selected certificates returned, so it cannot detect a lost certificate for another domain. After restarting, Traefik must obtain that certificate again, which can break HTTPS if issuance fails. Exclude Traefik's writes while reading and replacing its storage.
| ) => | ||
| queueTraefikTask(serverId, async () => { |
There was a problem hiding this comment.
Replacing whileTraefikStopped with queueTraefikTask removes the shared Docker marker that blocked cleanup from another Dokploy instance. If multiple Dokploy instances serve cloud requests, as imrja8 described, two requests can now edit the same remote server at once. Both remaining locks are in-memory maps.
The jobs also share acme.json.tmp. One can overwrite the other's changes or rename the file while the other is still writing it, leaving invalid certificate storage that Traefik cannot load. Keep a server-wide claim around the entire read, write, and restart sequence.
|
Will create a fresh PR, it got too wide.. |
What is this PR about?
Closes #4894.
On
canary, deleting a domain, app, compose or preview leaves its Let's Encrypt certificate inacme.json. Traefik keeps trying to renew every certificate in that file, so certificates for removed domains fail renewal every day and fill Traefik's logs.This PR adds Traefik → Clean Up Certificates (main server and remote servers) to remove the certificates nothing uses.
How it works
Listing: a Let's Encrypt certificate is listed only if none of its names (main + SANs) matches anything in use on that server:
/api/rawdata), includingHostRegexpIf any of these can't be read, the dialog warns. Users untick any certificate they want to keep.
Removing: Dokploy re-checks the selection, backs up
acme.json(the last 5 in/etc/dokploy/traefik/acme-backups/) and writes the new file. It then restarts Traefik with a singledocker restart, because Traefik only readsacme.jsonon start. A Traefik that was stopped stays stopped, and nothing is restarted if nothing can be removed.If something goes wrong: if Traefik doesn't stay up, the original file is put back and Traefik is restarted. If Traefik saved its certificates back during the restart, Dokploy tries once more.
Runs in the same per-server queue as Traefik recreates.
Delete-domain dialog: for Let's Encrypt domains, a note that the certificate is kept and how to remove it.
Tests
unused-certificates.test.ts: matching, removal, backups, undo and the retry; local via memfs, remote via mocked SSH, with real certificate fixtures.restart-traefik.test.ts: the restart helper and the queue.api/traefik-certificates.test.ts: the lock, progress, the removed count and the audit entry.pnpm typecheckand Biome pass.pnpm testpasses exceptapplication.real.test.ts, which needs nixpacks installed locally.Limits: the standalone
dokploy-traefikcontainer (the default), the defaultacme.jsonpath and the default API port.Checklist
Before submitting this PR, please make sure that:
canarybranch.Issues related (if applicable)
Closes #4894
Screenshots (if applicable)
The PR needs changes before merging because cleanup can overwrite certificate data written by Traefik or another Dokploy instance.
Summary
Adds certificate cleanup for local and remote Traefik servers.
Reviews (5) · Last reviewed commit: "fix(traefik): simplify certificate clean..." · Reviewed by Greptile