Bug: HTTPS certificate never issued after DNS correction — Traefik ACME retry gap
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 3k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 73
Description
Bug: HTTPS certificate never issued after DNS correction — Traefik ACME retry gap
What happens
You add a domain in Dokploy with HTTPS enabled (Let's Encrypt). Your DNS A record
happens to point to the wrong IP at that moment — a common setup mistake (migration
in progress, typo in the IP, DNS not yet propagated, etc.).
You fix the DNS. You verify with dig that propagation is complete. You go back to
Dokploy, edit the domain, click Save. Nothing happens. The certificate is never issued.
You wait an hour. Still nothing. The only workaround is to SSH into the server and run
docker restart dokploy-traefik — then the cert appears in 30 seconds.
The core problem: once Traefik fails an ACME challenge, it never retries on its own,
and Dokploy has no mechanism to tell it to try again.
Why this happens — step by step
Here's the exact chain of events, traced through the code:
-
Domain creation (
packages/server/src/services/domain.ts:16-42)
manageDomain()writes a Traefik YAML config with:- Router rule:
Host(`app.example.com`) - Service URL:
http://appname:3000(Docker internal name) - TLS:
certResolver: "letsencrypt"
- Router rule:
-
ACME HTTP-01 challenge starts
Traefik asks Let's Encrypt for a challenge token. Let's Encrypt calls back to
http://app.example.com/.well-known/acme-challenge/<token>.
Since DNS points to IP1 (wrong server), the callback hits IP1 → challenge fails. -
Traefik gives up — by design
Traefik deliberately does not retry failed ACME challenges to avoid burning
through Let's Encrypt rate limits. This is a conscious design choice:
traefik/traefik#9405.
Failed domains are not stored inacme.json— they simply don't exist
anywhere. No cert, no record, no scheduled retry. -
User fixes DNS, then saves domain in Dokploy UI
Theupdatemutation (apps/dokploy/server/api/routers/domain.ts:119-176)
callsmanageDomain()at line 164, which regenerates the Traefik config.
But the router rule is stillHost(`app.example.com`)and the service
is stillhttp://appname:3000— the file content is byte-for-byte identical.
Traefik's file watcher sees no change and does nothing. -
The domain is stuck forever
Traefik won't retry the ACME challenge on its own. The config file didn't change
so the file watcher won't trigger. There is no "retry certificate" button in the
domain UI. The user has no recourse from within Dokploy. -
Why
docker restartfixes it
On startup, Traefik compares all active routers (withcertResolverset)
against itsacme.json. Any domain present in the config but absent from
acme.jsontriggers a fresh ACME attempt. Since DNS now points to the
correct server, the HTTP-01 challenge succeeds.
Steps to reproduce
- Deploy Dokploy on Server B (IP2)
- Create an application, add domain
test.example.comwith HTTPS (Let's Encrypt) - Have DNS
test.example.com→ IP1 (any IP that isn't Server B) - Check Traefik logs:
docker logs dokploy-traefik 2>&1 | grep -i acme
→unable to obtain ACME certificate for domains - Fix DNS:
test.example.com→ IP2, confirm withdig +short test.example.com - Visit
https://test.example.com→ SSL error (no certificate) - Edit the domain in Dokploy UI, click Save → still no certificate
- Wait 1 hour → still no certificate
docker restart dokploy-traefik→ certificate issued within 30 seconds
Suggested fix
The infrastructure to solve this already exists in the codebase.
reloadDockerResource("dokploy-traefik", serverId) is implemented in
packages/server/src/services/settings.ts:283-312 and exposed via the
reloadTraefik mutation in apps/dokploy/server/api/routers/settings.ts:126-136.
It handles both Swarm (docker service update --force) and standalone
(docker restart) modes.
The fix: in the domain update mutation (domain.ts:164), after manageDomain(),
call reloadDockerResource("dokploy-traefik", serverId) when the domain uses
Let's Encrypt. This follows the exact same pattern already used by reloadTraefik
in the settings router.
Optionally, calling validateDomain() at domain creation time and warning the
user when DNS doesn't point to the server IP would prevent the initial ACME
failure entirely.
Environment
- Traefik version: 3.6.7 (hardcoded in
traefik-setup.ts:23) - ACME config: HTTP-01 challenge only (
traefik-setup.ts:309)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read the domain update mutation in apps/dokploy/server/api/routers/domain.ts around lines 119-176, then compare its manageDomain() call with reloadTraefik in apps/dokploy/server/api/routers/settings.ts and reloadDockerResource() in packages/server/src/services/settings.ts:283-312. The fix is complete when updating a Let's Encrypt domain triggers a Traefik reload and a previously failed certificate is issued after DNS correction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, typescript
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100