diff --git a/apps/docs/content/docs/core/domains/cloudflare.mdx b/apps/docs/content/docs/core/domains/cloudflare.mdx
index a85de688..5438c28d 100644
--- a/apps/docs/content/docs/core/domains/cloudflare.mdx
+++ b/apps/docs/content/docs/core/domains/cloudflare.mdx
@@ -68,6 +68,11 @@ We assume that you have enabled the `Full (Strict)` mode in the previous step, i
20. You should see the application running on the domain you just created.
### Using Cloudflare's Origin CA
+
+
+**Already served this domain with Let's Encrypt?** The steps below are not enough on their own. Traefik keeps serving the old Let's Encrypt certificate and Cloudflare keeps returning **Error 526** in `Full (Strict)` mode, even though every step looks correct. See [Migrating a domain that already used Let's Encrypt](#migrating-a-domain-that-already-used-lets-encrypt).
+
+
1. Go to cloudflare dashboard and then click on `Account Home` -> Select the Domain.
2. On the left side, click `SSL/TLS`.
3. Click on `Origin Server`.
@@ -96,7 +101,117 @@ You can also create a certificate for wildcards domains eg. `*.dokploy.com` and
**Important**: With a free Cloudflare account, this methods work only for the main domain and subdomains, not for sub-subdomains. Eg. `api.dokploy.com` works but `staging.api.dokploy.com` does not work.
+#### Migrating a domain that already used Let's Encrypt
+
+The steps above assume a domain that has never been served with a Let's Encrypt certificate. If Dokploy already issued one for it, setting the `Certificate` field to `None` is not enough: the old certificate stays in Traefik's ACME store and keeps being served, because a certificate matching the exact hostname (`api.dokploy.com`) takes precedence over a wildcard Origin CA certificate (`*.dokploy.com`). In `Full (Strict)` mode Cloudflare validates that certificate, so once it expires you get **Error 526** even though the Origin CA certificate is installed correctly.
+
+Three extra steps are needed.
+
+**1. Stop Traefik from requesting Let's Encrypt certificates for the domain**
+
+Besides the per-domain setting, the `websecure` entrypoint in `/etc/dokploy/traefik/traefik.yml` carries an instance-wide default that applies to every router which does not define its own TLS block:
+
+```yaml
+ websecure:
+ address: :443
+ http:
+ tls:
+ certResolver: letsencrypt # remove this line only
+```
+
+It has to become:
+
+```yaml
+ websecure:
+ address: :443
+ http:
+ tls: {}
+```
+
+
+Keep the empty braces. Written as `tls:` alone it is parsed as null and TLS is disabled on the entrypoint, which makes port 443 serve plain HTTP and every site return **Error 525 (SSL handshake failed)**. Removing the whole `http.tls` block has the same effect.
+
+
+
+Domains that still use `Let's Encrypt` as their certificate provider are not affected: Dokploy writes `tls.certResolver` into their own router configuration, so they keep renewing normally.
+
+
+Then confirm no router still requests a resolver:
+
+```bash
+grep -rn certResolver /etc/dokploy/traefik/dynamic/*.yml
+```
+
+Every match is a domain whose `Certificate` field is still set to `Let's Encrypt`.
+
+**2. Remove the old certificate from the ACME store**
+Existing certificates are stored in `/etc/dokploy/traefik/dynamic/acme.json`. Back it up, then drop the entries for the hostnames your Origin CA certificate covers, keeping the `Account` object:
+
+```bash
+docker run --rm -v /etc/dokploy/traefik/dynamic:/t alpine \
+ cp -a /t/acme.json /t/acme.json.bak
+
+docker run --rm -v /etc/dokploy/traefik/dynamic:/t python:3-alpine python - <<'EOF'
+import json
+
+# hostnames now covered by the Origin CA certificate
+REMOVE = {"api.dokploy.com"}
+
+path = "/t/acme.json"
+store = json.load(open(path))
+for name, resolver in store.items():
+ kept = []
+ for cert in resolver.get("Certificates") or []:
+ if cert["domain"]["main"] in REMOVE:
+ print("removing:", cert["domain"]["main"])
+ else:
+ kept.append(cert)
+ resolver["Certificates"] = kept
+json.dump(store, open(path, "w"))
+EOF
+
+docker run --rm -v /etc/dokploy/traefik/dynamic:/t alpine \
+ sh -c 'chown root:root /t/acme.json && chmod 600 /t/acme.json'
+```
+
+
+Traefik refuses to start if `acme.json` is not owned by root with `0600` permissions, so do not skip the last command.
+
+
+**3. Restart Traefik**
+
+The ACME store is only read at startup, so nothing changes until Traefik restarts. Restart the container, do not recreate it:
+
+```bash
+docker restart dokploy-traefik
+```
+
+#### Verifying the certificate is actually being served
+
+Check the origin directly, passing the hostname as SNI:
+
+```bash
+echo | openssl s_client -connect 127.0.0.1:443 -servername api.dokploy.com 2>/dev/null \
+ | openssl x509 -noout -issuer -enddate
+```
+
+The issuer must be Cloudflare:
+
+```
+issuer=C = US, O = "CloudFlare, Inc.", OU = CloudFlare Origin SSL Certificate Authority, ...
+notAfter=... 2041 GMT
+```
+
+| What you see | What it means |
+| --- | --- |
+| `issuer=... Let's Encrypt` | The old certificate is still shadowing the Origin CA one, step 2 or 3 was not applied |
+| `TRAEFIK DEFAULT CERT` | Traefik has no matching certificate, check that the hostname is covered by the certificate's SANs |
+| The handshake fails | TLS is disabled on the entrypoint, check the `tls: {}` braces from step 1 |
+
+
+Do not verify with `curl https://your-domain`. If the hostname is protected by Cloudflare Access, Cloudflare answers with a `302` redirect to the login page at the edge and never contacts your origin, so an expired or missing origin certificate still looks healthy.
+
## Assign a Domain Flexible