将 Traefik 切换为 DNS 挑战
默认情况下,Coolify 配置 Traefik 使用 HTTP 挑战(httpChallenge)来获取 SSL 证书,这需要 80 端口具备公网可达性。切换到 DNS 挑战(dnsChallenge)通常有两个原因:
- 您需要 通配符 SSL 证书(例如
*.example.com)—— 这类证书必须使用 DNS 挑战。 - 您的服务器没有公网 80 端口(例如:内网环境、位于防火墙后,或仅使用 Tailscale 的节点)。
工作原理
Traefik 不再通过 HTTP 验证域名所有权,而是要求您的 DNS 提供商在 _acme-challenge.<your-domain> 下创建一个临时的 TXT 记录。Let's Encrypt 会读取该记录以确认所有权,随后颁发证书。Traefik(通过 Lego 库)会自动处理整个过程。
前提条件
- 由支持的 DNS 提供商管理的域名。
- 该提供商的 API Token 或密钥,且具备创建和删除 DNS 记录的权限。
查找提供商所需的环境变量
每个提供商所需的环境变量不同。打开 Lego 提供商列表,点击您的提供商,并记下顶部列出的所需环境变量。
配置
前往 Servers → 您的服务器 → Proxy,并将默认的 Traefik 配置替换为以下内容。
高亮行显示了与默认 HTTP 挑战配置相比的具体更改内容。
name: coolify-proxy
networks:
coolify:
external: true
services:
traefik:
container_name: coolify-proxy
image: 'traefik:v3.6'
restart: unless-stopped
environment:
- HETZNER_API_TOKEN=<Hetzner API Token>
extra_hosts:
- 'host.docker.internal:host-gateway'
networks:
- coolify
ports:
- '80:80'
- '443:443'
- '443:443/udp'
- '8080:8080'
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
- '/data/coolify/proxy/:/traefik'
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=false'
- '--entrypoints.http.address=:80'
- '--entrypoints.https.address=:443'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http.encodequerysemicolons=true'
- '--entryPoints.https.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http3'
- '--providers.docker.exposedbydefault=false'
- '--providers.file.directory=/traefik/dynamic/'
- '--providers.file.watch=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=hetzner'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=0'
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
- '--providers.docker=true'
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
- coolify.managed=true
- coolify.proxy=truename: coolify-proxy
networks:
coolify:
external: true
services:
traefik:
container_name: coolify-proxy
image: 'traefik:v3.6'
restart: unless-stopped
environment:
- CF_DNS_API_TOKEN=<Cloudflare API Token>
extra_hosts:
- 'host.docker.internal:host-gateway'
networks:
- coolify
ports:
- '80:80'
- '443:443'
- '443:443/udp'
- '8080:8080'
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
- '/data/coolify/proxy/:/traefik'
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=false'
- '--entrypoints.http.address=:80'
- '--entrypoints.https.address=:443'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http.encodequerysemicolons=true'
- '--entryPoints.https.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http3'
- '--providers.docker.exposedbydefault=false'
- '--providers.file.directory=/traefik/dynamic/'
- '--providers.file.watch=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=0'
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
- '--providers.docker=true'
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
- coolify.managed=true
- coolify.proxy=truename: coolify-proxy
networks:
coolify:
external: true
services:
traefik:
container_name: coolify-proxy
image: 'traefik:v3.6'
restart: unless-stopped
environment:
- AWS_ACCESS_KEY_ID=<Access Key ID>
- AWS_SECRET_ACCESS_KEY=<Secret Access Key>
- AWS_REGION=<Region>
extra_hosts:
- 'host.docker.internal:host-gateway'
networks:
- coolify
ports:
- '80:80'
- '443:443'
- '443:443/udp'
- '8080:8080'
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
- '/data/coolify/proxy/:/traefik'
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=false'
- '--entrypoints.http.address=:80'
- '--entrypoints.https.address=:443'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http.encodequerysemicolons=true'
- '--entryPoints.https.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http3'
- '--providers.docker.exposedbydefault=false'
- '--providers.file.directory=/traefik/dynamic/'
- '--providers.file.watch=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=route53'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=0'
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
- '--providers.docker=true'
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
- coolify.managed=true
- coolify.proxy=truename: coolify-proxy
networks:
coolify:
external: true
services:
traefik:
container_name: coolify-proxy
image: 'traefik:v3.6'
restart: unless-stopped
environment:
- HOSTINGER_API_TOKEN=<Hostinger API Token>
extra_hosts:
- 'host.docker.internal:host-gateway'
networks:
- coolify
ports:
- '80:80'
- '443:443'
- '443:443/udp'
- '8080:8080'
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
- '/data/coolify/proxy/:/traefik'
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=false'
- '--entrypoints.http.address=:80'
- '--entrypoints.https.address=:443'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http.encodequerysemicolons=true'
- '--entryPoints.https.http2.maxConcurrentStreams=250'
- '--entrypoints.https.http3'
- '--providers.docker.exposedbydefault=false'
- '--providers.file.directory=/traefik/dynamic/'
- '--providers.file.watch=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=hostinger'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=0'
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
- '--providers.docker=true'
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
- coolify.managed=true
- coolify.proxy=true注意
您也可以使用 env_file 替代 environment —— 在服务器上创建一个 .env 文件并进行引用。这有助于将敏感信息从 UI 中隐藏。
将 --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=<name> 更改为与 Lego 提供商列表 中您提供商标识符匹配的值。
完成上述更改后,请重启代理。Traefik 现在将使用 DNS 挑战来获取和续期 SSL 证书。
故障排除
证书未签发 / 找不到 DNS 记录
DNS 传播可能需要时间。如果挑战立即失败,请增加 delaybeforecheck 的值,以便为您的提供商留出传播 TXT 记录的时间:
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=30'CNAME 记录干扰挑战
如果您的域名使用了 CNAME 委托且续期时挑战失败,请设置此环境变量以禁用 CNAME 跟踪:
environment:
- LEGO_DISABLE_CNAME_SUPPORT=true速率限制
Let's Encrypt 实施了速率限制。在测试期间,请添加 staging CA(测试证书颁发机构) 标志,以避免耗尽您的配额:
- '--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory'一切正常后,请移除此标志。
后续步骤
现在 Traefik 已使用 DNS 挑战,您可以签发 通配符 SSL 证书,使用一张证书覆盖域名下的所有子域名。
