docker-traefik-dns - 根据容器标签 URL 自动创建 Cloudflare DNS 记录

✨ 一个用 Go 语言编写的轻量级开源工具 docker-traefik-dns,自动化解决自建服务中的 DNS 配置繁琐问题。它能够读取 Docker 容器标签或 Traefik 规则中的域名,并自动调用 Cloudflare API 创建对应的 DNS 解析记录。

在服务器上部署服务后,还要到 Cloudflare 上配置一条 DNS 记录,有点麻烦。

(虽然 AI Agent 能自动去干,但是 token 在这方面烧不起也没必要,而且有时候还有幻觉不确定性)

https://note.okhk.net/self-hosted-service-with-traefik-and-cloudflare-tunnel

既然 Traefik 通过 Lable 完成了对其他服务的反向代理,而 Lable 中也有对应的服务域名,那么再来个程序依据 Lable 中的域名自动去调用 Cloudflare 的 API 添加对应的 A 记录或者 CNAME 记录不就完成上线可以访问了。

把想法和 AI 讨论一番后,直接就得到了下面这个简单项目

https://github.com/hkint/docker-traefik-dns
compose.yaml
services:
  docker-traefik-dns:
    image: ghcr.io/hkint/docker-traefik-dns
    container_name: docker-traefik-dns
    restart: unless-stopped
    environment:
      # Cloudflare Configuration,需要 DNS 编辑权限的 API Token
      - CF_API_TOKEN=${CF_API_TOKEN}
      - CF_PROXY=${CF_PROXY:-false}
      - CF_TTL=${CF_TTL:-1}
      - DOMAIN_FILTER=${DOMAIN_FILTER:-okhk.net}

      # Source configuration: "both" (default), "docker", or "traefik"
      - DNS_SOURCE=both

      # Default Target IP (Your public IP or Tailscale IP / LAN IP)
      - DEFAULT_TARGET_IP=${DEFAULT_TARGET_IP}

      # Docker Socket connection (reads container labels and Traefik rules directly)
      - DOCKER_HOST=unix:///var/run/docker.sock

      # Traefik API endpoint (optional if reading directly via docker socket)
      # - TRAEFIK_API_URL=http://traefik:8080
      # - TRAEFIK_TARGET_IP=${DEFAULT_TARGET_IP}

      # Operational settings
      - SYNC_INTERVAL=60s
      - DRY_RUN=false
      - LOG_LEVEL=info
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - traefik-net

networks:
  traefik-net:
    driver: bridge

包含如下特性:

💡

自动化感知与解析:服务采用 Go 语言编写,可以直接读取 Docker Socket 或 Traefik API,自动解析 Host(...) / HostSNI(...) 路由规则中的域名,无需重复配置。

声明式 Label 覆盖:除了自动抓取 Traefik 规则外,还支持通过自定义 Docker 标签(如 docker-traefik-dns.hostname、docker-traefik-dns.target)甚至兼容 Kubernetes external-dns 的标签,显式指定域名、目标 IP 及是否开启 Cloudflare 代理。

基于 TXT 记录的安全所有权校验:为了防止误删手动创建或其他服务管理的 DNS 记录,服务会在更新 DNS 时自动写入带有唯一标识符的 TXT 所有权记录。在 reconcile 同步循环中,仅处理带有该标识符的托管记录,保证了极高的安全边界。

Dry-run 与安全回退:提供 DRY_RUN 模式用于上线前的变更预览,同时支持设置全局 DEFAULT_TARGET_IP 与白名单 DOMAIN_FILTER 过滤。

其中 DNS_SOURCE=docker 指的是“从 Docker Engine API 读取容器及其 labels”,并不是说域名必须来自 Docker 专用 label。它会读取容器上的如下 label:

# 1. 标准 Traefik labels
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.app.rule=Host(`app.okhk.net`)"
  
# 2. Docker Traefik DNS 自定义 label
labels:
  - "docker-traefik-dns.hostname=app.okhk.net"
# 兼容 ExternalDNS 的 label:
  - "external-dns.alpha.kubernetes.io/hostname=app.okhk.net"

而 DNS_SOURCE=traefik 则是基于 Traefik API 获取已加载的 router rule,不会读取 Docker 容器上的 docker-traefik-dns.target label,一般会共用一个 Target 和 Proxy 配置。

Traefik API → /api/http/routers
Traefik API → /api/tcp/routers

故而可采用如下配置:

DNS_SOURCE=docker
DEFAULT_TARGET_IP=100.64.0.10
CF_PROXY=false
# 如测试配置开启 Dry run
# DRY_RUN=true
  • 部署内网服务(基于 Tailscale)

    只需要默认的 traefik label 即可

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.internal.rule=Host(`internal.okhk.net`)"

    此处以 whoami 为例,Cloudflare 显示已添加 A 记录,并有 TXT 管理记录

  • 部署公网服务(基于 Cloudflare Tunnel)

    额外配置覆盖 target 和 proxy

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.public.rule=Host(`public.okhk.net`)"
      - "docker-traefik-dns.target=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.cfargotunnel.com"
      - "docker-traefik-dns.proxy=true"
    💡
    注意:Cloudflare Tunnel 需要在 Zero Trust 控制台配置域名通配符转发,不然会被 Catch-all: http_status:403 拦截