How-To Guide: Caddy V2 & Cloudflare DNS-01 via Docker

This post outlines how I was able to get Caddy V2 & Cloudflare DNS ACME DNS-01 challenge working. It took a fair bit of doc review (the DNS-01 stuff for V2 is sparse at the moment), and some trial & error, so I hope it can help others!

Note that this process assumes (and my knowledge is limited to):

  1. You’re using Docker, and you know how to use it
  2. You use Cloudflare for DNS
  3. You wish to use DNS-01 ACME challenge via LetsEncrypt

Though in theory some of this can be re-purposed for other use-cases as needed.

Part 1: Docker Configuration

  • Option 1 (Easy, but less preferred):

    I built a quick Docker image with Caddy & the Cloudflare DNS module built in. Find it here on Docker Hub. Please note that you should NOT rely upon this image for anything important, in case I break it :slight_smile:

  • Option 2 (in case you’re a DIY-er, or in case I break Option 1 above):

    As Caddy has not yet bundled the DNS provider modules into the official Caddy docker image, you must build your own image with the module pre-loaded. The easiest way I found to do this is as follows:

    1. Create a new Dockerfile on GitHub with the content below. This builds the base caddy:latest image with the Cloudflare module added in:

      FROM caddy:builder AS builder
      RUN caddy-builder \

      FROM caddy:latest
      COPY --from=builder /usr/bin/caddy /usr/bin/caddy
    2. Deploy that image to Docker Hub via Docker’s documentation. Alternatively, Deploy to your own image repository solution.

    3. Deploy your newly-created container using the directions on the official Caddy docker image, with a slight modification for our new ACME integration. For example:

      docker run -it --name caddy \
        -p 80:80 \
        -p 443:443 \
        -v caddy_data:/data \
        -v caddy_config:/config \
        -v $PWD/Caddyfile:/etc/caddy/Caddyfile \
        -e \
        -e CLOUDFLARE_API_TOKEN=12345 \
        -e ACME_AGREE=true \

Part 2: Caddyfile

You should add the following to your Caddyfile as the tls directive. Note that I haven’t figured out why the using {env.CLOUDFLARE_EMAIL} for the email address didn’t work, so for now I’ve got it manually declared:

tls { 
  dns cloudflare {env.CLOUDFLARE_API_TOKEN}

That’s pretty much it! Please let me know if you have any questions related to this, and I’ll do my best to help out.


Thanks for posting!

Should we make this a wiki so that others can improve it over time?

This is a good post. I think any wiki article should also discuss the limitations of DNS-01 if users want to enable “orange-cloud” web-proxy protection in Cloudflare.

Thanks for the feedback! I think a wiki (maybe on the GitHub or General Docs?) around the various LetsEncrypt options would be good. This covers only one scenario, albeit a fairly popular one, from what I’ve seen.

Our wiki is here:

It’s just another category on the forums

1 Like

A post was split to a new topic: Unrecognized directive: dns

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.