Repository navigation
Description
To Reproduce
- Create a Compose application, deploy it successfully
- Go to the application's Domains tab, add a domain, set "Certificate Provider" to "Custom"
- The form shows a "Custom Certificate Resolver" text field — paste a certificate + private key (e.g. a Cloudflare Origin CA cert) into it and save
- Separately, go to the dedicated "Certificates" section in the sidebar, create a new certificate entry with Name / Certificate Data / Private Key (cert and key pasted into their own separate fields this time)
- Go back to the domain's HTTPS settings — there is no dropdown or option anywhere to select the certificate just created in step 4
- Redeploy the compose service
- Visit the domain through Cloudflare (SSL mode: Full Strict) — get Error 526 "Invalid SSL Certificate"
- Inspect /etc/dokploy/traefik/dynamic/ on the server — the certificate's files (certificate.yml, chain.crt, privkey.key) exist under dynamic/certificates//, but nothing in the per-app dynamic YAML references them
Current vs. Expected behavior
Current: After creating a certificate via the dedicated Certificates section, there is no UI path to actually apply it to a specific Compose service's domain. The "Custom Certificate Resolver" field on the domain form turns out to expect a Traefik certResolver name (matching an entry under certificatesResolvers in traefik.yml's static config) rather than raw certificate/key content — pasting cert/key data there does nothing useful, and there's no inline indication of this expected format.
Expected: After saving a certificate in the Certificates section, the domain's HTTPS settings should offer a way to select it (the docs at docs.dokploy.com/docs/core/certificates imply this should exist — "select your newly created certificate" — but no such control appears in the domain form for a Compose service). Selecting it should result in Traefik actually using that certificate for the domain's TLS handshake.
Provide environment information
OS: Ubuntu 24.04.3 LTS
Arch: x86_64
Dokploy version: 0.29.8
VPS Provider: <fill in your provider>
Applications: Docker Compose stack — Node.js/Express API, static SPA served via nginx, Next.js app, MySQL, RedisWhich area(s) are affected? (Select all that apply)
Docker Compose
Are you deploying the applications where Dokploy is installed or on a remote server?
Same server where Dokploy is installed
Additional context
Cloudflare was set to Full (Strict) SSL mode, which requires the origin (Traefik) to present a valid certificate — this is why the missing certificate-selection UI became a blocker rather than a cosmetic gap. Worked around by switching Cloudflare to Flexible mode instead, which avoids needing an origin certificate entirely, but that's a workaround, not a fix for the underlying gap.
Will you send a PR to fix it?
Yes
Activity
dosubot commentedon Jun 28, 2026
Hi @Mubashir-teapot! I'm Dosu and I'm helping the Dokploy team.
You've identified a real architectural gap. Here's what's happening under the hood:
The "Certificates" section and "Custom Certificate Resolver" field serve different purposes:
The Certificates section creates physical certificate files at
/etc/dokploy/traefik/dynamic/certificates/{id}/with acertificate.ymlthat Traefik auto-loads via its file provider [1]. These are TLS certificates that Traefik knows about but they're matched to domains via SNI — Traefik will use them automatically if the certificate's CN/SAN matches the requested domain and the router hastls: {}enabled without a specificcertResolver.The "Custom Certificate Resolver" field on a domain expects the name of a Traefik
certificatesResolver(e.g."letsencrypt") — not raw cert data, and not the name of a certificate from the Certificates section [2] [3]. For Compose services, this gets injected as a Docker label:traefik.http.routers.{name}.tls.certresolver={value}[3].Why your setup fails with Error 526:
When you set certificate type to "custom" and paste cert/key content into the "Custom Certificate Resolver" text field, that value gets used as a literal resolver name in Traefik's config. Since no such resolver exists, Traefik can't obtain/present a certificate, and Cloudflare's Full (Strict) mode rejects the connection.
The workaround for now:
If you've created a certificate in the Certificates section whose CN/SAN matches your domain, you should be able to set the certificate type to
"none"on the domain. This setstls: {}without a certResolver, which lets Traefik fall back to SNI-based certificate selection from its loaded certificate store — i.e., it should pick up the certificate you created in the Certificates section. This is worth testing.On the UX gap:
This was also raised in issue #4610, which proposed replacing the free-text input with a dropdown of registered certificates. That issue was closed without a fix. Your description is clearer about the actual problem — the docs say "select your newly created certificate" but no such selector exists in the domain form for Compose services. A PR adding a dropdown (or at minimum, proper documentation of the expected format) would be a welcome improvement.
Would you like me to look into the specific code paths for Compose domain label generation to help guide your PR?
To reply, just mention @dosu.
Share context across your team and agents. Try Dosu.
Mubashir-teapot commentedon Jun 29, 2026
Tested the "None" certificate type workaround it did not resolve the issue. Still getting Error 526 from Cloudflare in Full (Strict) mode.
Confirmed the certificate itself is loading correctly: its files (certificate.yml, chain.crt, privkey.key) are present under /etc/dokploy/traefik/dynamic/certificates//, and Traefik's file provider does pick those up. The gap is specifically on the domain/router side.
Separately, I tried to inspect the actual router config Dokploy generates for my Compose service's domains to debug this myself, but couldn't find it anywhere under /etc/dokploy/traefik/dynamic/ — that directory only contains acme.json, dokploy.yml (which is just Dokploy's own dashboard router), middlewares.yml, and the certificates folder. No per-app routing file exists there for a Compose service's domains.
If Dokploy generates these routes as Docker labels on the service containers (via the docker provider in traefik.yml) rather than as dynamic files, that's fine, but it means there's currently no way for a user to see or audit the actual router/TLS config being applied to their domain through the filesystem — only by manually docker inspecting each container's labels. Could someone confirm whether that's the intended mechanism for Compose services? If so, it'd be worth documenting, since right now there's no visibility into what Dokploy is actually telling Traefik for a given domain, which makes debugging issues like this one (and #4610) much harder than it needs to be.
This also isn't just a UX papercut it's a real security gap. Without a working path to apply a custom certificate, Full (Strict) Cloudflare↔origin encryption isn't achievable through the UI at all, forcing a fallback to Flexible mode (unencrypted Cloudflare↔origin hop) as the only way to get HTTPS working end to end.
On the offer to dig into this myself: I've been reviewing how my own stack manages Docker/Traefik config while debugging this, so I'm comfortable working through the actual mechanism if pointed at the relevant source — happy to review the real Compose domain/label-generation code and send a PR if that's useful. I did try manually editing Traefik's config directly on my server to work around this, but that caused its own issues, so I've held off going further down that path solo. Rather not fight this blind — if someone can point me at the right files, I'll take a real pass at fixing it; otherwise happy to hand this off and let the team take it from here.
dosubot commentedon Jun 29, 2026
@Mubashir-teapot — you're correct: Compose service routes are generated entirely as Docker labels on the service containers, not as dynamic YAML files. The only file-based dynamic configs are
dokploy.yml(dashboard),middlewares.yml,acme.json, and the certificates folder. For Compose services, Traefik discovers routing via its Docker provider, sodocker inspectis indeed the only way to audit the applied config. That's the intended mechanism, though I agree it lacks visibility.Here are the relevant source files for a PR:
Primary file:
packages/server/src/utils/docker/domain.tscreateDomainLabels()(lines 255–348) — generates all Traefik labels for a domain, including TLS handling [1]addDomainToCompose()(lines 134–237) — injects those labels into the compose spec [2]writeDomainsToCompose()(lines 109–133) — encodes the modified compose file and returns the deployment command [3]Integration point:
packages/server/src/utils/builders/compose.tsat line 26 callswriteDomainsToCompose()[4].Regarding
certificateType === "none": The code at lines 340–344 does settraefik.http.routers.{name}.tls=truewhen HTTPS is enabled [5]:This should allow Traefik to use SNI-based matching against its loaded certificate store. If you're still getting 526, it's worth verifying:
docker logson the Traefik container for TLS-related messages or hit the Traefik API at/api/rawdatato see loaded certificates and router configs)If the cert is loaded and SNI matching just isn't working, the fix in your PR might need to add explicit
tls.domainsortls.optionslabels pointing to the certificate, or introduce a proper dropdown that maps to the certificate's path directly — rather than relying on Traefik's implicit SNI matching.There are also tests at
apps/dokploy/__test__/compose/domain/labels.test.tsif you want to validate behavior changes.To reply, just mention @dosu.
Docs are dead. Just use Dosu.
Siumauricio commentedon Jun 29, 2026
Hey, I added some suggestions on the UI, If you want to use a cloudflare certificate you can follow this guide https://docs.dokploy.com/docs/core/domains/cloudflare
Mubashir-teapot commentedon Jun 29, 2026
Thanks both — tried the Cloudflare guide approach again (Certificate type none on the domain, matching cert in the Certificates section) and confirmed via direct SNI check against the server (bypassing Cloudflare entirely) that Traefik is still presenting TRAEFIK DEFAULT CERT, not the uploaded one:
$ nmap --script ssl-cert -p 443
| ssl-cert: Subject: commonName=TRAEFIK DEFAULT CERT
| Subject Alternative Name: DNS:.traefik.default
So the SNI-based fallback @dosu described (tls=true with no certResolver → Traefik should match against its loaded cert store) isn't kicking in for me, even though the cert files are confirmed present and well-formed on disk (certificate.yml, chain.crt, privkey.key under dynamic/certificates//). Still getting 526 from Cloudflare in Full (Strict).
@Siumauricio I saw #4705 — is that merged into a build I can pull and test, or still pending? Want to confirm whether this is purely the missing-selector UX gap your PR addresses, or a separate bug in the SNI fallback matching itself. If the fallback is genuinely not matching despite a valid CN/SAN, that's a second issue beyond just "no UI to pick a cert" — happy to dig into createDomainLabels()/addDomainToCompose() and the Traefik docker-provider side to confirm which one it is, and send a PR once I know which.
dosubot commentedon Jun 29, 2026
@Mubashir-teapot — I dug into this further and I think you're right that there's a real bug here beyond just the missing UI selector. Here's what I found:
PR #4705 adds help text to the domain form confirming the expected behavior: when "None" is selected, Traefik should automatically match a loaded certificate via SNI [1]. It's a docs/UX improvement, not a fix for the SNI matching itself.
Why SNI matching may be failing:
The
certificate.ymlgenerated by Dokploy contains only file paths — no domain/SAN hints [2]:Traefik must parse the actual
.crtfile to extract CN/SAN for matching. For this to work, the certificate's CN/SAN must exactly match the domain in the router'sHost()rule. A few things to check:Verify your cert's CN/SAN:
Verify the exact Host() rule on the container:
Compare them exactly — Compose services don't normalize domains (no lowercase conversion), so if there's any case mismatch between the Host() rule and the cert's SAN, SNI matching will silently fail and Traefik falls back to its default cert [3].
Cloudflare Origin CA wildcards — if your cert is
*.example.combut the Host() rule isexample.com(bare domain, no subdomain), that won't match either.Also worth checking Traefik's debug logs (
--log.level=DEBUG) — it should log which certificates it's loading from the file provider and any SNI matching attempts.If the CN/SAN and Host() rule match correctly and it still falls back to the default cert, that would confirm a bug in how Traefik processes file-provider certificates for Docker-provider routers — which would be a separate issue from what #4705 addresses.
To reply, just mention @dosu.
Share context across your team and agents. Try Dosu.