Help with server certs renewing with duckdns and dynu

1. The problem I’m having:

I assume caddy would renew server certs at least a month before expiry. However, it is less than 19 days from expiry now. The certs are not renewing yet.

2. Error messages and/or full log output:

$ docker logs caddy
{"level":"info","ts":1748226702.0930386,"msg":"maxprocs: Honoring GOMAXPROCS=\"24\" as set in environment"}
{"level":"info","ts":1748226702.0936866,"msg":"GOMEMLIMIT is updated","package":"github.com/KimMachineGun/automemlimit/memlimit","GOMEMLIMIT":243095721984,"previous":9223372036854775807}
{"level":"info","ts":1748226702.093765,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1748226702.1207433,"msg":"adapted config to JSON","adapter":"caddyfile"}
{"level":"info","ts":"2025-05-26T02:31:42.125Z","logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":"2025-05-26T02:31:42.125Z","logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0005a7000"}
{"level":"info","ts":"2025-05-26T02:31:42.126Z","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}
{"level":"info","ts":"2025-05-26T02:31:42.126Z","logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":"2025-05-26T02:31:42.127Z","logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":"2025-05-26T02:31:42.128Z","logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"warn","ts":"2025-05-26T02:31:42.128Z","logger":"http","msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":80"}
{"level":"warn","ts":"2025-05-26T02:31:42.128Z","logger":"http","msg":"HTTP/3 skipped because it requires TLS","network":"tcp","addr":":80"}
{"level":"info","ts":"2025-05-26T02:31:42.128Z","logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":"2025-05-26T02:31:42.128Z","logger":"http","msg":"enabling automatic TLS certificate management","domains":["*.example.duckdns.org","*.example.mywire.org","*.example.casacam.net"]}
{"level":"warn","ts":"2025-05-26T02:31:42.129Z","logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [*.example.casacam.net]: no OCSP server specified in certificate","identifiers":["*.example.casacam.net"]}
{"level":"warn","ts":"2025-05-26T02:31:42.129Z","logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [*.example.duckdns.org]: no OCSP server specified in certificate","identifiers":["*.example.duckdns.org"]}
{"level":"warn","ts":"2025-05-26T02:31:42.130Z","logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [*.shoebox.mywire.org]: no OCSP server specified in certificate","identifiers":["*.example.mywire.org"]}
{"level":"info","ts":"2025-05-26T02:31:42.130Z","msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1748226702.1306832,"msg":"serving initial configuration"}
{"level":"info","ts":"2025-05-26T02:31:42.133Z","logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"e1709400-bcd3-4b9b-9992-1ebf301cf030","try_again":"2025-05-27T02:31:42.133Z","try_again_in":86399.999999315}
{"level":"info","ts":"2025-05-26T02:31:42.134Z","logger":"tls","msg":"finished cleaning storage units"}

3. Caddy version:

# docker exec caddy caddy version
v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=

4. How I installed and ran Caddy:

a. System environment:

# lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 12 (bookworm)
Release: 12
Codename: bookworm
# systemd --version
systemd 252 (252.36-1~deb12u1)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified
# docker -v
Docker version 28.1.1, build 4eba377

Furthermore, the Debian above is a running on TrueNAS 24.10.2.2 on top of systemd-nspawn.

b. Command:

No idea. It is started by docker.

c. Service/unit/compose file:

$ cat compose.yaml
---
services:
  caddy:
    build:
      context: .
    container_name: caddy
    pull_policy: build
    restart: unless-stopped
    user: "3012:3012"
    cap_add:
      - NET_ADMIN
    env_file:
      - ./secrets.env
    environment:
      - TZ=Europe/London
      - GOMAXPROCS=24
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./caddy:/etc/caddy
      - ./config:/config:rw
      - ./data:/data:rw
      - ./srv:/srv
      - /mnt/logs/caddy/:/logs
    labels:
      - "com.centurylinklabs.watchtower.enable=false"

d. My complete Caddy config:

# cat Caddyfile
#################
# General Options
{
	email someone@gmail.com
	# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
	acme_ca https://acme-v02.api.letsencrypt.org/directory

	log {
		format json {
			time_format iso8601
		}
	}
}

#############################
# Snippets

# a snippet to log per host
(per_host_log) {
	log {
		hostnames {args[0]}
		output file /logs/{args[0]}/{args[0]}.json {
			mode 640
			roll_size 100MiB
			roll_keep 10
			roll_keep_for 720h
		}
		format json {
			time_format iso8601
		}
	}
}

# a snippet handles v2ray requests
(v2ray) {
	# the real deal, v2ray
	handle_path /ws {
		reverse_proxy http://10.27.0.65:2000 {
			transport http {
				versions h2c
			}
		}
	}
	# the decoy and default, pitch plex media server
	handle {
		invoke plex
	}
}

###############
# routes

&(ha) {
	reverse_proxy http://10.27.0.50:8123
}

&(ha2) {
	reverse_proxy http://10.27.0.65:8123
}

&(nc) {
	reverse_proxy http://10.27.0.65:1780
}

&(plex) {
	reverse_proxy http://10.27.0.50:32400
}

#######################
# *.example.duckdns.org

*.example.duckdns.org {
	tls {
		dns duckdns {$DUCKDNS_API_TOKEN}
	}

	import per_host_log ha.example.duckdns.org
	import per_host_log ha2.example.duckdns.org
	import per_host_log nc.example.duckdns.org
	import per_host_log plex.example.duckdns.org
	import per_host_log video.example.duckdns.org

	@ha host ha.example.duckdns.org
	handle @ha {
		invoke ha
	}

	@ha2 host ha2.example.duckdns.org
	handle @ha2 {
		invoke ha2
	}

	@nc host nc.example.duckdns.org
	handle @nc {
		invoke nc
	}

	@plex host plex.example.duckdns.org
	handle @plex {
		invoke plex
	}

	@v2ray host video.example.duckdns.org
	handle @v2ray {
		import v2ray
	}

	handle {
		abort
	}
}

#####################
# *.example.casacam.net
*.example.casacam.net {
	tls {
		dns dynu {$DYNU_API_TOKEN} {
			own_domain example.casacam.net
		}
	}

	import per_host_log ha.example.casacam.net
	import per_host_log ha2.example.casacam.net
	import per_host_log nc.example.casacam.net
	import per_host_log plex.example.casacam.net

	@ha host ha.example.casacam.net
	handle @ha {
		invoke ha
	}

	@ha2 host ha2.example.casacam.net
	handle @ha2 {
		invoke ha2
	}

	@nc host nc.example.casacam.net
	handle @nc {
		invoke nc
	}

	@plex host plex.example.casacam.net
	handle @plex {
		invoke plex
	}

	handle {
		abort
	}
}

######################
# *.example.mywire.org
*.example.mywire.org {
	tls {
		dns dynu {$DYNU_API_TOKEN} {
			own_domain example.mywire.org
		}
	}

	import per_host_log video.example.mywire.org

	@video host video.example.mywire.org
	handle @video {
		import v2ray
	}

	handle {
		abort
	}
}

5. Links to relevant resources:

Caddy dns module duckdns and module dynu installed.

I figured caddy renewed the certificates today finally.

I thought it would renew 30 days before expiry but I was wrong. It only renew when the certificates are less than 21 days.

Technically, Caddy renews 2/3 through validity period. You’re probably seeing 21 days because of February.

1 Like