Caddy on Synology DSM 7.2

1. The problem I’m having:

Summary

First time setup. Caddy Container is exiting after throwing multiple errors. It seems to me like it is not consuming my caddyfile at all.

Goals:

  • Cloudflare DNS-01
  • wildcard certs only
  • Do not try to capture port 443 and 80 on the host, as it is statically assigned to nginx on Synology.
  • reverse proxy for containers running on the same host.

2. Error messages and/or full log output:

The main issues seem to be that caddy insists on wanting to bind to port 443 & 2019
It also appears something in my caddyfile is incorrectly formatted, I am wondering what that can be (see above for caddyfile).

Docker logs:

caddy  | {"level":"warn","ts":1737886889.542978,"msg":"failed to set GOMAXPROCS","error":"open /sys/fs/cgroup/cpu/cpu.cfs_quota_us: no such file or directory"}
caddy  | {"level":"info","ts":1737886889.543482,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
caddy  | {"level":"info","ts":1737886889.546961,"msg":"adapted config to JSON","adapter":"caddyfile"}
caddy  | {"level":"warn","ts":1737886889.5470042,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
caddy  | {"level":"info","ts":1737886889.548721,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
caddy  | {"level":"info","ts":1737886889.549162,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000192200"}
caddy  | {"level":"info","ts":1737886889.5492225,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
caddy  | {"level":"info","ts":1737886889.5492504,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
caddy  | Error: loading initial config: loading new config: http app module: start: listening on :443: listen tcp :443: bind: address already in use

3. Caddy version:

Can’t even run it to check, but I just pulled the docker image today.

4. How I installed and ran Caddy:

a. System environment:

  • DSM 7.2
  • Docker 20.10.2 (I know…)
  • Docker Compose 2.9.0

b. Command:

Building caddy with the acm-dns plugin is successful using this command:

docker build -t caddy:latest /volume1/docker/caddy/dockerfile-caddy
Dockerfile
FROM caddy:builder AS builder

RUN xcaddy build \
    --with github.com/caddy-dns/cloudflare

FROM caddy:latest

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

c. Compose file:

docker compose yaml
services:
  caddy:
    build:
      context: ${DOCKER_FOLDER}/caddy/dockerfile-caddy
      dockerfile: Dockerfile
    image: caddy:latest
    container_name: caddy
    hostname: caddy
    restart: unless-stopped
    env_file: .env
    ports:
      - 4382:4382
    volumes:
      - ${DOCKER_FOLDER}/caddy/Caddyfile:/etc/caddy/Caddyfile
      - ${DOCKER_FOLDER}/caddy/caddy_config:/config
      - ${DOCKER_FOLDER}/caddy/caddy_data:/data
networks:
  default:
    name: $DOCKER_MY_NETWORK
    external: true
.env
TZ=Europe/Berlin
DOCKER_FOLDER=/volume1/docker
PUBLIC_DOMAIN=cd.domain1.com
PRIVATE_DOMAIN=cd.domain2.com
CLOUDFLARE_API_TOKEN=<mytoken>
DOCKER_MY_NETWORK=default_container_network_IPv4_only

(yes, I have redacted the domains, as the container isn’t even starting, so I assume domains are irrelevant here. At least for now.)

d. My complete Caddy config:

Logs say format is wrong on line 2 already (the one with acme_dns), which makes me think it isn’t even able to read the real caddyfile. But I might be wrong, open to advice.

Caddyfile
{
    acme_dns cloudflare {$CLOUDFLARE_API_TOKEN}
}


*.{$PUBLIC_DOMAIN}:4382 {

	tls {
        dns cloudflare {$CLOUDFLARE_API_TOKEN}
    }

    @a host nc.{$PUBLIC_DOMAIN}:4382
    handle @a {
        reverse_proxy localhost:4380
    }

    handle {
        abort
    }
}


*.{$PRIVATE_DOMAIN}:4382 {

	tls {
        dns cloudflare {$CLOUDFLARE_API_TOKEN}
    }

    @a host nc.{$PRIVATE_DOMAIN}:4382
    handle @a {
        reverse_proxy localhost:4380
    }

    handle {
        abort
    }
}

ok, so it seems I had a tab in front of line 2, which caddy didn’t like at all.

But the error is a bit misleading, it should rather log something like “YOUR CADDYFILE IS CORRUPTED AT LINE 2!! I AM FALLING BACK TO DEFAULTSS!!”, in bold an red, rather than politely complaining about formating…

That cannot be it. Something else must’ve changed in between.

Seems you are right. I suddenly had different errors after removing the tab, but there is still some fundamental issue in terms of permissions / file access I have the impression.

From the container command line, I can see the caddyfile, but running caddy fmt --overwrite errors out saying “Error: reading input file: open Caddyfile: no such file or directory”.

detailed logs
/srv # caddy fmt --overwrite
2025/01/26 15:41:42.902 WARN    failed to set GOMAXPROCS        {"error": "open /sys/fs/cgroup/cpu/cpu.cfs_quota_us: no such file or directory"}
Error: reading input file: open Caddyfile: no such file or directory
/srv # caddy --version
2025/01/26 15:47:27.577 WARN    failed to set GOMAXPROCS        {"error": "open /sys/fs/cgroup/cpu/cpu.cfs_quota_us: no such file or directory"}
v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=
/srv # cat /etc/caddy/Caddyfile
{
    debug
    acme_dns cloudflare {$CLOUDFLARE_API_TOKEN}
    auto_https off
    admin off
}


*.{$PUBLIC_DOMAIN}:4382 {

        tls {
        dns cloudflare {$CLOUDFLARE_API_TOKEN}
    }

    @a host nc.{$PUBLIC_DOMAIN}:4382
    handle @a {
        reverse_proxy localhost:4380
    }

    handle {
        abort
    }
}


*.{$PRIVATE_DOMAIN}:4382 {

        tls {
        dns cloudflare {$CLOUDFLARE_API_TOKEN}
    }

    @a host nc.{$PRIVATE_DOMAIN}:4382
    handle @a {
        reverse_proxy localhost:4380
    }

    handle {
        abort
    }
}

/srv # 

You’re in the directory /srv but the Caddyfile is in /etc/caddy/Caddyfile. How should Caddy know the config is in that other location? If the --config flag isn’t passed, Caddy assumes the Caddyfile is in the current directory, otherwise it has to told where it is.

1 Like

The following threw me off:

  • I told caddy where the caddyfile is, in the compose file. I guess different caddy instance, but that’s not obvious to a newcomer.
  • The caddyfile is in the default folder, I thought the command would try the default if it’s not specified
  • “no such file or directory” feels like it is actually trying something while in fact it is not trying anything it seems. A better error message might be “please specify the path to the caddyfile”.
  • the logs specifically state “run caddy fmt --overwrite” and not “run caddy fmt --overwrite <path-to-your-caddyfile>

Anyway, I ran caddy fmt --overwrite /etc/caddy/Caddyfile and all it did is replacing all spaces with tabs, so the caddyfile was sound it seems.

But caddy still refuses to generate any certificate it appears.

caddy  | {"level":"debug","ts":1737905026.7263138,"logger":"tls.handshake","msg":"no certificate matching TLS ClientHello","remote_ip":"172.16.0.1","remote_port":"47558","server_name":"nc.cd.domain1.com","remote":"172.16.0.1:47558","identifier":"nc.cd.domain1.com","cipher_suites":[4865,4867,4866,49195,49199,52393,52392,49196,49200,49162,49161,49171,49172,156,157,47,53],"cert_cache_fill":0,"load_or_obtain_if_necessary":true,"on_demand":false}

Could the fact that I use a sub-sub-domain and I am trying to get a wildcard cert on the subdomain be a problem? I wouldn’t expect it, but it might be a rather rare setup. The zones in cloudflare is the full domain “domain1.com”, not “cd.domain1.com”.

The really strange thing is, there isn’t a single log line about caddy trying to connect to cloudflare or any acme log. It’s like it’s disabled…

The compose file isn’t for a separate tool. We cannot be expected to explain how Docker Compose works. Also, you’re executing the caddy fmt in the shell inside the container, so the compose file is irrelevant.

There’s no default folder. Files can be anywhere, and the user is expected to point Caddy at them. The only default is the current directory, which is limited to specific commands in specific scenarios. This is explained in the docs:

It does say Error: reading input file: open Caddyfile. It’s a convention in Linux/Unix that unprefixed files names assume the current directory.

As said earlier, the command assumes the Caddyfile in the current directory by default, and the user is expected to check the documentation of the command because particularities change based on how they setup their computers.

You’ll have to share the full log and the request for us to know what’s happening. I can’t judge based on redacted log lines.