dokploy icon indicating copy to clipboard operation
dokploy copied to clipboard

Support for Cloudflare Origin CA certificates in Dokploy

Open soccerlover096 opened this issue 7 months ago • 1 comments

What problem will this feature address?

Currently, Dokploy only supports Let's Encrypt for SSL certificates. When using Cloudflare in Full (Strict) mode, we need to install Cloudflare Origin CA certificates on the server. This process is manual and prone to breaking during Dokploy updates.

Describe the solution you'd like

I would like Dokploy to natively support Cloudflare Origin CA certificates alongside Let's Encrypt. This would allow users to:

  1. Upload/paste their Cloudflare Origin CA certificate and private key in the Dokploy UI
  2. Select "Cloudflare Origin CA" as a certificate option when configuring domains
  3. Automatically configure Traefik to use these certificates
  4. Maintain the configuration across Dokploy updates

Describe alternatives you've considered

I've researched the following potential alternatives, although I haven't implemented them personally:

  1. Manual configuration: Configuring Traefik directly by modifying Docker service definitions and mounting certificate files. This approach seems functional but likely breaks during Dokploy updates and requires advanced technical knowledge.

  2. Cloudflare Tunnels: This eliminates the need for origin certificates by establishing a secure tunnel between Cloudflare and the origin server. However, this adds complexity and potential dependencies on Cloudflare's infrastructure.

  3. Using Full mode instead of Full (Strict): This is a simpler but less secure alternative that doesn't validate origin certificates. It doesn't provide the same security guarantees as Full (Strict) mode.

  4. Custom deployment scripts: Creating scripts to reinstall certificate configurations after Dokploy updates. This would be a brittle solution requiring maintenance with each Dokploy release.

Additional context

Many users deploy their applications behind Cloudflare for enhanced security and performance. The Full (Strict) SSL mode in Cloudflare requires a trusted certificate on the origin server, and Cloudflare provides free Origin CA certificates for this purpose.

Currently, the workaround involves manually configuring Traefik and mounting certificate files, which is complex and breaks during updates.

Will you send a PR to implement it?

Maybe, need help

soccerlover096 avatar May 06 '25 10:05 soccerlover096

@soccerlover096 there is a dynamic folder already mounted in traefik so you can just do the following,

Save your certs in dir below on the host

/etc/dokploy/traefik/dynamic/certs/

tls:
  certificates:
    - certFile: /etc/dokploy/traefik/dynamic/certs/domain.cert
      keyFile: /etc/dokploy/traefik/dynamic/certs/domain.key

Then save the above file at /etc/dokploy/traefik/dynamic/certs.yaml

That should be enough, check logs after in case of any errors, yes it isn't done within the ui, but it still works fine and is persistent, there is no need to alter any mounts

djsisson avatar May 06 '25 14:05 djsisson

I am using cloudflare tunnels and am using the same approach as @djsisson, it works like a charm.

Just make sure in your service -> domain config in Dokploy that you set your domain to https, Certificate Provider to Custom, and Custom Certificate Resolver to file.

In cloudflare tunnels Origin Server Name should be your domain with subdomain if you have one and it points to https://localhost:443

The origin certs last for 15 years so this really won't need to be touched again

moorej2400 avatar May 26 '25 23:05 moorej2400

I am using cloudflare tunnels and am using the same approach as @djsisson, it works like a charm.

Just make sure in your service -> domain config in Dokploy that you set your domain to https, Certificate Provider to Custom, and Custom Certificate Resolver to file.

In cloudflare tunnels Origin Server Name should be your domain with subdomain if you have one and it points to https://localhost:443

The origin certs last for 15 years so this really won't need to be touched again

Hello, I’m really glad to find someone else using Dokploy together with Cloudflare Tunnel, but I'm encountering an issue and hope to get some help.

I deployed Meilisearch using the provided template, and then created a tunnel using the Cloudflare-provided Docker image.

In the Cloudflare Tunnels dashboard, I set the public hostname to my domain, and the service address to the Meilisearch instance running in Dokploy, which is:

http://projectsname-meilisearch-gktdsr:7700

However, when I access the domain, I see this error:

502 Bad Gateway
Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared

When I checked the Cloudflare container logs, I found the following error:

2025-05-28T08:38:38Z ERR  error="Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared: dial tcp: lookup projectsname-meilisearch-gktdsr on 127.0.0.11:53: no such host" connIndex=2 event=1 ingressRule=0 originService=http://projectsname-meilisearch-gktdsr:7700

I’ve confirmed that http://projectsname-meilisearch-gktdsr:7700 is reachable from other services/containers (for example, from my Next.js project).

youyou-sudo avatar May 28 '25 08:05 youyou-sudo

@youyou-sudo that service name will only work if cloudflare is in the same network as that service

if it is running on the host or in a different network, it will not work

you instead just need to point it to your proxy, so localhost 80 if its running on the host or the proxy service name if it's in the same network as your proxy.

please note, if you have set up http->https redirects you will need to switch to using https localhost 443 and set the origin domain in your tunnel as well as ensure the cf origin certificate is being used by your proxy. otherwise you would get infinite redirect error

i will add, you can use that service name, if you used a host updater, basically it will edit your vps hosts file and map container names to ip's, but thats not usually used.

djsisson avatar May 28 '25 09:05 djsisson

Here is a guide I wrote for myself copied and pasted from my Notion. This is a setup where you point your cloudflare tunnel to your traefik reverse proxy Cloudflare Tunnel → Dokploy Reverse Proxy → Service Container. In the guide I have an example dokploy service called coder and domain example.io.

HTTPS Setup with Traefik

1: Go to cloudflared and get an Origin Server cert as PEM format

  • Navigate to your domain (example.io)
  • Go to SSL/TLSOrigin Server

2: Save Certificate Files on Your Server

  • Add .crt and .key files to /etc/dokploy/traefik/dynamic/certificates
  • Set permissions
sudo chmod 644 '/etc/dokploy/traefik/dynamic/certificates/exampleio.crt'
sudo chmod 600 '/etc/dokploy/traefik/dynamic/certificates/exampleio.key'

3: Update Traefik Config

  • Remove lets encrypt from the main config, we will be using certs from cloudflare
providers:
  swarm:
    exposedByDefault: false
    watch: true
  docker:
    exposedByDefault: false
    watch: true
    network: dokploy-network
  file:
    directory: /etc/dokploy/traefik/dynamic
    watch: true
entryPoints:
  web:
    address: ':80'
  websecure:
    address: ':443'
    http3:
      advertisedPort: 443
    # http:
    #   tls:
    #     certResolver: letsencrypt
api:
  insecure: true
# # Disabled because I am using cloudflare origin certificates with cloudflared tunnels
# certificatesResolvers:
#   letsencrypt:
#     acme:
#       email: [email protected]
#       storage: /etc/dokploy/traefik/dynamic/acme.json
#       httpChallenge:
#         entryPoint: web
  • Create a dynamic config for the new certificates
# /etc/dokploy/traefik/dynamic/certificates.yml
tls:
  certificates:
    - certFile: /etc/dokploy/traefik/dynamic/certificates/exampleio.crt
      keyFile: /etc/dokploy/traefik/dynamic/certificates/exampleio.key
      stores:
        - default
  stores:
    default:
      defaultCertificate:
        certFile: /etc/dokploy/traefik/dynamic/certificates/exampleio.crt
        keyFile: /etc/dokploy/traefik/dynamic/certificates/exampleio.key
  • Update middleware
# /etc/dokploy/traefik/dynamic/middlewares.yml
http:
  middlewares:
    redirect-to-https:
      redirectScheme:
        scheme: https
        permanent: true

4: Set Service Domain

  • Add the sub domain to the service in dokploy as https
    • Set Certificate Provider to Custom
    • Set Custom Certificate Resolver to file
  • Add the sub domain to cloudflared tunnel online
Hostname Config:
subdomain: coder
domain: example.io
path: none

Service:
type: https 
URL: localhost:443  ← Change from port 80 to 443

Additional application settings:
TLS → Origin Server Name: coder.example.io  ← THIS IS IMPORTANT or get 502 Bad Gateway. THIS MUST ALSO MATCH DOKPLOY DOMAIN SETTING

5: Restart services

# Restart Traefik to pick up new certificates
docker restart $(docker ps -q --filter "name=traefik")

# Redeploy your coder service in Dokploy (this will apply the HTTPS labels)
Requires manaual re-deploy

6: Verify deploy

View logs

docker logs $(docker ps -q --filter "name=traefik") 2>&1 | grep -i cert

Check cert

openssl s_client -connect localhost:443 -servername coder.example.io

That's it!

moorej2400 avatar May 30 '25 02:05 moorej2400

Here is a guide I wrote for myself copied and pasted from my Notion. This is a setup where you point your cloudflare tunnel to your traefik reverse proxy Cloudflare Tunnel → Dokploy Reverse Proxy → Service Container. In the guide I have an example dokploy service called coder and domain example.io.

HTTPS Setup with Traefik

.....

docker logs $(docker ps -q --filter "name=traefik") 2>&1 | grep -i cert Check cert

openssl s_client -connect localhost:443 -servername coder.example.io That's it!

This is actually really helpful, it worked for me too i was struggling with the certificates and traefik config for days, i hope you guys find some easier way, besides that... great work 💪💪

MERakram avatar Jun 14 '25 23:06 MERakram

+1 to have this integrated into the Dokploy UI somehow 😊

kylegillen avatar Jul 01 '25 02:07 kylegillen

@moorej2400 Could you kindly share a sample compose file of how the traefik labels look like with this cloudflare tunnel setup?

jobchumo avatar Jul 03 '25 19:07 jobchumo

@moorej2400 Could you kindly share a sample compose file of how the traefik labels look like with this cloudflare tunnel setup?

Dokploy Domain config Image

traefik labels are autogenerated by Dokploy, you can see your config like this if you click on preview compose. You DO NOT need to add these manually, they will be injected by configuring your domain properly as in the screenshot.

version: '3.8'
services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:1.97.1
    restart: always
    environment:
      - N8N_HOST=${N8N_HOST}
      - N8N_PORT=${N8N_PORT}
      - N8N_PROTOCOL=http
      - NODE_ENV=production
      - WEBHOOK_URL=https://${N8N_HOST}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - N8N_SECURE_COOKIE=false
      - N8N_RUNNERS_ENABLED=true
    volumes:
      - n8n_data-jproduction-n8n-sgfv2h:/home/node/.n8n
    networks:
      - jproduction-n8n-sgfv2h
    labels:
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-web.rule=Host(`n8n.example.io`)
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-web.entrypoints=web
      - traefik.http.services.jproduction-n8n-sgfv2h-4-web.loadbalancer.server.port=5678
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-web.service=jproduction-n8n-sgfv2h-4-web
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-web.middlewares=redirect-to-https@file
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-websecure.rule=Host(`n8n.example.io`)
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-websecure.entrypoints=websecure
      - traefik.http.services.jproduction-n8n-sgfv2h-4-websecure.loadbalancer.server.port=5678
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-websecure.service=jproduction-n8n-sgfv2h-4-websecure
      - traefik.http.routers.jproduction-n8n-sgfv2h-4-websecure.tls.certresolver=file
      - traefik.enable=true
volumes:
  n8n_data-jproduction-n8n-sgfv2h: null
networks:
  jproduction-n8n-sgfv2h:
    name: jproduction-n8n-sgfv2h
    external: true

moorej2400 avatar Jul 04 '25 18:07 moorej2400

@moorej2400 Thanks. Finally got my apps working

jobchumo avatar Jul 07 '25 13:07 jobchumo

Does this mean that following the guide for Cloudflare's Strict mode in the docs will simply not work? https://docs.dokploy.com/docs/core/domains/cloudflare#assign-a-domain-full-strict

MerlinB avatar Jul 22 '25 09:07 MerlinB

@MerlinB you can use strict

  1. install cf origin domain cert or use dns challenge in traefik
  2. change to HTTPS localhost:443 in tunnel entry
  3. set origin domain in tls settings for each https entry, can also turn on http2
  4. use https in your domains

Optional If you want to close 80/443 ports on your host Put both cloudflared and traefik in same docker network, no host mode. Set tunnel entries to use traefik service name not localhost (dokploy-traefik) Remove port bindings in traefik or set to private network ip. Run cloudflare warp locally and turn on split tunnels for it, set so your private network subnet is sent via cloudflare You can now access your host from local using its private network ip Means you do not need any ssh entries in your tunnel, can just ssh your network ip As well as avoid any 413 errors with >100mb layers in registries when pushing to your registry if you use cf warp as part of your workflow

djsisson avatar Jul 22 '25 10:07 djsisson

I found a way to make HTTPS work with Cloudflare's Full (Strict) mode using Dokploy and Traefik, without using Let's Encrypt or exposing ports manually.

This setup uses manually installed Cloudflare origin certificates (domain.cert + domain.key) as @djsisson suggested.

Image

These files need to be placed inside the Traefik container file system. Since Dokploy’s UI doesn’t currently allow uploading files into the Traefik file system, for certificates.yaml, domain.cert and domain.key you’ll need to create them manually (e.g., via docker cp, bind mounts, or by rebuilding your container image).

The domain.cert and domain.key are the TLS certificate signed by Cloudflare that you can generate for free.

# /etc/dokploy/traefik/traefik.yml
global:
  sendAnonymousUsage: false
providers:
  swarm:
    exposedByDefault: false
    watch: true
  docker:
    exposedByDefault: false
    watch: true
    network: dokploy-network
  file:
    directory: /etc/dokploy/traefik/dynamic
    watch: true
entryPoints:
  web:
    address: ':80'
  websecure:
    address: ':443'
    http3:
      advertisedPort: 443
    # http:
    #   tls:
    #     certResolver: letsencrypt
api:
  insecure: true
# certificatesResolvers:
#   letsencrypt:
#     acme:
#       email: [email protected]
#       storage: /etc/dokploy/traefik/dynamic/acme.json
#       httpChallenge:
#         entryPoint: web
# /etc/dokploy/traefik/dynamic/middlewares.yml
http:
  middlewares:
    redirect-to-https:
      redirectScheme:
        scheme: https
        permanent: true
# /etc/dokploy/traefik/dynamic/certificates/certificates.yaml
tls:
  certificates:
    - certFile: /etc/dokploy/traefik/dynamic/certificates/domain.cert
      keyFile: /etc/dokploy/traefik/dynamic/certificates/domain.key

⚙️ Routing your apps (the trick)

Finally, for dokploy.yml there is a bit of a trick. I had to create routers and services for each application I wanted to expose with HTTPS enabled, it means that, if you want, for example, to have dokploy.yourdomain.com, subdomain1.yourdomain.com, subdomain2.yourdomain.com, etc, you need to create a router and a service for every single one of them.

I did the creation of routers and services all inside the dokploy.yml but you can separate them on many files in case you want to organize it better. For example, instead of having the subdomain1-router-app and subdomain1-service-app inside the dokploy.yml I could've create a file called subdomain1.yml and it would still work fine.

This step bypasses the need for the Domains tab in Dokploy UI, as long as you configure routes manually in .yml files inside /etc/dokploy/traefik/dynamic. It means that your 'Domains' tab inside the service will be useless, you must rely strictly on your routers-services configured by the yml files.

# /etc/dokploy/traefik/dynamic/dokploy.yml
http:
  routers:
    dokploy-router-app:
      rule: Host(`dokploy.yourdomain.com`) && PathPrefix(`/`)
      service: dokploy-service-app
      entryPoints:
        - websecure
      tls: {}
    subdomain1-router-app:
      rule: Host(`subdomain1.yourdomain.com`) && PathPrefix(`/`)
      service: subdomain1-service-app
      entryPoints:
        - websecure
      tls: {}
  services:
    dokploy-service-app:
      loadBalancer:
        servers:
          - url: http://dokploy:3000
        passHostHeader: true
    subdomain1-service-app:
      loadBalancer:
        servers:
          - url: http://subdomain1-container:8080
        passHostHeader: true

Tips below:

The "- url" under "servers:" refers to the internal address of the container inside the Docker network used by Traefik. So, for this line:

    subdomain1-service-app:
      loadBalancer:
        servers:
          - url: http://subdomain1-container:8080
        passHostHeader: true

You're telling Traefik:

"When a request comes for subdomain1.yourdomain.com, forward it to a container reachable as subdomain1-container on port 8080."

The hostname (like subdomain1-container) must match the Docker service name or container name.

IMPORTANT: The container (like subdomain1-container) must be sharing at least one network connection with the Traefik container otherwise Traefik won't be able to resolve the http://subdomain1-container:8080 internally and probably will show Bad Gateway on your browser when accessing subdomain1.yourdomain.com.

Also, the port (like 8080 for subdomain1-container) must be the one that is listening on internally (not the host-exposed port).

troyaks1 avatar Aug 05 '25 18:08 troyaks1

is there any simple way to use Cloudflare API instead of Manually generating Cloudflare Origin CA certificates and insert Dokploy + Treafik ? (That are proven and solid working)

  • token with Zone:DNS:Edit permissions
  • Scope to specific zones
# /etc/dokploy/traefik/traefik.yml
global:
  sendAnonymousUsage: false

providers:
  docker:
    exposedByDefault: false
    watch: true
    network: dokploy-network
  file:
    directory: /etc/dokploy/traefik/dynamic
    watch: true

entryPoints:
  web:
    address: ':80'
  websecure:
    address: ':443'
    http:
      tls:
        certResolver: cloudflare

certificatesResolvers:
  cloudflare:
    acme:
      email: [email protected]
      storage: /etc/dokploy/traefik/dynamic/acme.json
      dnsChallenge:
        provider: cloudflare
        delayBeforeCheck: 30
# In Dokploy 
environment:
  - CF_DNS_API_TOKEN=your_cloudflare_dns_token

raddah avatar Sep 09 '25 21:09 raddah

As a note for future readers: You can upload certificates directly via /dashboard/settings/certificates and change etc/dokploy/traefik/dynamic/dokploy.yml via /dashboard/traefik:

# /etc/dokploy/traefik/dynamic/dokploy.yml
http:
  routers:
    dokploy-router-app:
      rule: Host(`dokploy.docker.localhost`) && PathPrefix(`/`)
      service: dokploy-service-app
      entryPoints:
        - web
      middlewares:
        - redirect-to-https
    dokploy-router-app-secure:
      rule: Host(`example.com`)
      service: dokploy-service-app
      entryPoints:
        - websecure
      tls:
        certResolver: {} # <--- do this
  services:
    dokploy-service-app:
      loadBalancer:
        servers:
          - url: http://dokploy:3000
        passHostHeader: true

li-kai avatar Sep 28 '25 09:09 li-kai