Conditional acme_dns on {env.POWERDNS_SERVER_URL}

1. The problem I’m having:

We have deployed Caddy within our docker environment on 5 stages. Some stages need to set the acme_dns to get certificates via DNS because the services are not accessible from outside (local, experimental stage).

I have configured acme now to use acme_dns in my Caddyfile:

    cert_issuer acme
    email {$TLS_ACME_EMAIL}
    acme_dns powerdns {env.POWERDNS_SERVER_URL} {env.POWERDNS_API_TOKEN}

On prod stage, I don’t want (and can’t) reach the POWERDNS Server. So this acme_dns fails and I need to change the config.

I would love to see the possibility to make the acme_dns conditional. If POWERDNS_SERVER_URL is set, then use this, otherwise act as if this row has been commented out.

Is there an IF statement or something alike for this?

I have found the map feature but believe that this won’t work in this context.

2. Error messages and/or full log output:

not available currently.

3. Caddy version:

Caddy v2.8.4

4. How I installed and ran Caddy:

caddy via docker

Dockerfile:


Primary navigation
Homepage
15
44
Project

    C
    caddy

    Issues
    0

Merge requests
0
Pipelines
Container registry
Tags
Repository graph

    24-7 Digital
    247d NG
    servers
    caddy

    caddy
    Dockerfile

Dockerfile
Philipp Kolmann's avatar
Add powerdns API to caddy for Cert DNS issue
Kolmann Philipp authored 4 months ago
e89aa890
Dockerfile
850 B

FROM caddy:builder-alpine AS builder
RUN xcaddy build \
    --with github.com/ggicci/caddy-jwt \
    --with github.com/caddy-dns/powerdns
FROM caddy:2.8
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
ARG VCS_REF=0
ENV VCS_REF=$VCS_REF
RUN echo "VCS_REF=$VCS_REF"
ARG BUILD_DATE=0
ENV BUILD_DATE=$BUILD_DATE
RUN echo "BUILD_DATE=$BUILD_DATE"
RUN CADDY_VERSION=`caddy version`
ARG VERSION=""
ENV VERSION="$VERSION - Caddy $CADDY_VERSION"
RUN echo "VERSION=$VERSION"
RUN echo $CADDY_VERSION
LABEL org.opencontainers.image.version=$VERSION
LABEL org.opencontainers.image.revision=$VCS_REF
LABEL org.opencontainers.image.vendor="XXX"
LABEL org.opencontainers.image.title="caddy"
LABEL org.opencontainers.image.created=$BUILD_DATE
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

a. System environment:

Debian 12.11

b. Command:

run via Dockerfile:

CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

c. Service/unit/compose file:

services:
  caddy:
    env_file:
      - path: ../running.env
        required: true
      - path: ./running.env
        required: false
    restart: unless-stopped
    image: "${CADDY_IMAGE}"
    entrypoint: ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]
    volumes:
      - caddy_data:/data
      - ./caddy/log:/var/log
      - ./caddy/etc:/etc/caddy
    networks:
      lb:
        aliases:
          - scribe.localhost
      scribeint:

d. My complete Caddy config:

{
    log {
        # level DEBUG
        format json {
            time_format iso8601
        }
        output file /var/log/access.log {
            roll_size 1gb
            roll_keep 5
            roll_keep_for 720h
        }
    }

    cert_issuer acme
    email {$TLS_ACME_EMAIL}
    #acme_dns powerdns {env.POWERDNS_SERVER_URL} {env.POWERDNS_API_TOKEN}

    servers :443 {
        name https
        listener_wrappers {
            proxy_protocol {
                timeout 5s
                allow {$CADDY_PROXY_ALLOW_V4} {$CADDY_PROXY_ALLOW_V6}
            }
            tls
        }
    }
    servers :80 {
        name http
        listener_wrappers {
            proxy_protocol {
                timeout 5s
                allow {$CADDY_PROXY_ALLOW_V4} {$CADDY_PROXY_ALLOW_V6}
            }
        }
    }
}

http:// {
    log
}

{$SCRIBE_HOSTNAME} {
    log
    reverse_proxy scribe:8080 
}

Not sure if the Caddyfile supports conditional templating directly, but as a workaround, you could use an environment variable to handle this.

For example, you could define an ACMEDNS_DIRECTIVE environment variable. In your PROD environment, just leave it empty or unset. For other environments, set it like this:

ACMEDNS_DIRECTIVE="acme_dns powerdns $POWERDNS_SERVER_URL $POWERDNS_API_TOKEN"

Then in your Caddyfile, you can do:

    cert_issuer acme
    email {$TLS_ACME_EMAIL}
    {$ACMEDNS_DIRECTIVE}

That way, the acme_dns directive line only gets included when the environment variable is set, which should do the trick for switching between environments.

1 Like

Hi @timelordx

thanks a lot for this idea. This fixes my Caddyfile issue!

since we also have 2 services with caddy-l4 enabled we use the yaml caddyfile there.

Do you have an idea how to solve this issue there?

apps:
  tls:
    certificates:
      automate:
        - "#{ $LIVEKIT_HOSTNAME}"
        - "#{ $TURN_HOSTNAME}"
    automation:
      policies:
        - issuers:
            - module: acme
              challenges:
                dns:
                  resolvers:
                    - "8.8.8.8:53"
                    - "9.9.9.9:53"
                  provider:
                    name: "powerdns"
                    server_url: "#{ $POWERDNS_SERVER_URL }"
                    api_token: "#{ $POWERDNS_API_TOKEN }"

thanks
Philipp

No idea which Caddy YAML adapter you’re using, but this one, for example,

supports conditional configurations with templates:

#{if ne $ENVIRONMENT "production"}
logging:
  logs:
    default: { level: DEBUG }
#{end}
1 Like